32using std::ostringstream;
36NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH);
37NotifyCategoryDef(drawmask,
"");
39TypeHandle PandaNode::BamReaderAuxDataDown::_type_handle;
41PandaNode::SceneRootFunc *PandaNode::_scene_root_func;
43PandaNodeChain PandaNode::_dirty_prev_transforms(
"_dirty_prev_transforms");
46PStatCollector PandaNode::_reset_prev_pcollector(
"App:Collisions:Reset");
51TypeHandle PandaNodePipelineReader::_type_handle;
76PandaNode(
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";
96 if (pgraph_cat.is_debug()) {
98 <<
"Destructing " << (
void *)
this <<
", " << get_name() <<
"\n";
101 if (_dirty_prev_transform) {
104 do_clear_dirty_prev_transform();
133 _paths_lock(
"PandaNode::_paths_lock"),
134 _dirty_prev_transform(false),
135 _python_tag_data(copy._python_tag_data),
136 _unexpected_change_flags(0)
138 if (pgraph_cat.is_debug()) {
140 <<
"Copying " << (
void *)
this <<
", " << get_name() <<
"\n";
142#ifdef DO_MEMORY_USAGE
151 CDReader copy_cdata(copy._cycler);
152 CDWriter cdata(_cycler,
true);
153 cdata->_state = copy_cdata->_state;
154 cdata->_transform = copy_cdata->_transform;
155 cdata->_prev_transform = copy_cdata->_prev_transform;
156 if (cdata->_transform != cdata->_prev_transform) {
157 do_set_dirty_prev_transform();
160 cdata->_effects = copy_cdata->_effects;
161 cdata->_tag_data = copy_cdata->_tag_data;
162 cdata->_draw_control_mask = copy_cdata->_draw_control_mask;
163 cdata->_draw_show_mask = copy_cdata->_draw_show_mask;
164 cdata->_into_collide_mask = copy_cdata->_into_collide_mask;
165 cdata->_bounds_type = copy_cdata->_bounds_type;
166 cdata->_user_bounds = copy_cdata->_user_bounds;
167 cdata->_internal_bounds =
nullptr;
168 cdata->_internal_bounds_computed = UpdateSeq::initial();
169 cdata->_internal_bounds_mark = UpdateSeq::initial();
170 ++cdata->_internal_bounds_mark;
171 cdata->_final_bounds = copy_cdata->_final_bounds;
172 cdata->_fancy_bits = copy_cdata->_fancy_bits;
284 if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
285 const LMatrix4 &mat = attribs._transform->get_mat();
289 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
290 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
291 cdata->_effects = cdata->_effects->xform(mat);
292 cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
294 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
304xform(
const LMatrix4 &) {
352calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
bool &found_any,
354 CPT(
TransformState) next_transform = transform->compose(get_transform());
357 int num_children = cr.get_num_children();
358 for (
int i = 0; i < num_children; i++) {
359 cr.get_child(i)->calc_tight_bounds(min_point, max_point,
360 found_any, next_transform,
364 return next_transform;
492copy_subgraph(
Thread *current_thread)
const {
493 InstanceMap inst_map;
494 return r_copy_subgraph(inst_map, current_thread);
501count_num_descendants()
const {
504 int num_children = children.get_num_children();
506 for (
int i = 0; i < num_children; ++i) {
508 count += child->count_num_descendants();
524 nassertv(child_node !=
nullptr);
526 if (!verify_child_no_cycles(child_node)) {
538 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
539 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
540 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
542 cdata->modify_down()->insert(DownConnection(child_node, sort));
543 cdata_child->modify_up()->insert(UpConnection(
this));
545 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
547 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
548 new_connection(
this, child_node, pipeline_stage, current_thread);
550 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
552 force_bounds_stale();
555 child_node->parents_changed();
566 nassertv(pipeline_stage == 0);
568 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
569 PT(
Down) down = cdata->modify_down();
570 nassertv(child_index >= 0 && child_index < (
int)down->size());
573 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
575 PT(
Up) up = cdata_child->modify_up();
577 down->erase(down->begin() + child_index);
578 int num_erased = up->erase(UpConnection(
this));
579 nassertv(num_erased == 1);
581 sever_connection(
this, child_node, pipeline_stage, current_thread);
582 force_bounds_stale(pipeline_stage, current_thread);
585 child_node->parents_changed();
597 nassertr(child_node !=
nullptr,
false);
604 bool any_removed =
false;
606 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
607 if (stage_remove_child(child_node, pipeline_stage, current_thread)) {
610 sever_connection(
this, child_node, pipeline_stage, current_thread);
611 force_bounds_stale(pipeline_stage, current_thread);
614 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
619 child_node->parents_changed();
634 nassertr(orig_child !=
nullptr,
false);
635 nassertr(new_child !=
nullptr,
false);
637 if (orig_child == new_child) {
642 if (!verify_child_no_cycles(new_child)) {
650 PT(
PandaNode) keep_orig_child = orig_child;
653 bool any_replaced =
false;
655 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
656 if (stage_replace_child(orig_child, new_child, pipeline_stage, current_thread)) {
660 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
664 orig_child->parents_changed();
665 new_child->parents_changed();
684 nassertv(pipeline_stage == 0);
696 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
697 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
699 cdata->modify_stashed()->insert(
DownConnection(child_node, sort));
700 cdata_child->modify_up()->insert(UpConnection(
this));
703 new_connection(
this, child_node, pipeline_stage, current_thread);
704 force_bounds_stale(pipeline_stage, current_thread);
707 child_node->parents_changed();
724 nassertv(pipeline_stage == 0);
739 CDWriter cdata_child(child_node->_cycler);
742 cdata_child->modify_up()->insert(UpConnection(
this));
745 new_connection(
this, child_node, pipeline_stage, current_thread);
747 force_bounds_stale();
749 child_node->parents_changed();
767 nassertv(pipeline_stage == 0);
769 if (!verify_child_no_cycles(child_node)) {
781 CDWriter cdata_child(child_node->_cycler);
783 cdata->modify_stashed()->insert(
DownConnection(child_node, sort));
784 cdata_child->modify_up()->insert(UpConnection(
this));
787 new_connection(
this, child_node, pipeline_stage, current_thread);
791 child_node->parents_changed();
802 nassertv(pipeline_stage == 0);
804 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
805 Down &stashed = *cdata->modify_stashed();
806 nassertv(child_index >= 0 && child_index < (
int)stashed.size());
808 PT(
PandaNode) child_node = stashed[child_index].get_child();
809 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
811 stashed.erase(stashed.begin() + child_index);
812 int num_erased = cdata_child->modify_up()->erase(UpConnection(
this));
813 nassertv(num_erased == 1);
815 sever_connection(
this, child_node, pipeline_stage, current_thread);
816 force_bounds_stale(pipeline_stage, current_thread);
819 child_node->parents_changed();
832 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
833 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
834 PT(
Down) down = cdata->modify_down();
836 for (di = down->begin(); di != down->end(); ++di) {
838 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
840 cdata_child->modify_up()->erase(UpConnection(
this));
842 sever_connection(
this, child_node, pipeline_stage, current_thread);
843 child_node->parents_changed();
848 Down &stashed = *cdata->modify_stashed();
849 for (di = stashed.begin(); di != stashed.end(); ++di) {
851 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
853 cdata_child->modify_up()->erase(UpConnection(
this));
855 sever_connection(
this, child_node, pipeline_stage, current_thread);
856 child_node->parents_changed();
861 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
863 force_bounds_stale();
890 for (i = 0; i < num_children; i++) {
893 add_child(child_node, sort, current_thread);
896 for (i = 0; i < num_stashed; i++) {
919 for (i = 0; i < num_children; i++) {
922 add_child(child_node, sort, current_thread);
925 for (i = 0; i < num_stashed; i++) {
941 bool any_changed =
false;
943 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
944 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
946 CPT(
RenderState) new_state = cdata->_state->set_attrib(attrib,
override);
947 if (cdata->_state != new_state) {
948 cdata->_state = new_state;
949 cdata->set_fancy_bit(FB_state,
true);
953 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
957 mark_bounds_stale(current_thread);
969clear_attrib(
int slot) {
970 bool any_changed =
false;
973 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
974 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
976 CPT(
RenderState) new_state = cdata->_state->remove_attrib(slot);
977 if (cdata->_state != new_state) {
978 cdata->_state = new_state;
979 cdata->set_fancy_bit(FB_state, !new_state->is_empty());
983 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
988 mark_bounds_stale(current_thread);
1003 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1004 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1005 cdata->_effects = cdata->_effects->add_effect(effect);
1006 cdata->set_fancy_bit(FB_effects,
true);
1008 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1018 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1019 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1020 cdata->_effects = cdata->_effects->remove_effect(type);
1021 cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
1023 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1038 bool any_changed =
false;
1039 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1040 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1041 if (cdata->_state != state) {
1042 cdata->_state = state;
1043 cdata->set_fancy_bit(FB_state, !state->
is_empty());
1047 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1051 mark_bounds_stale(current_thread);
1066 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1067 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1068 cdata->_effects = effects;
1069 cdata->set_fancy_bit(FB_effects, !effects->
is_empty());
1071 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1088 bool any_changed =
false;
1089 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1090 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1091 if (cdata->_transform != transform) {
1092 cdata->_transform = transform;
1093 cdata->set_fancy_bit(FB_transform, !transform->
is_identity());
1096 if (pipeline_stage == 0) {
1097 if (cdata->_transform != cdata->_prev_transform) {
1098 do_set_dirty_prev_transform();
1103 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1106 mark_bounds_stale(current_thread);
1107 transform_changed();
1126 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1127 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1128 cdata->_prev_transform = transform;
1129 if (pipeline_stage == 0) {
1130 if (cdata->_transform != cdata->_prev_transform) {
1131 do_set_dirty_prev_transform();
1133 do_clear_dirty_prev_transform();
1137 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1150 do_clear_dirty_prev_transform();
1155 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1156 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1157 cdata->_prev_transform = cdata->_transform;
1159 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1173 PStatTimer timer(_reset_prev_pcollector, current_thread);
1177 while (list_node != &_dirty_prev_transforms) {
1179 nassertv(panda_node->_dirty_prev_transform);
1180 panda_node->_dirty_prev_transform =
false;
1182 CDStageWriter cdata(panda_node->_cycler, 0, current_thread);
1183 cdata->_prev_transform = cdata->_transform;
1185 list_node = panda_node->_next;
1187 panda_node->_prev =
nullptr;
1188 panda_node->_next =
nullptr;
1193 _dirty_prev_transforms._prev = &_dirty_prev_transforms;
1194 _dirty_prev_transforms._next = &_dirty_prev_transforms;
1207set_tag(
const string &key,
const string &value,
Thread *current_thread) {
1210 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1211 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1212 cdata->_tag_data.store(key, value);
1213 cdata->set_fancy_bit(FB_tag,
true);
1215 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1225 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1226 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1227 cdata->_tag_data.remove(key);
1228 cdata->set_fancy_bit(FB_tag, !cdata->_tag_data.is_empty());
1230 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1241 if (other ==
this) {
1249 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1250 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
1251 CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread);
1253 for (
size_t n = 0; n < cdatar->_tag_data.size(); ++n) {
1254 cdataw->_tag_data.store(cdatar->_tag_data.get_key(n), cdatar->_tag_data.get_data(n));
1256 cdataw->set_fancy_bit(FB_tag, !cdataw->_tag_data.is_empty());
1258 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1262 _python_tag_data = other->_python_tag_data;
1277list_tags(ostream &out,
const string &separator)
const {
1279 for (
size_t n = 0; n < cdata->_tag_data.size(); ++n) {
1283 out << cdata->_tag_data.get_key(n);
1300 for (
size_t n = 0; n < cdata->_tag_data.size(); ++n) {
1301 keys.push_back(cdata->_tag_data.get_key(n));
1315 CDReader cdata_other(other->_cycler);
1317 const TagData &a_data = cdata->_tag_data;
1318 const TagData &b_data = cdata_other->_tag_data;
1322 while (ai < a_data.
size() && bi < b_data.
size()) {
1323 int cmp = strcmp(a_data.
get_key(ai).c_str(), b_data.
get_key(bi).c_str());
1336 if (ai < a_data.
size()) {
1340 if (bi < b_data.
size()) {
1347 if (_python_tag_data != other->_python_tag_data) {
1348 return (_python_tag_data < other->_python_tag_data) ? -1 : 1;
1362 if (other ==
this) {
1370 bool any_transform_changed =
false;
1371 bool any_state_changed =
false;
1372 bool any_draw_mask_changed =
false;
1374 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1375 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
1376 CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread);
1378 if (cdataw->_transform != cdatar->_transform) {
1379 any_transform_changed =
true;
1381 if (cdataw->_state != cdatar->_state) {
1382 any_state_changed =
true;
1384 if (cdataw->_draw_control_mask != cdatar->_draw_control_mask ||
1385 cdataw->_draw_show_mask != cdatar->_draw_show_mask) {
1386 any_draw_mask_changed =
true;
1389 cdataw->_transform = cdatar->_transform;
1390 cdataw->_prev_transform = cdatar->_prev_transform;
1391 cdataw->_state = cdatar->_state;
1392 cdataw->_effects = cdatar->_effects;
1393 cdataw->_draw_control_mask = cdatar->_draw_control_mask;
1394 cdataw->_draw_show_mask = cdatar->_draw_show_mask;
1398 cdataw->_into_collide_mask |= cdatar->_into_collide_mask;
1400 for (
size_t n = 0; n < cdatar->_tag_data.size(); ++n) {
1401 cdataw->_tag_data.store(cdatar->_tag_data.get_key(n), cdatar->_tag_data.get_data(n));
1404 static const int change_bits = (FB_transform | FB_state | FB_effects |
1405 FB_tag | FB_draw_mask);
1406 cdataw->_fancy_bits =
1407 (cdataw->_fancy_bits & ~change_bits) |
1408 (cdatar->_fancy_bits & change_bits);
1410 if (pipeline_stage == 0) {
1411 if (cdataw->_transform != cdataw->_prev_transform) {
1412 do_set_dirty_prev_transform();
1416 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1420 _python_tag_data = other->_python_tag_data;
1422 if (any_transform_changed || any_state_changed || any_draw_mask_changed) {
1423 mark_bounds_stale(current_thread);
1425 if (any_transform_changed) {
1426 transform_changed();
1428 if (any_state_changed) {
1431 if (any_draw_mask_changed) {
1432 draw_mask_changed();
1457 if (other ==
this) {
1474 for (pi = other->_paths.begin(); pi != other->_paths.end(); ++pi) {
1475 (*pi)->_node =
this;
1478 other->_paths.clear();
1515 _unexpected_change_flags |= flags;
1531 return _unexpected_change_flags & flags;
1550 _unexpected_change_flags &= ~flags;
1586 bool any_changed =
false;
1589 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1590 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1592 DrawMask draw_control_mask = (cdata->_draw_control_mask | show_mask | hide_mask) & ~clear_mask;
1593 DrawMask draw_show_mask = (cdata->_draw_show_mask | show_mask) & ~hide_mask;
1595 draw_show_mask |= ~draw_control_mask;
1597 if (cdata->_draw_control_mask != draw_control_mask ||
1598 cdata->_draw_show_mask != draw_show_mask) {
1599 cdata->_draw_control_mask = draw_control_mask;
1600 cdata->_draw_show_mask = draw_show_mask;
1603 cdata->set_fancy_bit(FB_draw_mask, !draw_control_mask.
is_zero());
1605 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1608 mark_bounds_stale(current_thread);
1609 draw_mask_changed();
1627 if (cdata->_last_update != cdata->_next_update) {
1631 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
1632 return cdataw->_net_draw_control_mask;
1634 return cdata->_net_draw_control_mask;
1654 if (cdata->_last_update != cdata->_next_update) {
1658 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
1659 return cdataw->_net_draw_show_mask;
1661 return cdata->_net_draw_show_mask;
1680 bool any_changed =
false;
1682 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1683 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1684 if (cdata->_into_collide_mask != mask) {
1685 cdata->_into_collide_mask = mask;
1689 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1692 mark_bounds_stale(current_thread);
1718 if (cdata->_last_update != cdata->_next_update) {
1722 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
1723 return cdataw->_net_collide_mask;
1725 return cdata->_net_collide_mask;
1733get_off_clip_planes(
Thread *current_thread)
const {
1735 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1736 if (cdata->_last_update != cdata->_next_update) {
1739 CDStageWriter cdataw =
1740 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
1741 return cdataw->_off_clip_planes;
1743 return cdata->_off_clip_planes;
1773 if (_scene_root_func !=
nullptr) {
1774 return (*_scene_root_func)(
this);
1807output(ostream &out)
const {
1808 out << get_type() <<
" " << get_name();
1815write(ostream &out,
int indent_level)
const {
1816 indent(out, indent_level) << *
this;
1824 out <<
" " << *transform;
1828 out <<
" " << *state;
1832 out <<
" " << *effects;
1835 if (!draw_control_mask.
is_zero()) {
1837 if (!(draw_control_mask & _overall_bit).is_zero()) {
1838 if (!(draw_show_mask & _overall_bit).is_zero()) {
1839 out <<
" (show_through)";
1844 if (!(draw_control_mask & ~_overall_bit).is_zero()) {
1845 draw_control_mask &= ~_overall_bit;
1846 if (!(draw_show_mask & draw_control_mask).is_zero()) {
1847 out <<
" (per-camera show_through)";
1849 if (!(~draw_show_mask & draw_control_mask).is_zero()) {
1850 out <<
" (per-camera hidden)";
1874 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1875 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1876 cdata->_bounds_type = bounds_type;
1877 mark_bounds_stale(pipeline_stage, current_thread);
1881 mark_internal_bounds_stale(pipeline_stage, current_thread);
1884 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1892 CDReader cdata(_cycler);
1893 return cdata->_bounds_type;
1909 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1910 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1911 if (volume ==
nullptr) {
1912 cdata->_user_bounds =
nullptr;
1914 cdata->_user_bounds = volume->make_copy();
1916 mark_bounds_stale(pipeline_stage, current_thread);
1919 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1927 pgraph_cat.warning()
1928 <<
"Deprecated PandaNode::set_bound() called. Use set_bounds() instead.\n";
1938get_bounds(
Thread *current_thread)
const {
1940 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1941 if (cdata->_last_bounds_update != cdata->_next_update) {
1946 CDStageWriter cdataw =
1947 ((
PandaNode *)
this)->update_cached(
true, pipeline_stage, cdata);
1948 result = cdataw->_external_bounds;
1952 return cdata->_external_bounds;
1969 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1970 if (cdata->_last_bounds_update != cdata->_next_update) {
1975 CDStageWriter cdataw =
1976 ((
PandaNode *)
this)->update_cached(
true, pipeline_stage, cdata);
1977 result = cdataw->_external_bounds;
1978 seq = cdataw->_last_bounds_update;
1982 seq = cdata->_last_bounds_update;
1983 return cdata->_external_bounds;
1996get_nested_vertices(
Thread *current_thread)
const {
1998 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1999 if (cdata->_last_bounds_update != cdata->_next_update) {
2004 CDStageWriter cdataw =
2005 ((
PandaNode *)
this)->update_cached(
true, pipeline_stage, cdata);
2006 result = cdataw->_nested_vertices;
2010 return cdata->_nested_vertices;
2027mark_bounds_stale(
Thread *current_thread)
const {
2028 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2029 mark_bounds_stale(pipeline_stage, current_thread);
2031 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2046mark_internal_bounds_stale(
Thread *current_thread) {
2047 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2048 mark_internal_bounds_stale(pipeline_stage, current_thread);
2050 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2119decode_from_bam_stream(vector_uchar data,
BamReader *reader) {
2135get_internal_bounds(
int pipeline_stage,
Thread *current_thread)
const {
2139 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2140 if (cdata->_user_bounds !=
nullptr) {
2141 return cdata->_user_bounds;
2144 if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) {
2145 return cdata->_internal_bounds;
2148 mark = cdata->_internal_bounds_mark;
2154 int internal_vertices;
2155 compute_internal_bounds(internal_bounds, internal_vertices,
2156 pipeline_stage, current_thread);
2157 nassertr(!internal_bounds.is_null(),
nullptr);
2160 CDStageWriter cdataw(((
PandaNode *)
this)->_cycler, pipeline_stage);
2161 if (cdataw->_internal_bounds_mark == mark) {
2162 cdataw->_internal_bounds_computed = mark;
2163 cdataw->_internal_bounds = internal_bounds;
2164 cdataw->_internal_vertices = internal_vertices;
2165 ((
PandaNode *)
this)->mark_bam_modified();
2166 return cdataw->_internal_bounds;
2182get_internal_vertices(
int pipeline_stage,
Thread *current_thread)
const {
2186 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2187 if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) {
2188 return cdata->_internal_vertices;
2191 mark = cdata->_internal_bounds_mark;
2197 int internal_vertices;
2198 compute_internal_bounds(internal_bounds, internal_vertices,
2199 pipeline_stage, current_thread);
2200 nassertr(!internal_bounds.is_null(), 0);
2203 CDStageWriter cdataw(((
PandaNode *)
this)->_cycler, pipeline_stage);
2204 if (cdataw->_internal_bounds_mark == mark) {
2205 cdataw->_internal_bounds_computed = mark;
2206 cdataw->_internal_bounds = internal_bounds;
2207 cdataw->_internal_vertices = internal_vertices;
2208 ((
PandaNode *)
this)->mark_bam_modified();
2209 return cdataw->_internal_vertices;
2227 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2228 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
2229 cdataw->_internal_bounds = volume;
2230 cdataw->_internal_bounds_computed = cdataw->_internal_bounds_mark;
2232 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2233 mark_bounds_stale(current_thread);
2245force_bounds_stale(
Thread *current_thread) {
2246 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2247 force_bounds_stale(pipeline_stage, current_thread);
2249 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2257force_bounds_stale(
int pipeline_stage,
Thread *current_thread) {
2259 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2260 ++cdata->_next_update;
2273 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2274 parents = Parents(cdata);
2276 int num_parents = parents.get_num_parents();
2277 for (
int i = 0; i < num_parents; ++i) {
2279 parent->mark_bounds_stale(pipeline_stage, current_thread);
2288r_mark_geom_bounds_stale(
Thread *current_thread) {
2292 for (i = 0; i < children.get_num_children(); i++) {
2294 child->r_mark_geom_bounds_stale(current_thread);
2298 for (i = 0; i < stashed.get_num_stashed(); i++) {
2300 child->r_mark_geom_bounds_stale(current_thread);
2311 int &internal_vertices,
2313 Thread *current_thread)
const {
2315 internal_vertices = 0;
2325 nassertv((_unexpected_change_flags & UC_parents) == 0);
2335 nassertv((_unexpected_change_flags & UC_children) == 0);
2344transform_changed() {
2345 nassertv((_unexpected_change_flags & UC_transform) == 0);
2355 nassertv((_unexpected_change_flags & UC_state) == 0);
2363draw_mask_changed() {
2364 nassertv((_unexpected_change_flags & UC_draw_mask) == 0);
2378 nassertr(copy !=
nullptr,
nullptr);
2379 if (copy->get_type() != get_type()) {
2380 pgraph_cat.warning()
2381 <<
"Don't know how to copy nodes of type " << get_type() <<
"\n";
2383 if (no_unsupported_copy) {
2384 nassert_raise(
"unsupported copy");
2389 copy->r_copy_children(
this, inst_map, current_thread);
2405 Thread *current_thread) {
2406 CDReader from_cdata(from->_cycler, current_thread);
2407 CPT(Down) from_down = from_cdata->get_down();
2408 Down::const_iterator di;
2409 for (di = from_down->begin(); di != from_down->end(); ++di) {
2410 int sort = (*di).get_sort();
2418 InstanceMap::const_iterator ci;
2419 ci = inst_map.find(source_child);
2420 if (ci != inst_map.end()) {
2421 dest_child = (*ci).second;
2423 dest_child = source_child->r_copy_subgraph(inst_map, current_thread);
2424 inst_map[source_child] = dest_child;
2427 quick_add_new_child(dest_child, sort, current_thread);
2444 CPT(
RenderState) child_state = node_state->compose(child->get_state());
2445 child->
r_prepare_scene(gsg, child_state, transformer, current_thread);
2451 CPT(
RenderState) child_state = node_state->compose(child->get_state());
2452 child->
r_prepare_scene(gsg, child_state, transformer, current_thread);
2462set_cull_callback() {
2464 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2465 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2466 cdata->set_fancy_bit(FB_cull_callback,
true);
2468 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2476disable_cull_callback() {
2478 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2479 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2480 cdata->set_fancy_bit(FB_cull_callback,
false);
2482 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2491stage_remove_child(
PandaNode *child_node,
int pipeline_stage,
2492 Thread *current_thread) {
2493 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2497 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
2499 int parent_index = child_node->do_find_parent(
this, cdata_child);
2500 if (parent_index < 0) {
2505 PT(Down) down = cdata->modify_down();
2506 int child_index = do_find_child(child_node, down);
2507 if (child_index >= 0) {
2509 down->erase(down->begin() + child_index);
2510 int num_erased = cdata_child->modify_up()->erase(UpConnection(
this));
2511 nassertr(num_erased == 1,
false);
2515 PT(Down) stashed = cdata->modify_stashed();
2516 int stashed_index = do_find_child(child_node, stashed);
2517 if (stashed_index >= 0) {
2519 stashed->erase(stashed->begin() + stashed_index);
2520 int num_erased = cdata_child->modify_up()->erase(UpConnection(
this));
2521 nassertr(num_erased == 1,
false);
2527 nassertr(
false,
false);
2537 int pipeline_stage,
Thread *current_thread) {
2539 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2540 CDStageWriter cdata_orig_child(orig_child->_cycler, pipeline_stage, current_thread);
2541 CDStageWriter cdata_new_child(new_child->_cycler, pipeline_stage, current_thread);
2545 int parent_index = orig_child->do_find_parent(
this, cdata_orig_child);
2546 if (parent_index < 0) {
2551 if (orig_child == new_child) {
2557 PT(
PandaNode) keep_orig_child = orig_child;
2560 if (stage_remove_child(new_child, pipeline_stage, current_thread)) {
2561 sever_connection(
this, new_child, pipeline_stage, current_thread);
2564 PT(Down) down = cdata->modify_down();
2565 int child_index = do_find_child(orig_child, down);
2566 if (child_index >= 0) {
2568 DownConnection &dc = (*down)[child_index];
2569 nassertr(dc.get_child() == orig_child,
false);
2570 dc.set_child(new_child);
2573 PT(Down) stashed = cdata->modify_stashed();
2574 int stashed_index = do_find_child(orig_child, stashed);
2575 if (stashed_index >= 0) {
2577 DownConnection &dc = (*stashed)[stashed_index];
2578 nassertr(dc.get_child() == orig_child,
false);
2579 dc.set_child(new_child);
2585 nassertr(
false,
false);
2591 cdata_new_child->modify_up()->insert(UpConnection(
this));
2592 int num_erased = cdata_orig_child->modify_up()->erase(UpConnection(
this));
2593 nassertr(num_erased == 1,
false);
2596 sever_connection(
this, orig_child, pipeline_stage, current_thread);
2597 new_connection(
this, new_child, pipeline_stage, current_thread);
2599 force_bounds_stale(pipeline_stage, current_thread);
2600 orig_child->parents_changed();
2601 new_child->parents_changed();
2616quick_add_new_child(
PandaNode *child_node,
int sort,
Thread *current_thread) {
2619 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2620 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2621 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2623 cdata->modify_down()->insert(DownConnection(child_node, sort));
2624 cdata_child->modify_up()->insert(UpConnection(
this));
2626 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2635 strm <<
"Detected attempt to create a cycle in the scene graph: "
2637 nassert_raise(strm.str());
2651 for (
size_t i = 0; i < parents.get_num_parents(); ++i) {
2653 if (parent->find_node_above(node)) {
2671 int pipeline_stage,
Thread *current_thread) {
2672 if (parent ==
nullptr) {
2677 pipeline_stage, current_thread);
2679 child_node->_paths.insert(child);
2685 PT(
NodePathComponent) child = get_component(parent, child_node, pipeline_stage, current_thread);
2687 if (child ==
nullptr) {
2690 child = get_top_component(child_node,
true, pipeline_stage, current_thread);
2693 reparent(parent, child, sort,
false, pipeline_stage, current_thread);
2706 nassertv(child !=
nullptr);
2708 for (
int pipeline_stage_i = pipeline_stage;
2709 pipeline_stage_i >= 0;
2710 --pipeline_stage_i) {
2711 detach_one_stage(child, pipeline_stage_i, current_thread);
2714 child->
get_node()->parents_changed();
2725 Thread *current_thread) {
2726 nassertv(child !=
nullptr);
2727 if (child->
is_top_node(pipeline_stage, current_thread)) {
2734 CDStageWriter cdata_parent(parent_node->_cycler, pipeline_stage, current_thread);
2735 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2736 int parent_index = child_node->do_find_parent(parent_node, cdata_child);
2737 if (parent_index >= 0) {
2741 int num_erased = cdata_child->modify_up()->erase(UpConnection(parent_node));
2742 nassertv(num_erased == 1);
2749 PT(Down) down = cdata_parent->modify_down();
2750 for (di = down->begin(); di != down->end(); ++di) {
2751 if ((*di).get_child() == child_node) {
2758 PT(Down) stashed = cdata_parent->modify_stashed();
2759 for (di = stashed->begin(); di != stashed->end(); ++di) {
2760 if ((*di).get_child() == child_node) {
2771 sever_connection(parent_node, child_node, pipeline_stage, current_thread);
2773 parent_node->force_bounds_stale(pipeline_stage, current_thread);
2774 parent_node->children_changed();
2775 parent_node->mark_bam_modified();
2789 bool as_stashed,
int pipeline_stage,
Thread *current_thread) {
2790 bool any_ok =
false;
2792 if (new_parent !=
nullptr &&
2799 for (
int pipeline_stage_i = pipeline_stage;
2800 pipeline_stage_i >= 0;
2801 --pipeline_stage_i) {
2802 if (reparent_one_stage(new_parent, child, sort, as_stashed,
2803 pipeline_stage_i, current_thread)) {
2808 if (new_parent !=
nullptr) {
2809 new_parent->
get_node()->children_changed();
2812 child->
get_node()->parents_changed();
2829 int sort,
bool as_stashed,
int pipeline_stage,
2830 Thread *current_thread) {
2831 nassertr(child !=
nullptr,
false);
2837 if (!child->
is_top_node(pipeline_stage, current_thread)) {
2838 detach(child, pipeline_stage, current_thread);
2841 if (new_parent !=
nullptr) {
2846 CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2847 int parent_index = child_node->do_find_parent(parent_node, cdata_child);
2849 if (parent_index >= 0) {
2856 child->set_next(new_parent, pipeline_stage, current_thread);
2860 CDStageWriter cdata_parent(parent_node->_cycler, pipeline_stage, current_thread);
2861 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2864 cdata_parent->modify_stashed()->insert(DownConnection(child_node, sort));
2866 cdata_parent->modify_down()->insert(DownConnection(child_node, sort));
2868 cdata_child->modify_up()->insert(UpConnection(parent_node));
2874 nassertr(child_node->_paths.find(child) != child_node->_paths.end(),
false);
2879 child_node->fix_path_lengths(pipeline_stage, current_thread);
2880 parent_node->force_bounds_stale(pipeline_stage, current_thread);
2892 int pipeline_stage,
Thread *current_thread) {
2893 nassertr(parent !=
nullptr,
nullptr);
2902 if (child->
get_next(pipeline_stage, current_thread) == parent) {
2909 result.cheat() = child;
2921 CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2922 int parent_index = child_node->do_find_parent(parent_node, cdata_child);
2924 if (parent_index >= 0) {
2928 child_node->_paths.insert(child);
2947get_top_component(
PandaNode *child_node,
bool force,
int pipeline_stage,
2948 Thread *current_thread) {
2954 if (child->
is_top_node(pipeline_stage, current_thread)) {
2961 result.cheat() = child;
2981 pipeline_stage, current_thread);
2982 child_node->_paths.insert(child);
2995get_generic_component(
bool accept_ambiguity,
int pipeline_stage,
2996 Thread *current_thread) {
2997 bool ambiguity_detected =
false;
2999 r_get_generic_component(accept_ambiguity, ambiguity_detected,
3000 pipeline_stage, current_thread);
3002 if (!accept_ambiguity && ambiguity_detected) {
3003 pgraph_cat.warning()
3004 <<
"Chose: " << *result <<
"\n";
3005 nassertr(!unambiguous_graph, result);
3017r_get_generic_component(
bool accept_ambiguity,
bool &ambiguity_detected,
3018 int pipeline_stage,
Thread *current_thread) {
3022 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
3024 int num_parents = cdata->get_up()->size();
3025 if (num_parents == 0) {
3027 return get_top_component(
this,
true, pipeline_stage, current_thread);
3031 if (num_parents == 1) {
3034 get_parent(0)->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread);
3035 return get_component(parent,
this, pipeline_stage, current_thread);
3039 if (!accept_ambiguity) {
3040 pgraph_cat.warning()
3041 << *
this <<
" has " << num_parents
3042 <<
" parents; choosing arbitrary path to root.\n";
3044 ambiguity_detected =
true;
3045 CPT(Up) up = cdata->get_up();
3051 parent_node->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread);
3052 return get_component(parent,
this, pipeline_stage, current_thread);
3062 int num_erased = _paths.erase(component);
3063 nassertv(num_erased == 1);
3080 int pipeline_stage,
Thread *current_thread) {
3084 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3085 if (!(*pi)->is_top_node(pipeline_stage, current_thread) &&
3086 (*pi)->get_next(pipeline_stage, current_thread)->get_node() == parent_node) {
3088 (*pi)->set_top_node(pipeline_stage, current_thread);
3092 child_node->fix_path_lengths(pipeline_stage, current_thread);
3108 int pipeline_stage,
Thread *current_thread) {
3112 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3113 if ((*pi)->is_top_node(pipeline_stage, current_thread)) {
3114 (*pi)->set_next(parent_node->get_generic_component(
false, pipeline_stage, current_thread), pipeline_stage, current_thread);
3118 child_node->fix_path_lengths(pipeline_stage, current_thread);
3130fix_path_lengths(
int pipeline_stage,
Thread *current_thread) {
3133 bool any_wrong =
false;
3135 Paths::const_iterator pi;
3136 for (pi = _paths.begin(); pi != _paths.end(); ++pi) {
3137 if ((*pi)->fix_length(pipeline_stage, current_thread)) {
3149 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
3150 children = Children(cdata);
3151 stashed = Stashed(cdata);
3154 int num_children = children.get_num_children();
3156 for (i = 0; i < num_children; ++i) {
3158 child_node->fix_path_lengths(pipeline_stage, current_thread);
3160 int num_stashed = stashed.get_num_stashed();
3161 for (i = 0; i < num_stashed; ++i) {
3163 child_node->fix_path_lengths(pipeline_stage, current_thread);
3172r_list_descendants(ostream &out,
int indent_level)
const {
3173 write(out, indent_level);
3176 int num_children = children.get_num_children();
3178 for (
int i = 0; i < num_children; ++i) {
3179 PandaNode *child = children.get_child(i);
3180 child->r_list_descendants(out, indent_level + 2);
3185 if (num_stashed != 0) {
3186 indent(out, indent_level) <<
"(" << num_stashed <<
" stashed)\n";
3195 nassertr(node !=
nullptr, -1);
3199 Down::const_iterator di;
3200 for (di = down->begin(); di != down->end(); ++di) {
3201 if ((*di).get_child() == node) {
3202 return di - down->begin();
3224 if (drawmask_cat.is_debug()) {
3225 drawmask_cat.debug(
false)
3226 << *
this <<
"::update_cached() {\n";
3232 UpdateSeq last_update = cdata->_last_update;
3233 UpdateSeq next_update = cdata->_next_update;
3234 UpdateSeq last_bounds_update = cdata->_last_bounds_update;
3235 nassertr(last_update != next_update ||
3236 (update_bounds && last_bounds_update != next_update),
3237 CDStageWriter(_cycler, pipeline_stage, cdata));
3240 CollideMask net_collide_mask = cdata->_into_collide_mask;
3241 DrawMask net_draw_control_mask, net_draw_show_mask;
3247 net_draw_control_mask = cdata->_draw_control_mask;
3248 net_draw_show_mask = cdata->_draw_show_mask;
3251 if (drawmask_cat.is_debug()) {
3252 drawmask_cat.debug(
false)
3253 <<
"net_draw_control_mask = " << net_draw_control_mask
3254 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3257 CPT(
RenderAttrib) off_clip_planes = cdata->_state->get_attrib(ClipPlaneAttrib::get_class_slot());
3258 if (off_clip_planes ==
nullptr) {
3259 off_clip_planes = ClipPlaneAttrib::make();
3263 Children children(cdata);
3269 int num_children = children.get_num_children();
3276#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3278 if (update_bounds) {
3279 child_volumes_ref.reserve(num_children + 1);
3282 int child_volumes_i = 0;
3284 bool all_box =
true;
3287 if (update_bounds) {
3289 internal_bounds = get_internal_bounds(pipeline_stage, current_thread);
3291 if (!internal_bounds->is_empty()) {
3292#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3293 child_volumes_ref.push_back(internal_bounds);
3295 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3296 child_volumes[child_volumes_i++] = internal_bounds;
3297 if (internal_bounds->as_bounding_box() ==
nullptr) {
3304 int child_vertices = 0;
3306 for (
int i = 0; i < num_children; ++i) {
3311 CDLockedStageReader child_cdata(child->_cycler, pipeline_stage, current_thread);
3313 UpdateSeq last_child_update = update_bounds
3314 ? child_cdata->_last_bounds_update
3315 : child_cdata->_last_update;
3317 if (last_child_update != child_cdata->_next_update) {
3319 CDStageWriter child_cdataw = child->update_cached(update_bounds, pipeline_stage, child_cdata);
3321 net_collide_mask |= child_cdataw->_net_collide_mask;
3323 if (drawmask_cat.is_debug()) {
3324 drawmask_cat.debug(
false)
3325 <<
"\nchild update " << *child <<
":\n";
3328 DrawMask child_control_mask = child_cdataw->_net_draw_control_mask;
3329 DrawMask child_show_mask = child_cdataw->_net_draw_show_mask;
3330 if (!(child_control_mask | child_show_mask).is_zero()) {
3362 DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask);
3363 exception_mask &= (net_draw_control_mask ^ net_draw_show_mask);
3365 if (drawmask_cat.is_debug()) {
3366 drawmask_cat.debug(
false)
3367 <<
"exception_mask = " << exception_mask <<
"\n";
3371 net_draw_control_mask |= child_control_mask;
3372 net_draw_show_mask |= child_show_mask;
3374 net_draw_control_mask &= ~exception_mask;
3375 net_draw_show_mask |= exception_mask;
3378 if (drawmask_cat.is_debug()) {
3379 drawmask_cat.debug(
false)
3380 <<
"child_control_mask = " << child_control_mask
3381 <<
"\nchild_show_mask = " << child_show_mask
3382 <<
"\nnet_draw_control_mask = " << net_draw_control_mask
3383 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3387 off_clip_planes = orig_cp->compose_off(child_cdataw->_off_clip_planes);
3389 if (update_bounds) {
3390 if (!child_cdataw->_external_bounds->is_empty()) {
3391#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3392 child_volumes_ref.push_back(child_cdataw->_external_bounds);
3394 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3395 child_volumes[child_volumes_i++] = child_cdataw->_external_bounds;
3396 if (child_cdataw->_external_bounds->as_bounding_box() ==
nullptr) {
3400 child_vertices += child_cdataw->_nested_vertices;
3405 net_collide_mask |= child_cdata->_net_collide_mask;
3408 if (drawmask_cat.is_debug()) {
3409 drawmask_cat.debug(
false)
3410 <<
"\nchild fresh " << *child <<
":\n";
3412 DrawMask child_control_mask = child_cdata->_net_draw_control_mask;
3413 DrawMask child_show_mask = child_cdata->_net_draw_show_mask;
3414 if (!(child_control_mask | child_show_mask).is_zero()) {
3417 DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask);
3418 exception_mask &= (net_draw_control_mask ^ net_draw_show_mask);
3420 if (drawmask_cat.is_debug()) {
3421 drawmask_cat.debug(
false)
3422 <<
"exception_mask = " << exception_mask <<
"\n";
3426 net_draw_control_mask |= child_control_mask;
3427 net_draw_show_mask |= child_show_mask;
3429 net_draw_control_mask &= ~exception_mask;
3430 net_draw_show_mask |= exception_mask;
3433 if (drawmask_cat.is_debug()) {
3434 drawmask_cat.debug(
false)
3435 <<
"child_control_mask = " << child_control_mask
3436 <<
"\nchild_show_mask = " << child_show_mask
3437 <<
"\nnet_draw_control_mask = " << net_draw_control_mask
3438 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3442 off_clip_planes = orig_cp->compose_off(child_cdata->_off_clip_planes);
3444 if (update_bounds) {
3445 if (!child_cdata->_external_bounds->is_empty()) {
3446#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3447 child_volumes_ref.push_back(child_cdata->_external_bounds);
3449 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3450 child_volumes[child_volumes_i++] = child_cdata->_external_bounds;
3451 if (child_cdata->_external_bounds->as_bounding_box() ==
nullptr) {
3455 child_vertices += child_cdata->_nested_vertices;
3462 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
3463 if (last_update == cdataw->_last_update &&
3464 next_update == cdataw->_next_update) {
3467 cdataw->_net_collide_mask = net_collide_mask;
3472 DrawMask draw_control_mask = cdataw->_draw_control_mask;
3473 DrawMask draw_show_mask = cdataw->_draw_show_mask;
3475 DrawMask show_through_mask = net_draw_control_mask & net_draw_show_mask;
3477 net_draw_control_mask |= draw_control_mask;
3478 net_draw_show_mask = (net_draw_show_mask & ~draw_control_mask) | (draw_show_mask & draw_control_mask);
3480 net_draw_show_mask |= show_through_mask;
3484 cdataw->_net_draw_control_mask = net_draw_control_mask;
3485 cdataw->_net_draw_show_mask = net_draw_show_mask | ~net_draw_control_mask;
3486 if (drawmask_cat.is_debug()) {
3487 drawmask_cat.debug(
false)
3488 <<
"renderable, set mask " << cdataw->_net_draw_show_mask <<
"\n";
3494 cdataw->_net_draw_control_mask = net_draw_control_mask;
3495 cdataw->_net_draw_show_mask = net_draw_show_mask;
3496 if (drawmask_cat.is_debug()) {
3497 drawmask_cat.debug(
false)
3498 <<
"not renderable, set mask " << cdataw->_net_draw_show_mask <<
"\n";
3502 cdataw->_off_clip_planes = off_clip_planes;
3504 if (update_bounds) {
3505 cdataw->_nested_vertices = cdataw->_internal_vertices + child_vertices;
3510 BoundingVolume::BoundsType btype = cdataw->_bounds_type;
3511 if (btype == BoundingVolume::BT_default) {
3512 btype = bounds_type;
3515 if (btype == BoundingVolume::BT_box ||
3516 (btype != BoundingVolume::BT_sphere && all_box && transform->
is_identity())) {
3526 if (child_volumes_i > 0) {
3528 const BoundingVolume **child_end = child_begin + child_volumes_i;
3534 gbv->xform(transform->
get_mat());
3538 cdataw->_external_bounds = gbv;
3539 cdataw->_last_bounds_update = next_update;
3542 cdataw->_last_update = next_update;
3544 if (drawmask_cat.is_debug()) {
3545 drawmask_cat.debug(
false)
3546 <<
"} " << *
this <<
"::update_cached();\n";
3549 nassertr(cdataw->_last_update == cdataw->_next_update, cdataw);
3557 if (cdataw->_last_update == cdataw->_next_update &&
3558 (!update_bounds || cdataw->_last_bounds_update == cdataw->_next_update)) {
3566 cdata = CDLockedStageReader(_cycler, pipeline_stage, current_thread);
3568 if (cdata->_last_update == cdata->_next_update &&
3569 (!update_bounds || cdata->_last_bounds_update == cdata->_next_update)) {
3572 return CDStageWriter(_cycler, pipeline_stage, cdata);
3586 _scene_root_func = func;
3616 cdata->update_bam_nested(manager);
3647 node->fillin(scan, manager);
3689 _draw_control_mask(
DrawMask::all_off()),
3690 _draw_show_mask(
DrawMask::all_on()),
3693 _user_bounds(nullptr),
3694 _final_bounds(false),
3698 _net_draw_control_mask(
DrawMask::all_off()),
3699 _net_draw_show_mask(
DrawMask::all_off()),
3712CData(
const PandaNode::CData ©) :
3714 _state(copy._state),
3715 _transform(copy._transform),
3716 _prev_transform(copy._prev_transform),
3718 _effects(copy._effects),
3719 _tag_data(copy._tag_data),
3720 _draw_control_mask(copy._draw_control_mask),
3721 _draw_show_mask(copy._draw_show_mask),
3722 _into_collide_mask(copy._into_collide_mask),
3723 _bounds_type(copy._bounds_type),
3724 _user_bounds(copy._user_bounds),
3725 _final_bounds(copy._final_bounds),
3726 _fancy_bits(copy._fancy_bits),
3728 _net_collide_mask(copy._net_collide_mask),
3729 _net_draw_control_mask(copy._net_draw_control_mask),
3730 _net_draw_show_mask(copy._net_draw_show_mask),
3731 _off_clip_planes(copy._off_clip_planes),
3732 _nested_vertices(copy._nested_vertices),
3733 _external_bounds(copy._external_bounds),
3734 _last_update(copy._last_update),
3735 _next_update(copy._next_update),
3736 _last_bounds_update(copy._last_bounds_update),
3739 _stashed(copy._stashed),
3759 return new CData(*
this);
3766void PandaNode::CData::
3774 dg.
add_uint32(_draw_control_mask.get_word());
3776 dg.
add_uint32(_into_collide_mask.get_word());
3780 for (
size_t n = 0; n < _tag_data.size(); ++n) {
3785 write_up_list(*get_up(), manager, dg);
3786 write_down_list(*get_down(), manager, dg);
3794void PandaNode::CData::
3795update_bam_nested(
BamWriter *manager)
const {
3800 update_up_list(*get_up(), manager);
3801 update_down_list(*get_down(), manager);
3809int PandaNode::CData::
3815 DCAST_INTO_R(state, p_list[pi++], pi);
3819 DCAST_INTO_R(transform, p_list[pi++], pi);
3820 _prev_transform = _transform = transform;
3838 DCAST_INTO_R(effects, p_list[pi++], pi);
3855 pi += complete_up_list(*modify_up(),
"up", p_list + pi, manager);
3856 pi += complete_down_list(*modify_down(),
"down", p_list + pi, manager);
3857 pi += complete_down_list(*modify_stashed(),
"stashed", p_list + pi, manager);
3861 set_fancy_bit(FB_transform, !_transform->is_identity());
3862 set_fancy_bit(FB_state, !_state->is_empty());
3863 set_fancy_bit(FB_effects, !_effects->is_empty());
3864 set_fancy_bit(FB_tag, !_tag_data.is_empty());
3869 nassertr(!_transform->is_invalid(), pi);
3870 nassertr(!_prev_transform->is_invalid(), pi);
3879void PandaNode::CData::
3894 _draw_control_mask = _overall_bit;
3895 _draw_show_mask = ~_overall_bit;
3904 draw_mask &= ~_overall_bit;
3905 _draw_control_mask = ~draw_mask;
3906 _draw_show_mask = draw_mask;
3914 _into_collide_mask.set_word(scan.
get_uint32());
3916 _bounds_type = BoundingVolume::BT_default;
3918 _bounds_type = (BoundingVolume::BoundsType)scan.
get_uint8();
3923 for (
int i = 0; i < num_tags; i++) {
3926 _tag_data.store(key, value);
3930 fillin_up_list(*modify_up(),
"up", scan, manager);
3931 fillin_down_list(*modify_down(),
"down", scan, manager);
3932 fillin_down_list(*modify_stashed(),
"stashed", scan, manager);
3938void PandaNode::CData::
3951 int num_parents = 0;
3952 Up::const_iterator ui;
3953 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3959 nassertv(num_parents == (
int)(uint16_t)num_parents);
3961 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3972void PandaNode::CData::
3975 int num_children = down_list.size();
3976 nassertv(num_children == (
int)(uint16_t)num_children);
3981 Down::const_iterator di;
3982 for (di = down_list.begin(); di != down_list.end(); ++di) {
3984 int sort = (*di).get_sort();
3993void PandaNode::CData::
3995 Up::const_iterator ui;
3996 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
4007void PandaNode::CData::
4009 Down::const_iterator di;
4010 for (di = down_list.begin(); di != down_list.end(); ++di) {
4019int PandaNode::CData::
4025 Up new_up_list(PandaNode::get_class_type());
4026 new_up_list.reserve(num_parents);
4027 for (
int i = 0; i < num_parents; i++) {
4029 UpConnection connection(parent_node);
4030 new_up_list.push_back(connection);
4038 up_list.swap(new_up_list);
4039 new_up_list.clear();
4047int PandaNode::CData::
4052 BamReaderAuxDataDown *aux;
4055 Down &new_down_list = aux->_down_list;
4056 for (Down::iterator di = new_down_list.begin();
4057 di != new_down_list.end();
4060 (*di).set_child(child_node);
4068 down_list.swap(new_down_list);
4069 new_down_list.clear();
4078void PandaNode::CData::
4090void PandaNode::CData::
4098 Down new_down_list(PandaNode::get_class_type());
4099 new_down_list.reserve(num_children);
4100 for (
int i = 0; i < num_children; i++) {
4103 DownConnection connection(
nullptr, sort);
4104 new_down_list.push_back(connection);
4109 PT(BamReaderAuxDataDown) aux =
new BamReaderAuxDataDown;
4110 aux->_down_list.swap(new_down_list);
4121 ? _cdata->_last_bounds_update
4122 : _cdata->_last_update;
4124 if (last_update != _cdata->_next_update) {
4133 int pipeline_stage = _current_thread->get_pipeline_stage();
4135 if (fresh_cdata->_last_update == fresh_cdata->_next_update &&
4136 (!update_bounds || fresh_cdata->_last_bounds_update == fresh_cdata->_next_update)) {
4139 if (_cdata != (
const PandaNode::CData *)fresh_cdata) {
4149 PStatTimer timer(PandaNode::_update_bounds_pcollector);
4151 nassertv(cdataw->_last_update == cdataw->_next_update);
4154 if (_cdata != (
const PandaNode::CData *)cdataw) {
4163 nassertv(_cdata->_last_update == _cdata->_next_update);
4164 nassertv(!update_bounds || _cdata->_last_bounds_update == _cdata->_next_update);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
int get_int_tag(const std::string &tag) const
Returns the value previously set via set_int_tag().
BamReaderAuxData * get_aux_tag(const std::string &tag) const
Returns the value previously set via set_aux_tag().
void finalize_now(TypedWritable *whom)
Forces the finalization of a particular object.
void set_aux_tag(const std::string &tag, BamReaderAuxData *value)
Allows the creating object to store a temporary data value on the BamReader.
void set_int_tag(const std::string &tag, int value)
Allows the creating object to store a temporary data value on the BamReader.
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
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...
void consider_update(const TypedWritable *obj)
Should be called from TypedWritable::update_bam_nested() to recursively check the entire hiererachy o...
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
static BitMask< uint32_t, nbits > bit(int index)
Returns a BitMask with only the indicated bit on.
static BitMask< uint32_t, nbits > all_on()
Returns a BitMask whose bits are all on.
static BitMask< uint32_t, nbits > all_off()
Returns a BitMask whose bits are all off.
void set_word(WordType value)
Sets the entire BitMask to the value indicated by the given word.
bool is_zero() const
Returns true if the entire bitmask is zero, false otherwise.
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
This defines a bounding sphere, consisting of a center and a radius.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
bool around(const BoundingVolume **first, const BoundingVolume **last)
Resets the volume to enclose only the volumes indicated.
This functions similarly to a LightAttrib.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
This class is similar to CycleDataLockedReader, except it allows reading from a particular stage of t...
Thread * get_current_thread() const
Returns the Thread pointer of the currently-executing thread, as passed to the constructor of this ob...
const CycleDataType * take_pointer()
This is intended to be called only from CycleDataStageWriter when it elevates the pointer from read t...
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
This class is similar to CycleDataReader, except it allows reading from a particular stage of the pip...
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
A single page of data maintained by a PipelineCycler.
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().
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
std::string get_string()
Extracts a variable-length string.
int32_t get_int32()
Extracts a signed 32-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
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 register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Similar to MutexHolder, but for a light mutex.
Similar to MutexHolder, but for a light reentrant mutex.
The abstract interface to all kinds of lights.
This just stores the pointers to implement a doubly-linked list of some kind of object.
static void update_type(ReferenceCount *ptr, TypeHandle type)
Associates the indicated type with the given pointer.
A base class for all things which can have a name.
This is one component of a NodePath.
PandaNode * get_node() const
Returns the node referenced by this component.
bool is_top_node(int pipeline_stage, Thread *current_thread) const
Returns true if this component represents the top node in the path.
NodePathComponent * get_next(int pipeline_stage, Thread *current_thread) const
Returns the next component in the path.
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.
A lightweight class that represents a single element that may be timed and/or counted via stats.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
This class maintains a linked list of PandaNodes.
Encapsulates the data from a PandaNode, pre-fetched for one stage of the pipeline.
void check_cached(bool update_bounds) const
Ensures that the draw masks etc.
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...
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
size_t get_num_children() const
Returns the number of children of the node.
PandaNode * get_parent(size_t n) const
Returns the nth parent of the node.
size_t get_num_parents() const
Returns the number of parents of the node.
PandaNode * get_stashed(size_t n) const
Returns the nth stashed child of the node.
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...
size_t get_num_stashed() const
Returns the number of stashed children of the node.
A basic node of the scene graph or data graph.
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.
void write_recorder(BamWriter *manager, Datagram &dg)
This method is provided for the benefit of classes (like MouseRecorder) that inherit from PandaMode a...
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...
virtual bool preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
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...
get_draw_control_mask
Returns the set of bits in draw_show_mask that are considered meaningful.
virtual bool is_geom_node() const
A simple downcast check.
void get_tag_keys(vector_string &keys) const
Fills the given vector up with the list of tags on this PandaNode.
virtual PandaNode * combine_with(PandaNode *other)
Collapses this PandaNode with the other PandaNode, if possible, and returns a pointer to the combined...
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,...
bool unstash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Returns the indicated stashed node to normal child status.
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 ...
virtual bool safe_to_combine() const
Returns true if it is generally safe to combine this particular kind of PandaNode with other kinds of...
virtual int get_unsafe_to_apply_attribs() const
Returns the union of all attributes from SceneGraphReducer::AttribTypes that may not safely be applie...
virtual int get_visible_child() const
Returns the index number of the currently visible child of this node.
set_tag
Associates a user-defined value with a user-defined key which is stored on the node.
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of PandaNode by calling the xf...
void clear_unexpected_change(unsigned int flags)
Sets one or more of the PandaNode::UnexpectedChange bits off, indicating that the corresponding prope...
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.
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...
void clear_effect(TypeHandle type)
Removes the render effect of the given type from this node.
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...
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 remove_all_children(Thread *current_thread=Thread::get_current_thread())
Removes all the children from the node at once, including stashed children.
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_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
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...
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other.
virtual bool safe_to_modify_transform() const
Returns true if it is safe to automatically adjust the transform on this kind of node.
void remove_stashed(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth stashed child from the node.
get_legal_collide_mask
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode.
virtual void r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, GeomTransformer &transformer, Thread *current_thread)
The recursive implementation of prepare_scene().
void set_bounds(const BoundingVolume *volume)
Resets the bounding volume so that it is the indicated volume.
set_effects
Sets the complete RenderEffects that will be applied this node.
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
static void register_with_read_factory()
Tells the BamReader how to create objects of type PandaNode.
get_parents
Returns an object that can be used to walk through the list of parents of the node,...
get_num_stashed
Returns the number of stashed nodes this node has.
void adjust_draw_mask(DrawMask show_mask, DrawMask hide_mask, DrawMask clear_mask)
Adjusts the hide/show bits of this particular node.
get_draw_show_mask
Returns the hide/show bits of this particular node.
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this PandaNode by the indicated matrix, if it means anything to do so.
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...
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...
get_child
Returns the nth child node of this node.
void copy_all_properties(PandaNode *other)
Copies the TransformState, RenderState, RenderEffects, tags, Python tags, and the show/hide state fro...
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 ...
virtual PandaNode * dupe_for_flatten() const
This is similar to make_copy(), but it makes a copy for the specific purpose of flatten.
set_state
Sets the complete RenderState that will be applied to all nodes at this level and below.
virtual bool has_selective_visibility() const
Should be overridden by derived classes to return true if this kind of node has some restrictions on ...
set_transform
Sets the transform that will be applied to this node and below.
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
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_scene_root() const
Returns true if this particular node is known to be the render root of some active DisplayRegion asso...
virtual bool is_lod_node() const
A simple downcast check.
bool stash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Stashes the indicated child node.
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.
virtual bool is_collision_node() const
A simple downcast check.
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.
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...
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...
clear_tag
Removes the value defined for this key on this particular node.
void copy_tags(PandaNode *other)
Copies all of the tags stored on the other node onto this node.
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 set_bound(const BoundingVolume *volume)
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...
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.
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
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...
void set_attrib(const RenderAttrib *attrib, int override=0)
Adds the indicated render attribute to the scene graph on this node.
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,...
get_stashed
Returns the nth stashed child of this node.
set_into_collide_mask
Sets the "into" CollideMask.
void set_unexpected_change(unsigned int flags)
Sets one or more of the PandaNode::UnexpectedChange bits on, indicating that the corresponding proper...
get_children
Returns an object that can be used to walk through the list of children of the node.
get_bounds_type
Returns the bounding volume type set with set_bounds_type().
void replace_node(PandaNode *other)
Inserts this node into the scene graph in place of the other one, and removes the other node.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
void steal_children(PandaNode *other, Thread *current_thread=Thread::get_current_thread())
Moves all the children from the other node onto this node.
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_bounds_type
Specifies the desired type of bounding volume that will be created for this node.
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...
virtual Light * as_light()
Cross-casts the node to a Light pointer, if it is one of the four kinds of Light nodes,...
get_parent
Returns the nth parent node of this node.
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_children
Returns the number of child nodes this node has.
A base class for all things that want to be reference-counted.
bool ref_if_nonzero() const
Atomically increases the reference count of this object if it is not zero.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
This is the base class for a number of special render effects that may be set on scene graph nodes to...
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
bool is_empty() const
Returns true if the state is empty, false otherwise.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
bool is_empty() const
Returns true if the state is empty, false otherwise.
const Key & get_key(size_t n) const
Returns the key in the nth entry of the table.
constexpr size_t size() const
Returns the total number of entries in the table.
const Value & get_data(size_t n) const
Returns the data in the nth entry of the table.
A thread; that is, a lightweight process.
get_pipeline_stage
Returns the Pipeline stage number associated with this thread.
get_current_thread
Returns a pointer to the currently-executing Thread object.
TypeHandle is the identifier used to differentiate C++ class types.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
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...
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 ...
void mark_bam_modified()
Increments the bam_modified counter, so that this object will be invalidated and retransmitted on any...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This is a sequence number that increments monotonically.
This is our own Panda specialization on the default STL map.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void node_unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void release_read_stage(int pipeline_stage, const CycleData *pointer) const
Releases a pointer previously obtained via a call to read_stage().