15 #include "pandaNode.h" 16 #include "config_pgraph.h" 17 #include "nodePathComponent.h" 18 #include "bamReader.h" 19 #include "bamWriter.h" 21 #include "geometricBoundingVolume.h" 22 #include "sceneGraphReducer.h" 23 #include "accumulatedAttribs.h" 24 #include "clipPlaneAttrib.h" 25 #include "boundingSphere.h" 26 #include "boundingBox.h" 27 #include "pStatTimer.h" 28 #include "config_mathutil.h" 29 #include "lightReMutexHolder.h" 30 #include "graphicsStateGuardianBase.h" 34 NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH);
35 NotifyCategoryDef(drawmask,
"");
37 TypeHandle PandaNode::BamReaderAuxDataDown::_type_handle;
39 PandaNode::SceneRootFunc *PandaNode::_scene_root_func;
41 PandaNodeChain PandaNode::_dirty_prev_transforms(
"_dirty_prev_transforms");
44 PStatCollector PandaNode::_reset_prev_pcollector(
"App:Collisions:Reset");
49 TypeHandle PandaNodePipelineReader::_type_handle;
82 PandaNode(
const string &name) :
84 _paths_lock(
"PandaNode::_paths_lock"),
85 _dirty_prev_transform(false)
87 if (pgraph_cat.is_debug()) {
89 <<
"Constructing " << (
void *)
this <<
", " << get_name() <<
"\n";
92 _unexpected_change_flags = 0;
95 #ifdef DO_MEMORY_USAGE 96 MemoryUsage::update_type(
this,
this);
107 if (pgraph_cat.is_debug()) {
109 <<
"Destructing " << (
void *)
this <<
", " << get_name() <<
"\n";
112 if (_dirty_prev_transform) {
115 do_clear_dirty_prev_transform();
133 remove_all_children();
147 _paths_lock(
"PandaNode::_paths_lock"),
148 _dirty_prev_transform(false)
150 if (pgraph_cat.is_debug()) {
152 <<
"Copying " << (
void *)
this <<
", " << get_name() <<
"\n";
154 #ifdef DO_MEMORY_USAGE 155 MemoryUsage::update_type(
this,
this);
159 _unexpected_change_flags = 0;
167 CDReader copy_cdata(copy._cycler);
168 CDWriter cdata(_cycler,
true);
169 cdata->_state = copy_cdata->_state;
170 cdata->_transform = copy_cdata->_transform;
171 cdata->_prev_transform = copy_cdata->_prev_transform;
172 if (cdata->_transform != cdata->_prev_transform) {
173 do_set_dirty_prev_transform();
176 cdata->_effects = copy_cdata->_effects;
177 cdata->_tag_data = copy_cdata->_tag_data;
178 cdata->_draw_control_mask = copy_cdata->_draw_control_mask;
179 cdata->_draw_show_mask = copy_cdata->_draw_show_mask;
180 cdata->_into_collide_mask = copy_cdata->_into_collide_mask;
181 cdata->_bounds_type = copy_cdata->_bounds_type;
182 cdata->_user_bounds = copy_cdata->_user_bounds;
183 cdata->_internal_bounds = NULL;
186 ++cdata->_internal_bounds_mark;
187 cdata->_final_bounds = copy_cdata->_final_bounds;
188 cdata->_fancy_bits = copy_cdata->_fancy_bits;
193 cdata->_python_tag_data = copy_cdata->_python_tag_data;
194 cdata->inc_py_refs();
195 #endif // HAVE_PYTHON 354 if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
355 const LMatrix4 &mat = attribs._transform->get_mat();
359 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
360 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
361 cdata->_effects = cdata->_effects->xform(mat);
362 cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
364 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
402 if (is_exact_type(get_class_type())) {
435 CPT(TransformState) PandaNode::
436 calc_tight_bounds(
LPoint3 &min_point,
LPoint3 &max_point,
bool &found_any,
437 const TransformState *transform,
Thread *current_thread)
const {
438 CPT(TransformState) next_transform = transform->compose(
get_transform());
440 Children cr = get_children(current_thread);
442 for (
int i = 0; i < num_children; i++) {
443 cr.
get_child(i)->calc_tight_bounds(min_point, max_point,
444 found_any, next_transform,
448 return next_transform;
618 copy_subgraph(
Thread *current_thread)
const {
620 return r_copy_subgraph(inst_map, current_thread);
629 count_num_descendants()
const {
634 for (
int i = 0; i < num_children; ++i) {
636 count += child->count_num_descendants();
655 nassertv(child_node != (
PandaNode *)NULL);
657 if (!verify_child_no_cycles(child_node)) {
665 remove_child(child_node);
669 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
670 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
671 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
674 cdata_child->modify_up()->insert(UpConnection(
this));
676 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
678 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
679 new_connection(
this, child_node, pipeline_stage, current_thread);
681 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
683 force_bounds_stale();
686 child_node->parents_changed();
699 nassertv(pipeline_stage == 0);
701 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
702 PT(
Down) down = cdata->modify_down();
703 nassertv(child_index >= 0 && child_index < (
int)down->size());
706 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
708 PT(
Up) up = cdata_child->modify_up();
710 down->erase(down->begin() + child_index);
711 int num_erased = up->erase(UpConnection(
this));
712 nassertv(num_erased == 1);
714 sever_connection(
this, child_node, pipeline_stage, current_thread);
715 force_bounds_stale(pipeline_stage, current_thread);
718 child_node->parents_changed();
720 child_node->mark_bam_modified();
733 nassertr(child_node != (
PandaNode *)NULL,
false);
740 bool any_removed =
false;
742 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
743 if (stage_remove_child(child_node, pipeline_stage, current_thread)) {
746 sever_connection(
this, child_node, pipeline_stage, current_thread);
747 force_bounds_stale(pipeline_stage, current_thread);
750 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
755 child_node->parents_changed();
773 nassertr(orig_child != (
PandaNode *)NULL,
false);
774 nassertr(new_child != (
PandaNode *)NULL,
false);
776 if (orig_child == new_child) {
781 if (!verify_child_no_cycles(new_child)) {
789 PT(
PandaNode) keep_orig_child = orig_child;
792 bool any_replaced =
false;
794 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
795 if (stage_replace_child(orig_child, new_child, pipeline_stage, current_thread)) {
799 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
803 orig_child->parents_changed();
804 new_child->parents_changed();
828 nassertv(pipeline_stage == 0);
837 remove_child(child_index);
840 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
841 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
843 cdata->modify_stashed()->insert(
DownConnection(child_node, sort));
844 cdata_child->modify_up()->insert(UpConnection(
this));
847 new_connection(
this, child_node, pipeline_stage, current_thread);
848 force_bounds_stale(pipeline_stage, current_thread);
851 child_node->parents_changed();
873 nassertv(pipeline_stage == 0);
882 PT(
PandaNode) child_node = get_stashed(stashed_index);
885 remove_stashed(stashed_index);
889 CDWriter cdata_child(child_node->_cycler);
892 cdata_child->modify_up()->insert(UpConnection(
this));
895 new_connection(
this, child_node, pipeline_stage, current_thread);
897 force_bounds_stale();
899 child_node->parents_changed();
921 nassertv(pipeline_stage == 0);
923 if (!verify_child_no_cycles(child_node)) {
931 remove_child(child_node);
935 CDWriter cdata_child(child_node->_cycler);
937 cdata->modify_stashed()->insert(
DownConnection(child_node, sort));
938 cdata_child->modify_up()->insert(UpConnection(
this));
941 new_connection(
this, child_node, pipeline_stage, current_thread);
945 child_node->parents_changed();
958 nassertv(pipeline_stage == 0);
960 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
961 Down &stashed = *cdata->modify_stashed();
962 nassertv(child_index >= 0 && child_index < (
int)stashed.size());
964 PT(
PandaNode) child_node = stashed[child_index].get_child();
965 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
967 stashed.erase(stashed.begin() + child_index);
968 int num_erased = cdata_child->modify_up()->erase(UpConnection(
this));
969 nassertv(num_erased == 1);
971 sever_connection(
this, child_node, pipeline_stage, current_thread);
972 force_bounds_stale(pipeline_stage, current_thread);
975 child_node->parents_changed();
977 child_node->mark_bam_modified();
992 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
993 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
994 PT(
Down) down = cdata->modify_down();
996 for (di = down->begin(); di != down->end(); ++di) {
998 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
1000 cdata_child->modify_up()->erase(UpConnection(
this));
1002 sever_connection(
this, child_node, pipeline_stage, current_thread);
1003 child_node->parents_changed();
1008 Down &stashed = *cdata->modify_stashed();
1009 for (di = stashed.begin(); di != stashed.end(); ++di) {
1011 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
1013 cdata_child->modify_up()->erase(UpConnection(
this));
1015 sever_connection(
this, child_node, pipeline_stage, current_thread);
1016 child_node->parents_changed();
1021 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1023 force_bounds_stale();
1025 mark_bam_modified();
1039 if (other ==
this) {
1054 for (i = 0; i < num_children; i++) {
1057 add_child(child_node, sort, current_thread);
1060 for (i = 0; i < num_stashed; i++) {
1063 add_stashed(child_node, sort, current_thread);
1077 if (other ==
this) {
1085 for (i = 0; i < num_children; i++) {
1088 add_child(child_node, sort, current_thread);
1091 for (i = 0; i < num_stashed; i++) {
1094 add_stashed(child_node, sort, current_thread);
1110 bool any_changed =
false;
1112 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1113 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1115 CPT(
RenderState) new_state = cdata->_state->set_attrib(attrib,
override);
1116 if (cdata->_state != new_state) {
1117 cdata->_state = new_state;
1118 cdata->set_fancy_bit(FB_state,
true);
1122 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1126 mark_bounds_stale(current_thread);
1128 mark_bam_modified();
1141 clear_attrib(
int slot) {
1142 bool any_changed =
false;
1145 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1146 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1148 CPT(
RenderState) new_state = cdata->_state->remove_attrib(slot);
1149 if (cdata->_state != new_state) {
1150 cdata->_state = new_state;
1151 cdata->set_fancy_bit(FB_state, !new_state->is_empty());
1155 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1160 mark_bounds_stale(current_thread);
1162 mark_bam_modified();
1178 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1179 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1180 cdata->_effects = cdata->_effects->add_effect(effect);
1181 cdata->set_fancy_bit(FB_effects,
true);
1183 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1184 mark_bam_modified();
1196 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1197 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1198 cdata->_effects = cdata->_effects->remove_effect(type);
1199 cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
1201 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1202 mark_bam_modified();
1219 bool any_changed =
false;
1220 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1221 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1222 if (cdata->_state != state) {
1223 cdata->_state = state;
1224 cdata->set_fancy_bit(FB_state, !state->
is_empty());
1228 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1232 mark_bounds_stale(current_thread);
1234 mark_bam_modified();
1250 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1251 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1252 cdata->_effects = effects;
1253 cdata->set_fancy_bit(FB_effects, !effects->
is_empty());
1255 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1256 mark_bam_modified();
1273 bool any_changed =
false;
1274 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1275 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1276 if (cdata->_transform != transform) {
1277 cdata->_transform = transform;
1278 cdata->set_fancy_bit(FB_transform, !transform->is_identity());
1281 if (pipeline_stage == 0) {
1282 if (cdata->_transform != cdata->_prev_transform) {
1283 do_set_dirty_prev_transform();
1288 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1291 mark_bounds_stale(current_thread);
1292 transform_changed();
1293 mark_bam_modified();
1312 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1313 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1314 cdata->_prev_transform = transform;
1315 if (pipeline_stage == 0) {
1316 if (cdata->_transform != cdata->_prev_transform) {
1317 do_set_dirty_prev_transform();
1319 do_clear_dirty_prev_transform();
1323 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1324 mark_bam_modified();
1339 do_clear_dirty_prev_transform();
1344 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1345 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1346 cdata->_prev_transform = cdata->_transform;
1348 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1349 mark_bam_modified();
1365 PStatTimer timer(_reset_prev_pcollector, current_thread);
1369 while (list_node != &_dirty_prev_transforms) {
1371 nassertv(panda_node->_dirty_prev_transform);
1372 panda_node->_dirty_prev_transform =
false;
1374 CDStageWriter cdata(panda_node->_cycler, 0, current_thread);
1375 cdata->_prev_transform = cdata->_transform;
1377 list_node = panda_node->_next;
1379 panda_node->_prev = NULL;
1380 panda_node->_next = NULL;
1385 _dirty_prev_transforms._prev = &_dirty_prev_transforms;
1386 _dirty_prev_transforms._next = &_dirty_prev_transforms;
1406 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1407 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1408 cdata->_tag_data[key] = value;
1409 cdata->set_fancy_bit(FB_tag,
true);
1411 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1412 mark_bam_modified();
1424 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1425 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1426 cdata->_tag_data.erase(key);
1427 cdata->set_fancy_bit(FB_tag, !cdata->_tag_data.empty());
1429 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1430 mark_bam_modified();
1443 if (other ==
this) {
1451 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1452 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
1453 CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread);
1455 TagData::const_iterator ti;
1456 for (ti = cdatar->_tag_data.begin();
1457 ti != cdatar->_tag_data.end();
1459 cdataw->_tag_data[(*ti).first] = (*ti).second;
1461 cdataw->set_fancy_bit(FB_tag, !cdataw->_tag_data.empty());
1464 PythonTagData::const_iterator pti;
1465 for (pti = cdatar->_python_tag_data.begin();
1466 pti != cdatar->_python_tag_data.end();
1468 const string &key = (*pti).first;
1469 PyObject *value = (*pti).second;
1472 pair<PythonTagData::iterator, bool> result;
1473 result = cdataw->_python_tag_data.insert(PythonTagData::value_type(key, value));
1475 if (!result.second) {
1480 PythonTagData::iterator wpti = result.first;
1481 PyObject *old_value = (*wpti).second;
1482 Py_XDECREF(old_value);
1483 (*wpti).second = value;
1486 #endif // HAVE_PYTHON 1488 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1489 mark_bam_modified();
1507 if (!cdata->_tag_data.empty()) {
1508 TagData::const_iterator ti = cdata->_tag_data.begin();
1511 while (ti != cdata->_tag_data.end()) {
1512 out << separator << (*ti).first;
1518 if (!cdata->_python_tag_data.empty()) {
1519 if (!cdata->_tag_data.empty()) {
1522 PythonTagData::const_iterator ti = cdata->_python_tag_data.begin();
1525 while (ti != cdata->_python_tag_data.end()) {
1526 out << separator << (*ti).first;
1530 #endif // HAVE_PYTHON 1546 if (!cdata->_tag_data.empty()) {
1547 TagData::const_iterator ti = cdata->_tag_data.begin();
1548 while (ti != cdata->_tag_data.end()) {
1549 keys.push_back((*ti).first);
1569 CDReader cdata_other(other->_cycler);
1571 TagData::const_iterator ati = cdata->_tag_data.begin();
1572 TagData::const_iterator bti = cdata_other->_tag_data.begin();
1573 while (ati != cdata->_tag_data.end() &&
1574 bti != cdata_other->_tag_data.end()) {
1575 int cmp = strcmp((*ati).first.c_str(), (*bti).first.c_str());
1580 cmp = strcmp((*ati).second.c_str(), (*bti).second.c_str());
1588 if (ati != cdata->_tag_data.end()) {
1592 if (bti != cdata_other->_tag_data.end()) {
1598 PythonTagData::const_iterator api = cdata->_python_tag_data.begin();
1599 PythonTagData::const_iterator bpi = cdata_other->_python_tag_data.begin();
1600 while (api != cdata->_python_tag_data.end() &&
1601 bpi != cdata_other->_python_tag_data.end()) {
1602 int cmp = strcmp((*api).first.c_str(), (*bpi).first.c_str());
1607 #if PY_MAJOR_VERSION >= 3 1608 if (PyObject_RichCompareBool((*api).second, (*bpi).second, Py_LT) == 1) {
1610 }
else if (PyObject_RichCompareBool((*api).second, (*bpi).second, Py_GT) == 1) {
1612 }
else if (PyObject_RichCompareBool((*api).second, (*bpi).second, Py_EQ) == 1) {
1616 if (PyObject_Cmp((*api).second, (*bpi).second, &cmp) == -1) {
1619 if ((*api).second != (*bpi).second) {
1620 cmp = (*api).second < (*bpi).second ? -1 : 1;
1632 if (api != cdata->_python_tag_data.end()) {
1636 if (bpi != cdata_other->_python_tag_data.end()) {
1640 #endif // HAVE_PYTHON 1656 if (other ==
this) {
1664 bool any_transform_changed =
false;
1665 bool any_state_changed =
false;
1666 bool any_draw_mask_changed =
false;
1668 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1669 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
1670 CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread);
1672 if (cdataw->_transform != cdatar->_transform) {
1673 any_transform_changed =
true;
1675 if (cdataw->_state != cdatar->_state) {
1676 any_state_changed =
true;
1678 if (cdataw->_draw_control_mask != cdatar->_draw_control_mask ||
1679 cdataw->_draw_show_mask != cdatar->_draw_show_mask) {
1680 any_draw_mask_changed =
true;
1683 cdataw->_transform = cdatar->_transform;
1684 cdataw->_prev_transform = cdatar->_prev_transform;
1685 cdataw->_state = cdatar->_state;
1686 cdataw->_effects = cdatar->_effects;
1687 cdataw->_draw_control_mask = cdatar->_draw_control_mask;
1688 cdataw->_draw_show_mask = cdatar->_draw_show_mask;
1693 cdataw->_into_collide_mask |= cdatar->_into_collide_mask;
1695 TagData::const_iterator ti;
1696 for (ti = cdatar->_tag_data.begin();
1697 ti != cdatar->_tag_data.end();
1699 cdataw->_tag_data[(*ti).first] = (*ti).second;
1703 PythonTagData::const_iterator pti;
1704 for (pti = cdatar->_python_tag_data.begin();
1705 pti != cdatar->_python_tag_data.end();
1707 const string &key = (*pti).first;
1708 PyObject *value = (*pti).second;
1711 pair<PythonTagData::iterator, bool> result;
1712 result = cdataw->_python_tag_data.insert(PythonTagData::value_type(key, value));
1714 if (!result.second) {
1719 PythonTagData::iterator wpti = result.first;
1720 PyObject *old_value = (*wpti).second;
1721 Py_XDECREF(old_value);
1722 (*wpti).second = value;
1725 #endif // HAVE_PYTHON 1727 static const int change_bits = (FB_transform | FB_state | FB_effects |
1728 FB_tag | FB_draw_mask);
1729 cdataw->_fancy_bits =
1730 (cdataw->_fancy_bits & ~change_bits) |
1731 (cdatar->_fancy_bits & change_bits);
1733 if (pipeline_stage == 0) {
1734 if (cdataw->_transform != cdataw->_prev_transform) {
1735 do_set_dirty_prev_transform();
1739 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1741 if (any_transform_changed || any_state_changed || any_draw_mask_changed) {
1742 mark_bounds_stale(current_thread);
1744 if (any_transform_changed) {
1745 transform_changed();
1747 if (any_state_changed) {
1750 if (any_draw_mask_changed) {
1751 draw_mask_changed();
1753 mark_bam_modified();
1780 if (other ==
this) {
1790 copy_all_properties(other);
1797 for (pi = other->_paths.begin(); pi != other->_paths.end(); ++pi) {
1798 (*pi)->_node =
this;
1801 other->_paths.clear();
1805 steal_children(other);
1845 _unexpected_change_flags |= flags;
1866 return _unexpected_change_flags & flags;
1889 _unexpected_change_flags &= ~flags;
1933 bool any_changed =
false;
1936 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1937 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1939 DrawMask draw_control_mask = (cdata->_draw_control_mask | show_mask | hide_mask) & ~clear_mask;
1940 DrawMask draw_show_mask = (cdata->_draw_show_mask | show_mask) & ~hide_mask;
1942 draw_show_mask |= ~draw_control_mask;
1944 if (cdata->_draw_control_mask != draw_control_mask ||
1945 cdata->_draw_show_mask != draw_show_mask) {
1946 cdata->_draw_control_mask = draw_control_mask;
1947 cdata->_draw_show_mask = draw_show_mask;
1950 cdata->set_fancy_bit(FB_draw_mask, !draw_control_mask.
is_zero());
1952 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1955 mark_bounds_stale(current_thread);
1956 draw_mask_changed();
1957 mark_bam_modified();
1978 if (cdata->_last_update != cdata->_next_update) {
1982 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
1983 return cdataw->_net_draw_control_mask;
1985 return cdata->_net_draw_control_mask;
2009 if (cdata->_last_update != cdata->_next_update) {
2013 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
2014 return cdataw->_net_draw_show_mask;
2016 return cdata->_net_draw_show_mask;
2038 mask &= get_legal_collide_mask();
2040 bool any_changed =
false;
2042 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2043 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2044 if (cdata->_into_collide_mask != mask) {
2045 cdata->_into_collide_mask = mask;
2049 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2052 mark_bounds_stale(current_thread);
2053 mark_bam_modified();
2083 if (cdata->_last_update != cdata->_next_update) {
2087 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
2088 return cdataw->_net_collide_mask;
2090 return cdata->_net_collide_mask;
2101 get_off_clip_planes(
Thread *current_thread)
const {
2104 if (cdata->_last_update != cdata->_next_update) {
2108 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
2109 return cdataw->_off_clip_planes;
2111 return cdata->_off_clip_planes;
2133 r_prepare_scene(gsg, node_state, transformer, current_thread);
2149 if (_scene_root_func != (SceneRootFunc *)NULL) {
2150 return (*_scene_root_func)(
this);
2167 if (is_scene_root()) {
2171 Parents parents = get_parents();
2189 output(ostream &out)
const {
2190 out << get_type() <<
" " << get_name();
2199 write(ostream &out,
int indent_level)
const {
2200 indent(out, indent_level) << *
this;
2203 list_tags(out,
" ");
2207 if (!transform->is_identity()) {
2208 out <<
" " << *transform;
2211 if (!state->is_empty()) {
2212 out <<
" " << *state;
2215 if (!effects->is_empty()) {
2216 out <<
" " << *effects;
2218 DrawMask draw_control_mask = get_draw_control_mask();
2219 if (!draw_control_mask.
is_zero()) {
2220 DrawMask draw_show_mask = get_draw_show_mask();
2221 if (!(draw_control_mask & _overall_bit).is_zero()) {
2222 if (!(draw_show_mask & _overall_bit).is_zero()) {
2223 out <<
" (show_through)";
2228 if (!(draw_control_mask & ~_overall_bit).is_zero()) {
2229 draw_control_mask &= ~_overall_bit;
2230 if (!(draw_show_mask & draw_control_mask).is_zero()) {
2231 out <<
" (per-camera show_through)";
2233 if (!(~draw_show_mask & draw_control_mask).is_zero()) {
2234 out <<
" (per-camera hidden)";
2263 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2264 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2265 cdata->_bounds_type = bounds_type;
2266 mark_bounds_stale(pipeline_stage, current_thread);
2271 mark_internal_bounds_stale(pipeline_stage, current_thread);
2272 mark_bam_modified();
2274 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2286 return cdata->_bounds_type;
2306 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2307 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2308 if (volume == NULL) {
2309 cdata->_user_bounds = NULL;
2311 cdata->_user_bounds = volume->make_copy();
2313 mark_bounds_stale(pipeline_stage, current_thread);
2314 mark_bam_modified();
2316 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2326 pgraph_cat.warning()
2327 <<
"Deprecated PandaNode::set_bound() called. Use set_bounds() instead.\n";
2340 get_bounds(
Thread *current_thread)
const {
2343 if (cdata->_last_bounds_update != cdata->_next_update) {
2349 ((
PandaNode *)
this)->update_cached(
true, pipeline_stage, cdata);
2350 result = cdataw->_external_bounds;
2354 return cdata->_external_bounds;
2377 if (cdata->_last_bounds_update != cdata->_next_update) {
2383 ((
PandaNode *)
this)->update_cached(
true, pipeline_stage, cdata);
2384 result = cdataw->_external_bounds;
2385 seq = cdataw->_last_bounds_update;
2389 seq = cdata->_last_bounds_update;
2390 return cdata->_external_bounds;
2407 get_nested_vertices(
Thread *current_thread)
const {
2410 if (cdata->_last_bounds_update != cdata->_next_update) {
2416 ((
PandaNode *)
this)->update_cached(
true, pipeline_stage, cdata);
2417 result = cdataw->_nested_vertices;
2421 return cdata->_nested_vertices;
2443 mark_bounds_stale(
Thread *current_thread)
const {
2444 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2445 mark_bounds_stale(pipeline_stage, current_thread);
2447 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2467 mark_internal_bounds_stale(
Thread *current_thread) {
2468 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2469 mark_internal_bounds_stale(pipeline_stage, current_thread);
2471 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2558 decode_from_bam_stream(
const string &data,
BamReader *reader) {
2577 get_internal_bounds(
int pipeline_stage,
Thread *current_thread)
const {
2581 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2583 return cdata->_user_bounds;
2586 if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) {
2587 return cdata->_internal_bounds;
2590 mark = cdata->_internal_bounds_mark;
2596 int internal_vertices;
2597 compute_internal_bounds(internal_bounds, internal_vertices,
2598 pipeline_stage, current_thread);
2599 nassertr(!internal_bounds.is_null(), NULL);
2603 if (cdataw->_internal_bounds_mark == mark) {
2604 cdataw->_internal_bounds_computed = mark;
2605 cdataw->_internal_bounds = internal_bounds;
2606 cdataw->_internal_vertices = internal_vertices;
2607 ((
PandaNode *)
this)->mark_bam_modified();
2608 return cdataw->_internal_bounds;
2628 get_internal_vertices(
int pipeline_stage,
Thread *current_thread)
const {
2632 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2633 if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) {
2634 return cdata->_internal_vertices;
2637 mark = cdata->_internal_bounds_mark;
2643 int internal_vertices;
2644 compute_internal_bounds(internal_bounds, internal_vertices,
2645 pipeline_stage, current_thread);
2646 nassertr(!internal_bounds.is_null(), 0);
2650 if (cdataw->_internal_bounds_mark == mark) {
2651 cdataw->_internal_bounds_computed = mark;
2652 cdataw->_internal_bounds = internal_bounds;
2653 cdataw->_internal_vertices = internal_vertices;
2654 ((
PandaNode *)
this)->mark_bam_modified();
2655 return cdataw->_internal_vertices;
2676 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2677 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
2678 cdataw->_internal_bounds = volume;
2679 cdataw->_internal_bounds_computed = cdataw->_internal_bounds_mark;
2681 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2682 mark_bounds_stale(current_thread);
2683 mark_bam_modified();
2698 force_bounds_stale(
Thread *current_thread) {
2699 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2700 force_bounds_stale(pipeline_stage, current_thread);
2702 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2713 force_bounds_stale(
int pipeline_stage,
Thread *current_thread) {
2715 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2716 ++cdata->_next_update;
2717 mark_bam_modified();
2729 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2733 for (
int i = 0; i < num_parents; ++i) {
2735 parent->mark_bounds_stale(pipeline_stage, current_thread);
2746 r_mark_geom_bounds_stale(
Thread *current_thread) {
2747 Children children = get_children(current_thread);
2752 child->r_mark_geom_bounds_stale(current_thread);
2755 Stashed stashed = get_stashed(current_thread);
2758 child->r_mark_geom_bounds_stale(current_thread);
2772 int &internal_vertices,
2774 Thread *current_thread)
const {
2776 internal_vertices = 0;
2790 nassertv((_unexpected_change_flags & UC_parents) == 0);
2803 children_changed() {
2804 nassertv((_unexpected_change_flags & UC_children) == 0);
2815 transform_changed() {
2816 nassertv((_unexpected_change_flags & UC_transform) == 0);
2828 nassertv((_unexpected_change_flags & UC_state) == 0);
2839 draw_mask_changed() {
2840 nassertv((_unexpected_change_flags & UC_draw_mask) == 0);
2859 nassertr(copy != (
PandaNode *)NULL, NULL);
2860 if (copy->get_type() != get_type()) {
2861 pgraph_cat.warning()
2862 <<
"Don't know how to copy nodes of type " << get_type() <<
"\n";
2864 if (no_unsupported_copy) {
2865 nassertr(
false, NULL);
2869 copy->r_copy_children(
this, inst_map, current_thread);
2890 Thread *current_thread) {
2891 CDReader from_cdata(from->_cycler, current_thread);
2892 CPT(
Down) from_down = from_cdata->get_down();
2893 Down::const_iterator di;
2894 for (di = from_down->begin(); di != from_down->end(); ++di) {
2895 int sort = (*di).get_sort();
2903 InstanceMap::const_iterator ci;
2904 ci = inst_map.find(source_child);
2905 if (ci != inst_map.end()) {
2906 dest_child = (*ci).second;
2908 dest_child = source_child->r_copy_subgraph(inst_map, current_thread);
2909 inst_map[source_child] = dest_child;
2912 quick_add_new_child(dest_child, sort, current_thread);
2927 Children children = get_children(current_thread);
2933 CPT(
RenderState) child_state = node_state->compose(child->get_state());
2934 child->
r_prepare_scene(gsg, child_state, transformer, current_thread);
2937 Stashed stashed = get_stashed(current_thread);
2940 CPT(
RenderState) child_state = node_state->compose(child->get_state());
2941 child->
r_prepare_scene(gsg, child_state, transformer, current_thread);
2954 set_cull_callback() {
2956 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2957 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2958 cdata->set_fancy_bit(FB_cull_callback,
true);
2960 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2961 mark_bam_modified();
2970 disable_cull_callback() {
2972 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2973 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2974 cdata->set_fancy_bit(FB_cull_callback,
false);
2976 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2977 mark_bam_modified();
2987 stage_remove_child(
PandaNode *child_node,
int pipeline_stage,
2988 Thread *current_thread) {
2989 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2993 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
2995 int parent_index = child_node->do_find_parent(
this, cdata_child);
2996 if (parent_index < 0) {
3001 PT(
Down) down = cdata->modify_down();
3002 int child_index = do_find_child(child_node, down);
3003 if (child_index >= 0) {
3005 down->erase(down->begin() + child_index);
3006 int num_erased = cdata_child->modify_up()->erase(UpConnection(
this));
3007 nassertr(num_erased == 1,
false);
3011 PT(
Down) stashed = cdata->modify_stashed();
3012 int stashed_index = do_find_child(child_node, stashed);
3013 if (stashed_index >= 0) {
3015 stashed->erase(stashed->begin() + stashed_index);
3016 int num_erased = cdata_child->modify_up()->erase(UpConnection(
this));
3017 nassertr(num_erased == 1,
false);
3024 nassertr(
false,
false);
3036 int pipeline_stage,
Thread *current_thread) {
3038 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
3039 CDStageWriter cdata_orig_child(orig_child->_cycler, pipeline_stage, current_thread);
3040 CDStageWriter cdata_new_child(new_child->_cycler, pipeline_stage, current_thread);
3044 int parent_index = orig_child->do_find_parent(
this, cdata_orig_child);
3045 if (parent_index < 0) {
3050 if (orig_child == new_child) {
3056 PT(
PandaNode) keep_orig_child = orig_child;
3059 if (stage_remove_child(new_child, pipeline_stage, current_thread)) {
3060 sever_connection(
this, new_child, pipeline_stage, current_thread);
3063 PT(
Down) down = cdata->modify_down();
3064 int child_index = do_find_child(orig_child, down);
3065 if (child_index >= 0) {
3068 nassertr(dc.get_child() == orig_child,
false);
3072 PT(
Down) stashed = cdata->modify_stashed();
3073 int stashed_index = do_find_child(orig_child, stashed);
3074 if (stashed_index >= 0) {
3077 nassertr(dc.get_child() == orig_child,
false);
3084 nassertr(
false,
false);
3090 cdata_new_child->modify_up()->insert(UpConnection(
this));
3091 int num_erased = cdata_orig_child->modify_up()->erase(UpConnection(
this));
3092 nassertr(num_erased == 1,
false);
3095 sever_connection(
this, orig_child, pipeline_stage, current_thread);
3096 new_connection(
this, new_child, pipeline_stage, current_thread);
3098 force_bounds_stale(pipeline_stage, current_thread);
3099 orig_child->parents_changed();
3100 new_child->parents_changed();
3101 mark_bam_modified();
3119 quick_add_new_child(
PandaNode *child_node,
int sort,
Thread *current_thread) {
3122 OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
3123 CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
3124 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
3127 cdata_child->modify_up()->insert(UpConnection(
this));
3129 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
3141 strm <<
"Detected attempt to create a cycle in the scene graph: " 3143 nassert_raise(strm.str());
3159 Parents parents = get_parents();
3162 if (parent->find_node_above(node)) {
3183 int pipeline_stage,
Thread *current_thread) {
3189 pipeline_stage, current_thread);
3191 child_node->_paths.insert(child);
3197 PT(
NodePathComponent) child = get_component(parent, child_node, pipeline_stage, current_thread);
3202 child = get_top_component(child_node,
true, pipeline_stage, current_thread);
3205 reparent(parent, child, sort,
false, pipeline_stage, current_thread);
3222 for (
int pipeline_stage_i = pipeline_stage;
3223 pipeline_stage_i >= 0;
3224 --pipeline_stage_i) {
3225 detach_one_stage(child, pipeline_stage_i, current_thread);
3228 child->
get_node()->parents_changed();
3242 Thread *current_thread) {
3244 if (child->
is_top_node(pipeline_stage, current_thread)) {
3251 CDStageWriter cdata_parent(parent_node->_cycler, pipeline_stage, current_thread);
3252 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
3253 int parent_index = child_node->do_find_parent(parent_node, cdata_child);
3254 if (parent_index >= 0) {
3259 int num_erased = cdata_child->modify_up()->erase(UpConnection(parent_node));
3260 nassertv(num_erased == 1);
3267 PT(
Down) down = cdata_parent->modify_down();
3268 for (di = down->begin(); di != down->end(); ++di) {
3269 if ((*di).get_child() == child_node) {
3276 PT(
Down) stashed = cdata_parent->modify_stashed();
3277 for (di = stashed->begin(); di != stashed->end(); ++di) {
3278 if ((*di).get_child() == child_node) {
3289 sever_connection(parent_node, child_node, pipeline_stage, current_thread);
3291 parent_node->force_bounds_stale(pipeline_stage, current_thread);
3292 parent_node->children_changed();
3310 bool as_stashed,
int pipeline_stage,
Thread *current_thread) {
3311 bool any_ok =
false;
3320 for (
int pipeline_stage_i = pipeline_stage;
3321 pipeline_stage_i >= 0;
3322 --pipeline_stage_i) {
3323 if (reparent_one_stage(new_parent, child, sort, as_stashed,
3324 pipeline_stage_i, current_thread)) {
3330 new_parent->
get_node()->children_changed();
3333 child->
get_node()->parents_changed();
3354 int sort,
bool as_stashed,
int pipeline_stage,
3355 Thread *current_thread) {
3362 if (!child->
is_top_node(pipeline_stage, current_thread)) {
3363 detach(child, pipeline_stage, current_thread);
3371 CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread);
3372 int parent_index = child_node->do_find_parent(parent_node, cdata_child);
3374 if (parent_index >= 0) {
3381 child->set_next(new_parent, pipeline_stage, current_thread);
3385 CDStageWriter cdata_parent(parent_node->_cycler, pipeline_stage, current_thread);
3386 CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
3389 cdata_parent->modify_stashed()->insert(
DownConnection(child_node, sort));
3391 cdata_parent->modify_down()->insert(
DownConnection(child_node, sort));
3393 cdata_child->modify_up()->insert(UpConnection(parent_node));
3399 nassertr(child_node->_paths.find(child) != child_node->_paths.end(),
false);
3404 child_node->fix_path_lengths(pipeline_stage, current_thread);
3405 parent_node->force_bounds_stale(pipeline_stage, current_thread);
3420 int pipeline_stage,
Thread *current_thread) {
3429 Paths::const_iterator pi;
3430 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3431 if ((*pi)->get_next(pipeline_stage, current_thread) == parent) {
3439 CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread);
3440 int parent_index = child_node->do_find_parent(parent_node, cdata_child);
3442 if (parent_index >= 0) {
3446 child_node->_paths.insert(child);
3469 get_top_component(
PandaNode *child_node,
bool force,
int pipeline_stage,
3470 Thread *current_thread) {
3475 Paths::const_iterator pi;
3476 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3477 if ((*pi)->is_top_node(pipeline_stage, current_thread)) {
3493 pipeline_stage, current_thread);
3494 child_node->_paths.insert(child);
3511 get_generic_component(
bool accept_ambiguity,
int pipeline_stage,
3512 Thread *current_thread) {
3513 bool ambiguity_detected =
false;
3515 r_get_generic_component(accept_ambiguity, ambiguity_detected,
3516 pipeline_stage, current_thread);
3518 if (!accept_ambiguity && ambiguity_detected) {
3519 pgraph_cat.warning()
3520 <<
"Chose: " << *result <<
"\n";
3521 nassertr(!unambiguous_graph, result);
3536 r_get_generic_component(
bool accept_ambiguity,
bool &ambiguity_detected,
3537 int pipeline_stage,
Thread *current_thread) {
3541 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
3543 int num_parents = cdata->get_up()->size();
3544 if (num_parents == 0) {
3546 return get_top_component(
this,
true, pipeline_stage, current_thread);
3550 if (num_parents == 1) {
3553 get_parent(0)->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread);
3554 return get_component(parent,
this, pipeline_stage, current_thread);
3558 if (!accept_ambiguity) {
3559 pgraph_cat.warning()
3560 << *
this <<
" has " << num_parents
3561 <<
" parents; choosing arbitrary path to root.\n";
3563 ambiguity_detected =
true;
3564 CPT(
Up) up = cdata->get_up();
3570 parent_node->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread);
3571 return get_component(parent,
this, pipeline_stage, current_thread);
3584 int num_erased = _paths.erase(component);
3585 nassertv(num_erased == 1);
3608 int pipeline_stage,
Thread *current_thread) {
3612 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3613 if (!(*pi)->is_top_node(pipeline_stage, current_thread) &&
3614 (*pi)->get_next(pipeline_stage, current_thread)->get_node() == parent_node) {
3616 (*pi)->set_top_node(pipeline_stage, current_thread);
3620 child_node->fix_path_lengths(pipeline_stage, current_thread);
3641 int pipeline_stage,
Thread *current_thread) {
3645 for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3646 if ((*pi)->is_top_node(pipeline_stage, current_thread)) {
3647 (*pi)->set_next(parent_node->get_generic_component(
false, pipeline_stage, current_thread), pipeline_stage, current_thread);
3651 child_node->fix_path_lengths(pipeline_stage, current_thread);
3667 fix_path_lengths(
int pipeline_stage,
Thread *current_thread) {
3670 bool any_wrong =
false;
3672 Paths::const_iterator pi;
3673 for (pi = _paths.begin(); pi != _paths.end(); ++pi) {
3674 if ((*pi)->fix_length(pipeline_stage, current_thread)) {
3686 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
3693 for (i = 0; i < num_children; ++i) {
3695 child_node->fix_path_lengths(pipeline_stage, current_thread);
3698 for (i = 0; i < num_stashed; ++i) {
3700 child_node->fix_path_lengths(pipeline_stage, current_thread);
3711 r_list_descendants(ostream &out,
int indent_level)
const {
3712 write(out, indent_level);
3714 Children children = get_children();
3717 for (
int i = 0; i < num_children; ++i) {
3719 child->r_list_descendants(out, indent_level + 2);
3724 if (num_stashed != 0) {
3725 indent(out, indent_level) <<
"(" << num_stashed <<
" stashed)\n";
3736 nassertr(node != (
PandaNode *)NULL, -1);
3740 Down::const_iterator di;
3741 for (di = down->begin(); di != down->end(); ++di) {
3742 if ((*di).get_child() == node) {
3743 return di - down->begin();
3768 if (drawmask_cat.is_debug()) {
3769 drawmask_cat.debug(
false)
3770 << *
this <<
"::update_cached() {\n";
3776 UpdateSeq last_update = cdata->_last_update;
3777 UpdateSeq next_update = cdata->_next_update;
3778 UpdateSeq last_bounds_update = cdata->_last_bounds_update;
3779 nassertr(last_update != next_update ||
3780 (update_bounds && last_bounds_update != next_update),
3784 CollideMask net_collide_mask = cdata->_into_collide_mask;
3785 DrawMask net_draw_control_mask, net_draw_show_mask;
3786 bool renderable = is_renderable();
3791 net_draw_control_mask = cdata->_draw_control_mask;
3792 net_draw_show_mask = cdata->_draw_show_mask;
3795 if (drawmask_cat.is_debug()) {
3796 drawmask_cat.debug(
false)
3797 <<
"net_draw_control_mask = " << net_draw_control_mask
3798 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3801 CPT(
RenderAttrib) off_clip_planes = cdata->_state->get_attrib(ClipPlaneAttrib::get_class_slot());
3803 off_clip_planes = ClipPlaneAttrib::make();
3809 int num_vertices = cdata->_internal_vertices;
3813 _cycler.release_read_stage(pipeline_stage, cdata.
take_pointer());
3823 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 3825 if (update_bounds) {
3826 child_volumes_ref.reserve(num_children + 1);
3829 int child_volumes_i = 0;
3831 bool all_box =
true;
3834 if (update_bounds) {
3836 internal_bounds = get_internal_bounds(pipeline_stage, current_thread);
3838 if (!internal_bounds->
is_empty()) {
3839 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 3840 child_volumes_ref.push_back(internal_bounds);
3842 nassertr(child_volumes_i < num_children + 1,
CDStageWriter(_cycler, pipeline_stage, cdata));
3843 child_volumes[child_volumes_i++] = internal_bounds;
3852 for (
int i = 0; i < num_children; ++i) {
3859 UpdateSeq last_child_update = update_bounds
3860 ? child_cdata->_last_bounds_update
3861 : child_cdata->_last_update;
3863 if (last_child_update != child_cdata->_next_update) {
3865 CDStageWriter child_cdataw = child->update_cached(update_bounds, pipeline_stage, child_cdata);
3867 net_collide_mask |= child_cdataw->_net_collide_mask;
3869 if (drawmask_cat.is_debug()) {
3870 drawmask_cat.debug(
false)
3871 <<
"\nchild update " << *child <<
":\n";
3874 DrawMask child_control_mask = child_cdataw->_net_draw_control_mask;
3875 DrawMask child_show_mask = child_cdataw->_net_draw_show_mask;
3876 if (!(child_control_mask | child_show_mask).is_zero()) {
3913 DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask);
3914 exception_mask &= (net_draw_control_mask ^ net_draw_show_mask);
3916 if (drawmask_cat.is_debug()) {
3917 drawmask_cat.debug(
false)
3918 <<
"exception_mask = " << exception_mask <<
"\n";
3922 net_draw_control_mask |= child_control_mask;
3923 net_draw_show_mask |= child_show_mask;
3925 net_draw_control_mask &= ~exception_mask;
3926 net_draw_show_mask |= exception_mask;
3929 if (drawmask_cat.is_debug()) {
3930 drawmask_cat.debug(
false)
3931 <<
"child_control_mask = " << child_control_mask
3932 <<
"\nchild_show_mask = " << child_show_mask
3933 <<
"\nnet_draw_control_mask = " << net_draw_control_mask
3934 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3938 off_clip_planes = orig_cp->compose_off(child_cdataw->_off_clip_planes);
3940 if (update_bounds) {
3941 if (!child_cdataw->_external_bounds->is_empty()) {
3942 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 3943 child_volumes_ref.push_back(child_cdataw->_external_bounds);
3945 nassertr(child_volumes_i < num_children + 1,
CDStageWriter(_cycler, pipeline_stage, cdata));
3946 child_volumes[child_volumes_i++] = child_cdataw->_external_bounds;
3947 if (child_cdataw->_external_bounds->as_bounding_box() == NULL) {
3951 num_vertices += child_cdataw->_nested_vertices;
3956 net_collide_mask |= child_cdata->_net_collide_mask;
3959 if (drawmask_cat.is_debug()) {
3960 drawmask_cat.debug(
false)
3961 <<
"\nchild fresh " << *child <<
":\n";
3963 DrawMask child_control_mask = child_cdata->_net_draw_control_mask;
3964 DrawMask child_show_mask = child_cdata->_net_draw_show_mask;
3965 if (!(child_control_mask | child_show_mask).is_zero()) {
3968 DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask);
3969 exception_mask &= (net_draw_control_mask ^ net_draw_show_mask);
3971 if (drawmask_cat.is_debug()) {
3972 drawmask_cat.debug(
false)
3973 <<
"exception_mask = " << exception_mask <<
"\n";
3977 net_draw_control_mask |= child_control_mask;
3978 net_draw_show_mask |= child_show_mask;
3980 net_draw_control_mask &= ~exception_mask;
3981 net_draw_show_mask |= exception_mask;
3984 if (drawmask_cat.is_debug()) {
3985 drawmask_cat.debug(
false)
3986 <<
"child_control_mask = " << child_control_mask
3987 <<
"\nchild_show_mask = " << child_show_mask
3988 <<
"\nnet_draw_control_mask = " << net_draw_control_mask
3989 <<
"\nnet_draw_show_mask = " << net_draw_show_mask
3993 off_clip_planes = orig_cp->compose_off(child_cdata->_off_clip_planes);
3995 if (update_bounds) {
3996 if (!child_cdata->_external_bounds->is_empty()) {
3997 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 3998 child_volumes_ref.push_back(child_cdata->_external_bounds);
4000 nassertr(child_volumes_i < num_children + 1,
CDStageWriter(_cycler, pipeline_stage, cdata));
4001 child_volumes[child_volumes_i++] = child_cdata->_external_bounds;
4002 if (child_cdata->_external_bounds->as_bounding_box() == NULL) {
4006 num_vertices += child_cdata->_nested_vertices;
4013 CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
4014 if (last_update == cdataw->_last_update &&
4015 next_update == cdataw->_next_update) {
4018 cdataw->_net_collide_mask = net_collide_mask;
4023 DrawMask draw_control_mask = cdataw->_draw_control_mask;
4024 DrawMask draw_show_mask = cdataw->_draw_show_mask;
4026 DrawMask show_through_mask = net_draw_control_mask & net_draw_show_mask;
4028 net_draw_control_mask |= draw_control_mask;
4029 net_draw_show_mask = (net_draw_show_mask & ~draw_control_mask) | (draw_show_mask & draw_control_mask);
4031 net_draw_show_mask |= show_through_mask;
4035 cdataw->_net_draw_control_mask = net_draw_control_mask;
4036 cdataw->_net_draw_show_mask = net_draw_show_mask | ~net_draw_control_mask;
4037 if (drawmask_cat.is_debug()) {
4038 drawmask_cat.debug(
false)
4039 <<
"renderable, set mask " << cdataw->_net_draw_show_mask <<
"\n";
4046 cdataw->_net_draw_control_mask = net_draw_control_mask;
4047 cdataw->_net_draw_show_mask = net_draw_show_mask;
4048 if (drawmask_cat.is_debug()) {
4049 drawmask_cat.debug(
false)
4050 <<
"not renderable, set mask " << cdataw->_net_draw_show_mask <<
"\n";
4054 cdataw->_off_clip_planes = off_clip_planes;
4056 if (update_bounds) {
4057 cdataw->_nested_vertices = num_vertices;
4059 CPT(TransformState) transform =
get_transform(current_thread);
4062 BoundingVolume::BoundsType btype = cdataw->_bounds_type;
4063 if (btype == BoundingVolume::BT_default) {
4064 btype = bounds_type;
4067 if (btype == BoundingVolume::BT_box ||
4068 (btype != BoundingVolume::BT_sphere && all_box && transform->is_identity())) {
4079 if (child_volumes_i > 0) {
4081 const BoundingVolume **child_end = child_begin + child_volumes_i;
4087 if (!transform->is_identity()) {
4088 gbv->xform(transform->get_mat());
4091 cdataw->_external_bounds = gbv;
4092 cdataw->_last_bounds_update = next_update;
4095 cdataw->_last_update = next_update;
4097 if (drawmask_cat.is_debug()) {
4098 drawmask_cat.debug(
false)
4099 <<
"} " << *
this <<
"::update_cached();\n";
4102 nassertr(cdataw->_last_update == cdataw->_next_update, cdataw);
4106 mark_bam_modified();
4110 if (cdataw->_last_update == cdataw->_next_update &&
4111 (!update_bounds || cdataw->_last_bounds_update == cdataw->_next_update)) {
4121 if (cdata->_last_update == cdata->_next_update &&
4122 (!update_bounds || cdata->_last_bounds_update == cdata->_next_update)) {
4143 _scene_root_func = func;
4181 cdata->update_bam_nested(manager);
4219 parse_params(params, scan, manager);
4220 node->fillin(scan, manager);
4264 _state(RenderState::make_empty()),
4265 _transform(TransformState::make_identity()),
4266 _prev_transform(TransformState::make_identity()),
4268 _effects(RenderEffects::make_empty()),
4272 _bounds_type(BoundingVolume::BT_default),
4274 _final_bounds(
false),
4294 CData(
const PandaNode::CData ©) :
4296 _state(copy._state),
4297 _transform(copy._transform),
4298 _prev_transform(copy._prev_transform),
4300 _effects(copy._effects),
4301 _tag_data(copy._tag_data),
4303 _draw_control_mask(copy._draw_control_mask),
4304 _draw_show_mask(copy._draw_show_mask),
4305 _into_collide_mask(copy._into_collide_mask),
4306 _bounds_type(copy._bounds_type),
4307 _user_bounds(copy._user_bounds),
4308 _final_bounds(copy._final_bounds),
4309 _fancy_bits(copy._fancy_bits),
4311 _net_collide_mask(copy._net_collide_mask),
4312 _net_draw_control_mask(copy._net_draw_control_mask),
4313 _net_draw_show_mask(copy._net_draw_show_mask),
4314 _off_clip_planes(copy._off_clip_planes),
4315 _nested_vertices(copy._nested_vertices),
4316 _external_bounds(copy._external_bounds),
4317 _last_update(copy._last_update),
4318 _next_update(copy._next_update),
4319 _last_bounds_update(copy._last_bounds_update),
4322 _stashed(copy._stashed),
4332 _python_tag_data = copy._python_tag_data;
4334 #endif // HAVE_PYTHON 4347 #endif // HAVE_PYTHON 4357 return new CData(*
this);
4366 void PandaNode::CData::
4374 dg.
add_uint32(_draw_control_mask.get_word());
4376 dg.
add_uint32(_into_collide_mask.get_word());
4380 TagData::const_iterator ti;
4381 for (ti = _tag_data.begin(); ti != _tag_data.end(); ++ti) {
4387 write_up_list(*get_up(), manager, dg);
4388 write_down_list(*get_down(), manager, dg);
4389 write_down_list(*get_stashed(), manager, dg);
4399 void PandaNode::CData::
4400 update_bam_nested(
BamWriter *manager)
const {
4407 update_up_list(*get_up(), manager);
4408 update_down_list(*get_down(), manager);
4409 update_down_list(*get_stashed(), manager);
4419 int PandaNode::CData::
4425 _transform = DCAST(TransformState, p_list[pi++]);
4426 _prev_transform = _transform;
4437 manager->
finalize_now((TransformState *)_transform.p());
4457 pi += complete_up_list(*modify_up(),
"up", p_list + pi, manager);
4458 pi += complete_down_list(*modify_down(),
"down", p_list + pi, manager);
4459 pi += complete_down_list(*modify_stashed(),
"stashed", p_list + pi, manager);
4463 set_fancy_bit(FB_transform, !_transform->is_identity());
4464 set_fancy_bit(FB_state, !_state->is_empty());
4465 set_fancy_bit(FB_effects, !_effects->is_empty());
4466 set_fancy_bit(FB_tag, !_tag_data.empty());
4481 void PandaNode::CData::
4497 _draw_control_mask = _overall_bit;
4498 _draw_show_mask = ~_overall_bit;
4507 draw_mask &= ~_overall_bit;
4508 _draw_control_mask = ~draw_mask;
4509 _draw_show_mask = draw_mask;
4517 _into_collide_mask.set_word(scan.
get_uint32());
4519 _bounds_type = BoundingVolume::BT_default;
4521 _bounds_type = (BoundingVolume::BoundsType)scan.
get_uint8();
4526 for (
int i = 0; i < num_tags; i++) {
4529 _tag_data[key] = value;
4533 fillin_up_list(*modify_up(),
"up", scan, manager);
4534 fillin_down_list(*modify_down(),
"down", scan, manager);
4535 fillin_down_list(*modify_stashed(),
"stashed", scan, manager);
4545 void PandaNode::CData::
4547 if (!_python_tag_data.empty()) {
4548 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 4551 PyGILState_STATE gstate;
4552 gstate = PyGILState_Ensure();
4554 PythonTagData::const_iterator ti;
4555 for (ti = _python_tag_data.begin();
4556 ti != _python_tag_data.end();
4558 PyObject *value = (*ti).second;
4561 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 4562 PyGILState_Release(gstate);
4566 #endif // HAVE_PYTHON 4575 void PandaNode::CData::
4577 if (!_python_tag_data.empty()) {
4578 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 4581 PyGILState_STATE gstate;
4582 gstate = PyGILState_Ensure();
4585 PythonTagData::const_iterator ti;
4586 for (ti = _python_tag_data.begin();
4587 ti != _python_tag_data.end();
4589 PyObject *value = (*ti).second;
4593 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 4594 PyGILState_Release(gstate);
4598 #endif // HAVE_PYTHON 4606 void PandaNode::CData::
4618 int num_parents = 0;
4619 Up::const_iterator ui;
4620 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
4626 nassertv(num_parents == (
int)(PN_uint16)num_parents);
4628 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
4642 void PandaNode::CData::
4645 int num_children = down_list.size();
4646 nassertv(num_children == (
int)(PN_uint16)num_children);
4651 Down::const_iterator di;
4652 for (di = down_list.begin(); di != down_list.end(); ++di) {
4654 int sort = (*di).get_sort();
4666 void PandaNode::CData::
4668 Up::const_iterator ui;
4669 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
4683 void PandaNode::CData::
4685 Down::const_iterator di;
4686 for (di = down_list.begin(); di != down_list.end(); ++di) {
4698 int PandaNode::CData::
4704 Up new_up_list(PandaNode::get_class_type());
4705 new_up_list.reserve(num_parents);
4706 for (
int i = 0; i < num_parents; i++) {
4708 UpConnection connection(parent_node);
4709 new_up_list.push_back(connection);
4718 up_list.swap(new_up_list);
4719 new_up_list.clear();
4730 int PandaNode::CData::
4735 BamReaderAuxDataDown *aux;
4738 Down &new_down_list = aux->_down_list;
4739 for (Down::iterator di = new_down_list.begin();
4740 di != new_down_list.end();
4743 (*di).set_child(child_node);
4751 down_list.swap(new_down_list);
4752 new_down_list.clear();
4764 void PandaNode::CData::
4779 void PandaNode::CData::
4788 Down new_down_list(PandaNode::get_class_type());
4789 new_down_list.reserve(num_children);
4790 for (
int i = 0; i < num_children; i++) {
4794 new_down_list.push_back(connection);
4799 PT(BamReaderAuxDataDown) aux =
new BamReaderAuxDataDown;
4800 aux->_down_list.swap(new_down_list);
4814 ? _cdata->_last_bounds_update
4815 : _cdata->_last_update;
4817 if (last_update != _cdata->_next_update) {
4823 #ifdef DO_PIPELINING 4825 #endif // DO_PIPELINING 4829 if (fresh_cdata->_last_update == fresh_cdata->_next_update &&
4830 (!update_bounds || fresh_cdata->_last_bounds_update == fresh_cdata->_next_update)) {
4834 if (_cdata != (
const PandaNode::CData *)fresh_cdata) {
4836 #ifdef DO_PIPELINING 4838 #endif // DO_PIPELINING 4844 PStatTimer timer(PandaNode::_update_bounds_pcollector);
4846 nassertv(cdataw->_last_update == cdataw->_next_update);
4849 if (_cdata != (
const PandaNode::CData *)cdataw) {
4851 #ifdef DO_PIPELINING 4853 #endif // DO_PIPELINING 4858 nassertv(_cdata->_last_update == _cdata->_next_update);
4859 nassertv(!update_bounds || _cdata->_last_bounds_update == _cdata->_next_update);
bool is_empty() const
Returns true if the state is empty, false otherwise.
virtual int get_visible_child() const
Returns the index number of the currently visible child of this node.
static BitMask< PN_uint32, nbits > bit(int index)
Returns a BitMask with only the indicated bit on.
int get_num_children() const
Returns the number of children of the node.
void set_tag(const string &key, const string &value, Thread *current_thread=Thread::get_current_thread())
Associates a user-defined value with a user-defined key which is stored on the node.
void clear_unexpected_change(unsigned int flags)
Sets one or more of the PandaNode::UnexpectedChange bits off, indicating that the corresponding prope...
virtual int get_first_visible_child() const
Returns the index number of the first visible child of this node, or a number >= get_num_children() i...
bool is_scene_root() const
Returns true if this particular node is known to be the render root of some active DisplayRegion asso...
virtual Light * as_light()
Cross-casts the node to a Light pointer, if it is one of the four kinds of Light nodes, or returns NULL if it is not.
virtual bool preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
A basic node of the scene graph or data graph.
The abstract interface to all kinds of lights.
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
PandaNode * get_stashed(int n) const
Returns the nth stashed child of the node.
void add_uint8(PN_uint8 value)
Adds an unsigned 8-bit integer to the datagram.
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
virtual CollideMask get_legal_collide_mask() const
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode...
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
int get_num_parents() const
Returns the number of parents of the node.
This is our own Panda specialization on the default STL map.
const RenderEffects * get_effects() const
Returns the complete RenderEffects that will be applied to this node.
int get_num_stashed(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of stashed nodes this node has.
void add_string(const string &str)
Adds a variable-length string to the datagram.
const TransformState * get_transform() const
Returns the transform that has been set on this particular node.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
bool replace_child(PandaNode *orig_child, PandaNode *new_child, Thread *current_thread=Thread::get_current_thread())
Searches for the orig_child node in the node's list of children, and replaces it with the new_child i...
virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, GeomTransformer &transformer)
Applies whatever attributes are specified in the AccumulatedAttribs object (and by the attrib_types b...
bool is_empty() const
Returns true if the state is empty, false otherwise.
bool has_object(const TypedWritable *obj) const
Returns true if the object has previously been written (or at least requested to be written) to the b...
DrawMask get_net_draw_show_mask() const
Returns the union of all draw_show_mask values–of renderable nodes only–at this level and below...
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
int get_pipeline_stage() const
Returns the Pipeline stage number associated with this thread.
virtual bool safe_to_modify_transform() const
Returns true if it is safe to automatically adjust the transform on this kind of node.
virtual PandaNode * combine_with(PandaNode *other)
Collapses this PandaNode with the other PandaNode, if possible, and returns a pointer to the combined...
static void reset_all_prev_transform(Thread *current_thread=Thread::get_current_thread())
Visits all nodes in the world with the _dirty_prev_transform flag–that is, all nodes whose _prev_tra...
void write_recorder(BamWriter *manager, Datagram &dg)
This method is provided for the benefit of classes (like MouseRecorder) that inherit from PandaMode a...
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
void set_effects(const RenderEffects *effects, Thread *current_thread=Thread::get_current_thread())
Sets the complete RenderEffects that will be applied this node.
int get_child_sort(int n) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
void set_bounds(const BoundingVolume *volume)
Resets the bounding volume so that it is the indicated volume.
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of child nodes this node has.
static BitMask< PN_uint32, nbits > all_on()
Returns a BitMask whose bits are all on.
bool is_empty() const
Any kind of volume might be empty.
bool stash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Stashes the indicated child node.
PandaNode * get_parent(int n) const
Returns the nth parent of the node.
void get_tag_keys(vector_string &keys) const
Fills the given vector up with the list of tags on this PandaNode.
void clear_tag(const string &key, Thread *current_thread=Thread::get_current_thread())
Removes the value defined for this key on this particular node.
bool unstash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Returns the indicated stashed node to normal child status.
This defines a bounding sphere, consisting of a center and a radius.
const RenderState * get_state() const
Returns the complete RenderState that will be applied to all nodes at this level and below...
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
A single page of data maintained by a PipelineCycler.
unsigned int get_unexpected_change(unsigned int flags) const
Returns nonzero if any of the bits in the input parameter are set on this node, or zero if none of th...
Base class for objects that can be written to and read from Bam files.
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
virtual bool has_selective_visibility() const
Should be overridden by derived classes to return true if this kind of node has some restrictions on ...
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
static bool decode_raw_from_bam_stream(TypedWritable *&ptr, ReferenceCount *&ref_ptr, const string &data, BamReader *reader=NULL)
Reads the string created by a previous call to encode_to_bam_stream(), and extracts the single object...
const CycleDataType * take_pointer()
This is intended to be called only from CycleDataStageWriter when it elevates the pointer from read t...
PandaNode * get_parent(int n) const
Returns the nth parent node of this node.
void adjust_draw_mask(DrawMask show_mask, DrawMask hide_mask, DrawMask clear_mask)
Adjusts the hide/show bits of this particular node.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
This functions similarly to a LightAttrib.
static BitMask< PN_uint32, nbits > all_off()
Returns a BitMask whose bits are all off.
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
This is the base class for a number of special render effects that may be set on scene graph nodes to...
int get_stashed_sort(int n) const
Returns the sort index of the nth stashed node of this node (that is, the number that was passed to a...
Parents get_parents(Thread *current_thread=Thread::get_current_thread()) const
Returns an object that can be used to walk through the list of parents of the node, similar to get_children() and get_stashed().
PN_int32 get_int32()
Extracts a signed 32-bit integer.
PN_uint8 get_uint8()
Extracts an unsigned 8-bit integer.
PandaNode * get_node() const
Returns the node referenced by this component.
PN_uint32 get_uint32()
Extracts an unsigned 32-bit integer.
static void register_with_read_factory()
Tells the BamReader how to create objects of type PandaNode.
virtual bool safe_to_combine() const
Returns true if it is generally safe to combine this particular kind of PandaNode with other kinds of...
int get_int_tag(const string &tag) const
Returns the value previously set via set_int_tag().
void set_word(WordType value)
Sets the entire BitMask to the value indicated by the given word.
void copy_tags(PandaNode *other)
Copies all of the tags stored on the other node onto this node.
string get_string()
Extracts a variable-length string.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
virtual void r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, GeomTransformer &transformer, Thread *current_thread)
The recursive implementation of prepare_scene().
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This just stores the pointers to implement a doubly-linked list of some kind of object.
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
DrawMask get_net_draw_control_mask() const
Returns the set of bits in get_net_draw_show_mask() that have been explicitly set via adjust_draw_mas...
virtual const BoundingBox * as_bounding_box() const
Virtual downcast method.
PandaNode * get_stashed(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth stashed child of this node.
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node...
This is our own Panda specialization on the default STL vector.
int find_parent(PandaNode *node) const
Returns the index of the indicated parent node, if it is a parent, or -1 if it is not...
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
void reset_prev_transform(Thread *current_thread=Thread::get_current_thread())
Resets the transform that represents this node's "previous" position to the same as the current trans...
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this PandaNode by the indicated matrix, if it means anything to do so...
A lightweight class that represents a single element that may be timed and/or counted via stats...
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
int get_stashed_sort(int n) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
void check_cached(bool update_bounds) const
Ensures that the draw masks etc.
A base class for all things which can have a name.
bool is_top_node(int pipeline_stage, Thread *current_thread) const
Returns true if this component represents the top node in the path.
int get_child_sort(int n) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
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...
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
This is a 4-by-4 transform matrix.
void remove_all_children(Thread *current_thread=Thread::get_current_thread())
Removes all the children from the node at once, including stashed children.
void set_bounds_type(BoundingVolume::BoundsType bounds_type)
Specifies the desired type of bounding volume that will be created for this node. ...
Similar to MutexHolder, but for a light mutex.
virtual bool is_collision_node() const
A simple downcast check.
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
void set_child(PandaNode *child)
This is only called by PandaNode::replace_child().
bool is_under_scene_root() const
Returns true if this particular node is in a live scene graph: that is, it is a child or descendent o...
NodePathComponent * get_next(int pipeline_stage, Thread *current_thread) const
Returns the next component in the path.
virtual PandaNode * dupe_for_flatten() const
This is similar to make_copy(), but it makes a copy for the specific purpose of flatten.
void remove_stashed(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth stashed child from the node.
void set_state(const RenderState *state, Thread *current_thread=Thread::get_current_thread())
Sets the complete RenderState that will be applied to all nodes at this level and below...
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void copy_all_properties(PandaNode *other)
Copies the TransformState, RenderState, RenderEffects, tags, Python tags, and the show/hide state fro...
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, so that it will be drawn at render time.
void steal_children(PandaNode *other, Thread *current_thread=Thread::get_current_thread())
Moves all the children from the other node onto 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...
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
void set_into_collide_mask(CollideMask 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...
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin()...
virtual bool safe_to_flatten_below() const
Returns true if a flatten operation may safely continue past this node, or false if nodes below this ...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
static void set_scene_root_func(SceneRootFunc *func)
This is used by the GraphicsEngine to hook in a pointer to the scene_root_func(), the function to det...
int get_child_sort(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
CollideMask get_net_collide_mask(Thread *current_thread=Thread::get_current_thread()) const
Returns the union of all into_collide_mask() values set at CollisionNodes at this level and below...
void add_stashed(PandaNode *child_node, int sort=0, Thread *current_thread=Thread::get_current_thread())
Adds a new child to the node, directly as a stashed child.
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
virtual int get_unsafe_to_apply_attribs() const
Returns the union of all attributes from SceneGraphReducer::AttribTypes that may not safely be applie...
virtual bool is_lod_node() const
A simple downcast check.
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
This class is similar to CycleDataLockedReader, except it allows reading from a particular stage of t...
BoundingVolume::BoundsType get_bounds_type() const
Returns the bounding volume type set with set_bounds_type().
Similar to MutexHolder, but for a light reentrant mutex.
void finalize_now(TypedWritable *whom)
Forces the finalization of a particular object.
void set_attrib(const RenderAttrib *attrib, int override=0)
Adds the indicated render attribute to the scene graph on this node.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
PandaNode * get_parent(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth parent node of this node.
This class is similar to CycleDataReader, except it allows reading from a particular stage of the pip...
int get_num_stashed() const
Returns the number of stashed children of the node.
virtual bool is_ambient_light() const
Returns true if this is an AmbientLight, false if it is not a light, or it is some other kind of ligh...
A base class for all things that want to be reference-counted.
int get_num_children() const
Returns the number of child nodes this node has.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
void set_bound(const BoundingVolume *volume)
Deprecated.
void replace_node(PandaNode *other)
Inserts this node into the scene graph in place of the other one, and removes the other node...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
bool around(const BoundingVolume **first, const BoundingVolume **last)
Resets the volume to enclose only the volumes indicated.
Children get_children(Thread *current_thread=Thread::get_current_thread()) const
Returns an object that can be used to walk through the list of children of the node.
BamReaderAuxData * get_aux_tag(const string &tag) const
Returns the value previously set via set_aux_tag().
A thread; that is, a lightweight process.
void add_uint32(PN_uint32 value)
Adds an unsigned 32-bit integer to the datagram.
int get_num_stashed() const
Returns the number of stashed nodes this node has.
int get_stashed_sort(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the sort index of the nth stashed node of this node (that is, the number that was passed to a...
Encapsulates the data from a PandaNode, pre-fetched for one stage of the pipeline.
void set_aux_tag(const string &tag, BamReaderAuxData *value)
Allows the creating object to store a temporary data value on the BamReader.
Thread * get_current_thread() const
Returns the Thread pointer of the currently-executing thread, as passed to the constructor of this ob...
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 ...
void set_int_tag(const string &tag, int value)
Allows the creating object to store a temporary data value on the BamReader.
PandaNode * get_child(int n) const
Returns the nth child node of this node.
void add_int32(PN_int32 value)
Adds a signed 32-bit integer to the datagram.
A class to retrieve the individual data elements previously stored in a Datagram. ...
void clear_effect(TypeHandle type)
Removes the render effect of the given type from 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, for the purposes of detecting motion for accurate collision calculations.
PandaNode * get_child(int n) const
Returns the nth child of the node.
void consider_update(const TypedWritable *obj)
Should be called from TypedWritable::update_bam_nested() to recursively check the entire hiererachy o...
TypeHandle is the identifier used to differentiate C++ class types.
This is a sequence number that increments monotonically.
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of PandaNode by calling the xf...
int find_stashed(PandaNode *node, Thread *current_thread=Thread::get_current_thread()) const
Returns the index of the indicated stashed node, if it is a stashed child, or -1 if it is not...
virtual bool is_geom_node() const
A simple downcast check.
virtual int get_next_visible_child(int n) const
Returns the index number of the next visible child of this node following the indicated child...
void copy_children(PandaNode *other, Thread *current_thread=Thread::get_current_thread())
Makes another instance of all the children of the other node, copying them to this node...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
void set_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Sets the transform that will be applied to this node and below.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
void mark_bam_modified()
Increments the bam_modified counter, so that this object will be invalidated and retransmitted on any...
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of PandaNode by duplicating ...
bool is_zero() const
Returns true if the entire bitmask is zero, false otherwise.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
void read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
This class maintains a linked list of PandaNodes.
This is one component of a NodePath.
static UpdateSeq initial()
Returns an UpdateSeq in the 'initial' state.
void list_tags(ostream &out, const string &separator="\) const
Writes a list of all the tag keys assigned to the node to the indicated stream.