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 #ifdef DO_MEMORY_USAGE
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);
304 xform(
const LMatrix4 &) {
352 calc_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;
492 copy_subgraph(
Thread *current_thread)
const {
493 InstanceMap inst_map;
494 return r_copy_subgraph(inst_map, current_thread);
501 count_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);
969 clear_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;
1207 set_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;
1277 list_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());
1328 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;
1733 get_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);
1807 output(ostream &out)
const {
1808 out << get_type() <<
" " << get_name();
1815 write(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";
1938 get_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;
1996 get_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;
2027 mark_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);
2046 mark_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);
2119 decode_from_bam_stream(vector_uchar data,
BamReader *reader) {
2135 get_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;
2182 get_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);
2245 force_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);
2257 force_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);
2288 r_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);
2334 children_changed() {
2335 nassertv((_unexpected_change_flags & UC_children) == 0);
2344 transform_changed() {
2345 nassertv((_unexpected_change_flags & UC_transform) == 0);
2355 nassertv((_unexpected_change_flags & UC_state) == 0);
2363 draw_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);
2462 set_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);
2476 disable_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);
2491 stage_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();
2616 quick_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);
2901 Paths::const_iterator pi;
2902 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
2903 if ((*pi)->get_next(pipeline_stage, current_thread) == parent) {
2911 CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2912 int parent_index = child_node->do_find_parent(parent_node, cdata_child);
2914 if (parent_index >= 0) {
2918 child_node->_paths.insert(child);
2937 get_top_component(
PandaNode *child_node,
bool force,
int pipeline_stage,
2938 Thread *current_thread) {
2943 Paths::const_iterator pi;
2944 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
2945 if ((*pi)->is_top_node(pipeline_stage, current_thread)) {
2961 pipeline_stage, current_thread);
2962 child_node->_paths.insert(child);
2975 get_generic_component(
bool accept_ambiguity,
int pipeline_stage,
2976 Thread *current_thread) {
2977 bool ambiguity_detected =
false;
2979 r_get_generic_component(accept_ambiguity, ambiguity_detected,
2980 pipeline_stage, current_thread);
2982 if (!accept_ambiguity && ambiguity_detected) {
2983 pgraph_cat.warning()
2984 <<
"Chose: " << *result <<
"\n";
2985 nassertr(!unambiguous_graph, result);
2997 r_get_generic_component(
bool accept_ambiguity,
bool &ambiguity_detected,
2998 int pipeline_stage,
Thread *current_thread) {
3002 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
3004 int num_parents = cdata->get_up()->size();
3005 if (num_parents == 0) {
3007 return get_top_component(
this,
true, pipeline_stage, current_thread);
3011 if (num_parents == 1) {
3014 get_parent(0)->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread);
3015 return get_component(parent,
this, pipeline_stage, current_thread);
3019 if (!accept_ambiguity) {
3020 pgraph_cat.warning()
3021 << *
this <<
" has " << num_parents
3022 <<
" parents; choosing arbitrary path to root.\n";
3024 ambiguity_detected =
true;
3025 CPT(Up) up = cdata->get_up();
3031 parent_node->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread);
3032 return get_component(parent,
this, pipeline_stage, current_thread);
3042 int num_erased = _paths.erase(component);
3043 nassertv(num_erased == 1);
3060 int pipeline_stage,
Thread *current_thread) {
3064 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3065 if (!(*pi)->is_top_node(pipeline_stage, current_thread) &&
3066 (*pi)->get_next(pipeline_stage, current_thread)->get_node() == parent_node) {
3068 (*pi)->set_top_node(pipeline_stage, current_thread);
3072 child_node->fix_path_lengths(pipeline_stage, current_thread);
3088 int pipeline_stage,
Thread *current_thread) {
3092 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3093 if ((*pi)->is_top_node(pipeline_stage, current_thread)) {
3094 (*pi)->set_next(parent_node->get_generic_component(
false, pipeline_stage, current_thread), pipeline_stage, current_thread);
3098 child_node->fix_path_lengths(pipeline_stage, current_thread);
3110 fix_path_lengths(
int pipeline_stage,
Thread *current_thread) {
3113 bool any_wrong =
false;
3115 Paths::const_iterator pi;
3116 for (pi = _paths.begin(); pi != _paths.end(); ++pi) {
3117 if ((*pi)->fix_length(pipeline_stage, current_thread)) {
3129 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
3130 children = Children(cdata);
3131 stashed = Stashed(cdata);
3134 int num_children = children.get_num_children();
3136 for (i = 0; i < num_children; ++i) {
3138 child_node->fix_path_lengths(pipeline_stage, current_thread);
3140 int num_stashed = stashed.get_num_stashed();
3141 for (i = 0; i < num_stashed; ++i) {
3143 child_node->fix_path_lengths(pipeline_stage, current_thread);
3152 r_list_descendants(ostream &out,
int indent_level)
const {
3153 write(out, indent_level);
3156 int num_children = children.get_num_children();
3158 for (
int i = 0; i < num_children; ++i) {
3159 PandaNode *child = children.get_child(i);
3160 child->r_list_descendants(out, indent_level + 2);
3165 if (num_stashed != 0) {
3166 indent(out, indent_level) <<
"(" << num_stashed <<
" stashed)\n";
3175 nassertr(node !=
nullptr, -1);
3179 Down::const_iterator di;
3180 for (di = down->begin(); di != down->end(); ++di) {
3181 if ((*di).get_child() == node) {
3182 return di - down->begin();
3204 if (drawmask_cat.is_debug()) {
3205 drawmask_cat.debug(
false)
3206 << *
this <<
"::update_cached() {\n";
3212 UpdateSeq last_update = cdata->_last_update;
3213 UpdateSeq next_update = cdata->_next_update;
3214 UpdateSeq last_bounds_update = cdata->_last_bounds_update;
3215 nassertr(last_update != next_update ||
3216 (update_bounds && last_bounds_update != next_update),
3217 CDStageWriter(_cycler, pipeline_stage, cdata));
3220 CollideMask net_collide_mask = cdata->_into_collide_mask;
3221 DrawMask net_draw_control_mask, net_draw_show_mask;
3227 net_draw_control_mask = cdata->_draw_control_mask;
3228 net_draw_show_mask = cdata->_draw_show_mask;
3231 if (drawmask_cat.is_debug()) {
3232 drawmask_cat.debug(
false)
3233 <<
"net_draw_control_mask = " << net_draw_control_mask
3234 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3237 CPT(
RenderAttrib) off_clip_planes = cdata->_state->get_attrib(ClipPlaneAttrib::get_class_slot());
3238 if (off_clip_planes ==
nullptr) {
3239 off_clip_planes = ClipPlaneAttrib::make();
3243 Children children(cdata);
3245 int num_vertices = cdata->_internal_vertices;
3251 int num_children = children.get_num_children();
3258 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3260 if (update_bounds) {
3261 child_volumes_ref.reserve(num_children + 1);
3264 int child_volumes_i = 0;
3266 bool all_box =
true;
3269 if (update_bounds) {
3271 internal_bounds = get_internal_bounds(pipeline_stage, current_thread);
3273 if (!internal_bounds->is_empty()) {
3274 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3275 child_volumes_ref.push_back(internal_bounds);
3277 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3278 child_volumes[child_volumes_i++] = internal_bounds;
3279 if (internal_bounds->as_bounding_box() ==
nullptr) {
3287 for (
int i = 0; i < num_children; ++i) {
3292 CDLockedStageReader child_cdata(child->_cycler, pipeline_stage, current_thread);
3294 UpdateSeq last_child_update = update_bounds
3295 ? child_cdata->_last_bounds_update
3296 : child_cdata->_last_update;
3298 if (last_child_update != child_cdata->_next_update) {
3300 CDStageWriter child_cdataw = child->update_cached(update_bounds, pipeline_stage, child_cdata);
3302 net_collide_mask |= child_cdataw->_net_collide_mask;
3304 if (drawmask_cat.is_debug()) {
3305 drawmask_cat.debug(
false)
3306 <<
"\nchild update " << *child <<
":\n";
3309 DrawMask child_control_mask = child_cdataw->_net_draw_control_mask;
3310 DrawMask child_show_mask = child_cdataw->_net_draw_show_mask;
3311 if (!(child_control_mask | child_show_mask).is_zero()) {
3343 DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask);
3344 exception_mask &= (net_draw_control_mask ^ net_draw_show_mask);
3346 if (drawmask_cat.is_debug()) {
3347 drawmask_cat.debug(
false)
3348 <<
"exception_mask = " << exception_mask <<
"\n";
3352 net_draw_control_mask |= child_control_mask;
3353 net_draw_show_mask |= child_show_mask;
3355 net_draw_control_mask &= ~exception_mask;
3356 net_draw_show_mask |= exception_mask;
3359 if (drawmask_cat.is_debug()) {
3360 drawmask_cat.debug(
false)
3361 <<
"child_control_mask = " << child_control_mask
3362 <<
"\nchild_show_mask = " << child_show_mask
3363 <<
"\nnet_draw_control_mask = " << net_draw_control_mask
3364 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3368 off_clip_planes = orig_cp->compose_off(child_cdataw->_off_clip_planes);
3370 if (update_bounds) {
3371 if (!child_cdataw->_external_bounds->is_empty()) {
3372 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3373 child_volumes_ref.push_back(child_cdataw->_external_bounds);
3375 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3376 child_volumes[child_volumes_i++] = child_cdataw->_external_bounds;
3377 if (child_cdataw->_external_bounds->as_bounding_box() ==
nullptr) {
3381 num_vertices += child_cdataw->_nested_vertices;
3386 net_collide_mask |= child_cdata->_net_collide_mask;
3389 if (drawmask_cat.is_debug()) {
3390 drawmask_cat.debug(
false)
3391 <<
"\nchild fresh " << *child <<
":\n";
3393 DrawMask child_control_mask = child_cdata->_net_draw_control_mask;
3394 DrawMask child_show_mask = child_cdata->_net_draw_show_mask;
3395 if (!(child_control_mask | child_show_mask).is_zero()) {
3398 DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask);
3399 exception_mask &= (net_draw_control_mask ^ net_draw_show_mask);
3401 if (drawmask_cat.is_debug()) {
3402 drawmask_cat.debug(
false)
3403 <<
"exception_mask = " << exception_mask <<
"\n";
3407 net_draw_control_mask |= child_control_mask;
3408 net_draw_show_mask |= child_show_mask;
3410 net_draw_control_mask &= ~exception_mask;
3411 net_draw_show_mask |= exception_mask;
3414 if (drawmask_cat.is_debug()) {
3415 drawmask_cat.debug(
false)
3416 <<
"child_control_mask = " << child_control_mask
3417 <<
"\nchild_show_mask = " << child_show_mask
3418 <<
"\nnet_draw_control_mask = " << net_draw_control_mask
3419 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3423 off_clip_planes = orig_cp->compose_off(child_cdata->_off_clip_planes);
3425 if (update_bounds) {
3426 if (!child_cdata->_external_bounds->is_empty()) {
3427 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3428 child_volumes_ref.push_back(child_cdata->_external_bounds);
3430 nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3431 child_volumes[child_volumes_i++] = child_cdata->_external_bounds;
3432 if (child_cdata->_external_bounds->as_bounding_box() ==
nullptr) {
3436 num_vertices += child_cdata->_nested_vertices;
3443 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
3444 if (last_update == cdataw->_last_update &&
3445 next_update == cdataw->_next_update) {
3448 cdataw->_net_collide_mask = net_collide_mask;
3453 DrawMask draw_control_mask = cdataw->_draw_control_mask;
3454 DrawMask draw_show_mask = cdataw->_draw_show_mask;
3456 DrawMask show_through_mask = net_draw_control_mask & net_draw_show_mask;
3458 net_draw_control_mask |= draw_control_mask;
3459 net_draw_show_mask = (net_draw_show_mask & ~draw_control_mask) | (draw_show_mask & draw_control_mask);
3461 net_draw_show_mask |= show_through_mask;
3465 cdataw->_net_draw_control_mask = net_draw_control_mask;
3466 cdataw->_net_draw_show_mask = net_draw_show_mask | ~net_draw_control_mask;
3467 if (drawmask_cat.is_debug()) {
3468 drawmask_cat.debug(
false)
3469 <<
"renderable, set mask " << cdataw->_net_draw_show_mask <<
"\n";
3475 cdataw->_net_draw_control_mask = net_draw_control_mask;
3476 cdataw->_net_draw_show_mask = net_draw_show_mask;
3477 if (drawmask_cat.is_debug()) {
3478 drawmask_cat.debug(
false)
3479 <<
"not renderable, set mask " << cdataw->_net_draw_show_mask <<
"\n";
3483 cdataw->_off_clip_planes = off_clip_planes;
3485 if (update_bounds) {
3486 cdataw->_nested_vertices = num_vertices;
3491 BoundingVolume::BoundsType btype = cdataw->_bounds_type;
3492 if (btype == BoundingVolume::BT_default) {
3493 btype = bounds_type;
3496 if (btype == BoundingVolume::BT_box ||
3497 (btype != BoundingVolume::BT_sphere && all_box && transform->
is_identity())) {
3507 if (child_volumes_i > 0) {
3509 const BoundingVolume **child_end = child_begin + child_volumes_i;
3515 gbv->xform(transform->
get_mat());
3519 cdataw->_external_bounds = gbv;
3520 cdataw->_last_bounds_update = next_update;
3523 cdataw->_last_update = next_update;
3525 if (drawmask_cat.is_debug()) {
3526 drawmask_cat.debug(
false)
3527 <<
"} " << *
this <<
"::update_cached();\n";
3530 nassertr(cdataw->_last_update == cdataw->_next_update, cdataw);
3538 if (cdataw->_last_update == cdataw->_next_update &&
3539 (!update_bounds || cdataw->_last_bounds_update == cdataw->_next_update)) {
3547 cdata = CDLockedStageReader(_cycler, pipeline_stage, current_thread);
3549 if (cdata->_last_update == cdata->_next_update &&
3550 (!update_bounds || cdata->_last_bounds_update == cdata->_next_update)) {
3553 return CDStageWriter(_cycler, pipeline_stage, cdata);
3567 _scene_root_func = func;
3597 cdata->update_bam_nested(manager);
3628 node->fillin(scan, manager);
3670 _draw_control_mask(
DrawMask::all_off()),
3671 _draw_show_mask(
DrawMask::all_on()),
3674 _user_bounds(nullptr),
3675 _final_bounds(false),
3679 _net_draw_control_mask(
DrawMask::all_off()),
3680 _net_draw_show_mask(
DrawMask::all_off()),
3693 CData(
const PandaNode::CData ©) :
3695 _state(copy._state),
3696 _transform(copy._transform),
3697 _prev_transform(copy._prev_transform),
3699 _effects(copy._effects),
3700 _tag_data(copy._tag_data),
3701 _draw_control_mask(copy._draw_control_mask),
3702 _draw_show_mask(copy._draw_show_mask),
3703 _into_collide_mask(copy._into_collide_mask),
3704 _bounds_type(copy._bounds_type),
3705 _user_bounds(copy._user_bounds),
3706 _final_bounds(copy._final_bounds),
3707 _fancy_bits(copy._fancy_bits),
3709 _net_collide_mask(copy._net_collide_mask),
3710 _net_draw_control_mask(copy._net_draw_control_mask),
3711 _net_draw_show_mask(copy._net_draw_show_mask),
3712 _off_clip_planes(copy._off_clip_planes),
3713 _nested_vertices(copy._nested_vertices),
3714 _external_bounds(copy._external_bounds),
3715 _last_update(copy._last_update),
3716 _next_update(copy._next_update),
3717 _last_bounds_update(copy._last_bounds_update),
3720 _stashed(copy._stashed),
3740 return new CData(*
this);
3747 void PandaNode::CData::
3755 dg.
add_uint32(_draw_control_mask.get_word());
3757 dg.
add_uint32(_into_collide_mask.get_word());
3761 for (
size_t n = 0; n < _tag_data.size(); ++n) {
3766 write_up_list(*get_up(), manager, dg);
3767 write_down_list(*get_down(), manager, dg);
3768 write_down_list(*get_stashed(), manager, dg);
3775 void PandaNode::CData::
3776 update_bam_nested(
BamWriter *manager)
const {
3781 update_up_list(*get_up(), manager);
3782 update_down_list(*get_down(), manager);
3783 update_down_list(*get_stashed(), manager);
3790 int PandaNode::CData::
3796 DCAST_INTO_R(state, p_list[pi++], pi);
3800 DCAST_INTO_R(transform, p_list[pi++], pi);
3801 _prev_transform = _transform = transform;
3819 DCAST_INTO_R(effects, p_list[pi++], pi);
3836 pi += complete_up_list(*modify_up(),
"up", p_list + pi, manager);
3837 pi += complete_down_list(*modify_down(),
"down", p_list + pi, manager);
3838 pi += complete_down_list(*modify_stashed(),
"stashed", p_list + pi, manager);
3842 set_fancy_bit(FB_transform, !_transform->is_identity());
3843 set_fancy_bit(FB_state, !_state->is_empty());
3844 set_fancy_bit(FB_effects, !_effects->is_empty());
3845 set_fancy_bit(FB_tag, !_tag_data.is_empty());
3850 nassertr(!_transform->is_invalid(), pi);
3851 nassertr(!_prev_transform->is_invalid(), pi);
3860 void PandaNode::CData::
3875 _draw_control_mask = _overall_bit;
3876 _draw_show_mask = ~_overall_bit;
3885 draw_mask &= ~_overall_bit;
3886 _draw_control_mask = ~draw_mask;
3887 _draw_show_mask = draw_mask;
3895 _into_collide_mask.set_word(scan.
get_uint32());
3897 _bounds_type = BoundingVolume::BT_default;
3899 _bounds_type = (BoundingVolume::BoundsType)scan.
get_uint8();
3904 for (
int i = 0; i < num_tags; i++) {
3907 _tag_data.store(key, value);
3911 fillin_up_list(*modify_up(),
"up", scan, manager);
3912 fillin_down_list(*modify_down(),
"down", scan, manager);
3913 fillin_down_list(*modify_stashed(),
"stashed", scan, manager);
3919 void PandaNode::CData::
3932 int num_parents = 0;
3933 Up::const_iterator ui;
3934 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3940 nassertv(num_parents == (
int)(uint16_t)num_parents);
3942 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3953 void PandaNode::CData::
3956 int num_children = down_list.size();
3957 nassertv(num_children == (
int)(uint16_t)num_children);
3962 Down::const_iterator di;
3963 for (di = down_list.begin(); di != down_list.end(); ++di) {
3965 int sort = (*di).get_sort();
3974 void PandaNode::CData::
3976 Up::const_iterator ui;
3977 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3988 void PandaNode::CData::
3990 Down::const_iterator di;
3991 for (di = down_list.begin(); di != down_list.end(); ++di) {
4000 int PandaNode::CData::
4006 Up new_up_list(PandaNode::get_class_type());
4007 new_up_list.reserve(num_parents);
4008 for (
int i = 0; i < num_parents; i++) {
4010 UpConnection connection(parent_node);
4011 new_up_list.push_back(connection);
4019 up_list.swap(new_up_list);
4020 new_up_list.clear();
4028 int PandaNode::CData::
4033 BamReaderAuxDataDown *aux;
4036 Down &new_down_list = aux->_down_list;
4037 for (Down::iterator di = new_down_list.begin();
4038 di != new_down_list.end();
4041 (*di).set_child(child_node);
4049 down_list.swap(new_down_list);
4050 new_down_list.clear();
4059 void PandaNode::CData::
4071 void PandaNode::CData::
4079 Down new_down_list(PandaNode::get_class_type());
4080 new_down_list.reserve(num_children);
4081 for (
int i = 0; i < num_children; i++) {
4084 DownConnection connection(
nullptr, sort);
4085 new_down_list.push_back(connection);
4090 PT(BamReaderAuxDataDown) aux =
new BamReaderAuxDataDown;
4091 aux->_down_list.swap(new_down_list);
4102 ? _cdata->_last_bounds_update
4103 : _cdata->_last_update;
4105 if (last_update != _cdata->_next_update) {
4110 #ifdef DO_PIPELINING
4116 if (fresh_cdata->_last_update == fresh_cdata->_next_update &&
4117 (!update_bounds || fresh_cdata->_last_bounds_update == fresh_cdata->_next_update)) {
4120 if (_cdata != (
const PandaNode::CData *)fresh_cdata) {
4122 #ifdef DO_PIPELINING
4130 PStatTimer timer(PandaNode::_update_bounds_pcollector);
4132 nassertv(cdataw->_last_update == cdataw->_next_update);
4135 if (_cdata != (
const PandaNode::CData *)cdataw) {
4137 #ifdef DO_PIPELINING
4144 nassertv(_cdata->_last_update == _cdata->_next_update);
4145 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.
void set_bounds_type(BoundingVolume::BoundsType bounds_type)
Specifies the desired type of bounding volume that will be created for this node.
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)
Deprecated.
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...
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.
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.
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.
CPT(TransformState) PandaNode
This is used to support NodePath::calc_tight_bounds().
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.
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().