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();
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);
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);
441 int num_children = cr.get_num_children();
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 {
619 InstanceMap inst_map;
620 return r_copy_subgraph(inst_map, current_thread);
634 for (
int i = 0; i < num_children; ++i) {
655 nassertv(child_node != (
PandaNode *)NULL);
657 if (!verify_child_no_cycles(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());
705 PT(
PandaNode) child_node = (*down)[child_index].get_child();
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);
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();
853 child_node->mark_bam_modified();
873 nassertv(pipeline_stage == 0);
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();
901 child_node->mark_bam_modified();
921 nassertv(pipeline_stage == 0);
923 if (!verify_child_no_cycles(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) {
997 PT(
PandaNode) child_node = (*di).get_child();
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();
1004 child_node->mark_bam_modified();
1008 Down &stashed = *cdata->modify_stashed();
1009 for (di = stashed.begin(); di != stashed.end(); ++di) {
1010 PT(
PandaNode) child_node = (*di).get_child();
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();
1017 child_node->mark_bam_modified();
1021 CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1023 force_bounds_stale();
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++) {
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++) {
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);
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);
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);
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);
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);
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);
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);
1292 transform_changed();
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);
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);
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);
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);
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);
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) {
1744 if (any_transform_changed) {
1745 transform_changed();
1747 if (any_state_changed) {
1750 if (any_draw_mask_changed) {
1751 draw_mask_changed();
1780 if (other ==
this) {
1797 for (pi = other->_paths.begin(); pi != other->_paths.end(); ++pi) {
1798 (*pi)->_node =
this;
1801 other->_paths.clear();
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);
1956 draw_mask_changed();
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;
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);
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 {
2102 int pipeline_stage = current_thread->get_pipeline_stage();
2103 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
2104 if (cdata->_last_update != cdata->_next_update) {
2107 CDStageWriter cdataw =
2108 ((
PandaNode *)
this)->update_cached(
false, pipeline_stage, cdata);
2109 return cdataw->_off_clip_planes;
2111 return cdata->_off_clip_planes;
2149 if (_scene_root_func != (SceneRootFunc *)NULL) {
2150 return (*_scene_root_func)(
this);
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;
2206 CPT(TransformState) transform = get_transform();
2207 if (!transform->is_identity()) {
2208 out <<
" " << *transform;
2211 if (!state->is_empty()) {
2212 out <<
" " << *state;
2215 if (!effects->is_empty()) {
2216 out <<
" " << *effects;
2219 if (!draw_control_mask.
is_zero()) {
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;
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();
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 {
2341 int pipeline_stage = current_thread->get_pipeline_stage();
2342 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
2343 if (cdata->_last_bounds_update != cdata->_next_update) {
2348 CDStageWriter cdataw =
2349 ((
PandaNode *)
this)->update_cached(
true, pipeline_stage, cdata);
2350 result = cdataw->_external_bounds;
2354 return cdata->_external_bounds;
2375 int pipeline_stage = current_thread->get_pipeline_stage();
2376 CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
2377 if (cdata->_last_bounds_update != cdata->_next_update) {
2382 CDStageWriter cdataw =
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;
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;
2444 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2447 CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2468 OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, 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);
2602 CDStageWriter cdataw(((
PandaNode *)this)->_cycler, pipeline_stage);
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);
2649 CDStageWriter cdataw(((
PandaNode *)this)->_cycler, pipeline_stage);
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);
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;
2729 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2730 parents = Parents(cdata);
2732 int num_parents = parents.get_num_parents();
2733 for (
int i = 0; i < num_parents; ++i) {
2746 r_mark_geom_bounds_stale(
Thread *current_thread) {
2750 for (i = 0; i < children.get_num_children(); i++) {
2752 child->r_mark_geom_bounds_stale(current_thread);
2756 for (i = 0; i < stashed.get_num_stashed(); i++) {
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);
2857 r_copy_subgraph(
PandaNode::InstanceMap &inst_map,
Thread *current_thread)
const {
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);
2933 CPT(
RenderState) child_state = node_state->compose(child->get_state());
2934 child->
r_prepare_scene(gsg, child_state, transformer, 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);
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);
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) {
3067 DownConnection &dc = (*down)[child_index];
3068 nassertr(dc.get_child() == orig_child,
false);
3069 dc.set_child(new_child);
3072 PT(Down) stashed = cdata->modify_stashed();
3073 int stashed_index = do_find_child(orig_child, stashed);
3074 if (stashed_index >= 0) {
3076 DownConnection &dc = (*stashed)[stashed_index];
3077 nassertr(dc.get_child() == orig_child,
false);
3078 dc.set_child(new_child);
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();
3102 orig_child->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);
3126 cdata->modify_down()->insert(DownConnection(child_node, sort));
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());
3160 for (
int i = 0; i < parents.get_num_parents(); ++i) {
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)) {
3248 PT(
PandaNode) child_node = child->get_node();
3249 PT(
PandaNode) parent_node = child->get_next(pipeline_stage, current_thread)->get_node();
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();
3293 parent_node->mark_bam_modified();
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) {
3422 PandaNode *parent_node = parent->get_node();
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);
3687 children = Children(cdata);
3688 stashed = Stashed(cdata);
3691 int num_children = children.get_num_children();
3693 for (i = 0; i < num_children; ++i) {
3695 child_node->fix_path_lengths(pipeline_stage, current_thread);
3697 int num_stashed = stashed.get_num_stashed();
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);
3715 int num_children = children.get_num_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),
3781 CDStageWriter(_cycler, pipeline_stage, cdata));
3784 CollideMask net_collide_mask = cdata->_into_collide_mask;
3785 DrawMask net_draw_control_mask, net_draw_show_mask;
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
3803 off_clip_planes = ClipPlaneAttrib::make();
3807 Children children(cdata);
3809 int num_vertices = cdata->_internal_vertices;
3813 _cycler.release_read_stage(pipeline_stage, cdata.
take_pointer());
3815 int num_children = children.get_num_children();
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;
3844 if (internal_bounds->as_bounding_box() == NULL) {
3852 for (
int i = 0; i < num_children; ++i) {
3857 CDLockedStageReader child_cdata(child->_cycler, pipeline_stage, current_thread);
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);
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);
4110 if (cdataw->_last_update == cdataw->_next_update &&
4111 (!update_bounds || cdataw->_last_bounds_update == cdataw->_next_update)) {
4119 cdata = CDLockedStageReader(_cycler, pipeline_stage, current_thread);
4121 if (cdata->_last_update == cdata->_next_update &&
4122 (!update_bounds || cdata->_last_bounds_update == cdata->_next_update)) {
4125 return CDStageWriter(_cycler, pipeline_stage, cdata);
4143 _scene_root_func = func;
4181 cdata->update_bam_nested(manager);
4219 parse_params(params, scan, manager);
4220 node->fillin(scan, manager);
4265 _transform(TransformState::make_identity()),
4266 _prev_transform(TransformState::make_identity()),
4269 _draw_control_mask(
DrawMask::all_off()),
4270 _draw_show_mask(
DrawMask::all_on()),
4274 _final_bounds(false),
4278 _net_draw_control_mask(
DrawMask::all_off()),
4279 _net_draw_show_mask(
DrawMask::all_off()),
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());
4478 void PandaNode::CData::
4494 _draw_control_mask = _overall_bit;
4495 _draw_show_mask = ~_overall_bit;
4504 draw_mask &= ~_overall_bit;
4505 _draw_control_mask = ~draw_mask;
4506 _draw_show_mask = draw_mask;
4514 _into_collide_mask.set_word(scan.
get_uint32());
4516 _bounds_type = BoundingVolume::BT_default;
4518 _bounds_type = (BoundingVolume::BoundsType)scan.
get_uint8();
4523 for (
int i = 0; i < num_tags; i++) {
4526 _tag_data[key] = value;
4530 fillin_up_list(*modify_up(),
"up", scan, manager);
4531 fillin_down_list(*modify_down(),
"down", scan, manager);
4532 fillin_down_list(*modify_stashed(),
"stashed", scan, manager);
4542 void PandaNode::CData::
4544 if (!_python_tag_data.empty()) {
4545 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
4548 PyGILState_STATE gstate;
4549 gstate = PyGILState_Ensure();
4551 PythonTagData::const_iterator ti;
4552 for (ti = _python_tag_data.begin();
4553 ti != _python_tag_data.end();
4555 PyObject *value = (*ti).second;
4558 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
4559 PyGILState_Release(gstate);
4563 #endif // HAVE_PYTHON
4572 void PandaNode::CData::
4574 if (!_python_tag_data.empty()) {
4575 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
4578 PyGILState_STATE gstate;
4579 gstate = PyGILState_Ensure();
4582 PythonTagData::const_iterator ti;
4583 for (ti = _python_tag_data.begin();
4584 ti != _python_tag_data.end();
4586 PyObject *value = (*ti).second;
4590 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
4591 PyGILState_Release(gstate);
4595 #endif // HAVE_PYTHON
4603 void PandaNode::CData::
4615 int num_parents = 0;
4616 Up::const_iterator ui;
4617 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
4623 nassertv(num_parents == (
int)(PN_uint16)num_parents);
4625 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
4639 void PandaNode::CData::
4642 int num_children = down_list.size();
4643 nassertv(num_children == (
int)(PN_uint16)num_children);
4648 Down::const_iterator di;
4649 for (di = down_list.begin(); di != down_list.end(); ++di) {
4651 int sort = (*di).get_sort();
4663 void PandaNode::CData::
4665 Up::const_iterator ui;
4666 for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
4680 void PandaNode::CData::
4682 Down::const_iterator di;
4683 for (di = down_list.begin(); di != down_list.end(); ++di) {
4695 int PandaNode::CData::
4701 Up new_up_list(PandaNode::get_class_type());
4702 new_up_list.reserve(num_parents);
4703 for (
int i = 0; i < num_parents; i++) {
4705 UpConnection connection(parent_node);
4706 new_up_list.push_back(connection);
4715 up_list.swap(new_up_list);
4716 new_up_list.clear();
4727 int PandaNode::CData::
4732 BamReaderAuxDataDown *aux;
4735 Down &new_down_list = aux->_down_list;
4736 for (Down::iterator di = new_down_list.begin();
4737 di != new_down_list.end();
4740 (*di).set_child(child_node);
4748 down_list.swap(new_down_list);
4749 new_down_list.clear();
4761 void PandaNode::CData::
4776 void PandaNode::CData::
4785 Down new_down_list(PandaNode::get_class_type());
4786 new_down_list.reserve(num_children);
4787 for (
int i = 0; i < num_children; i++) {
4790 DownConnection connection(NULL, sort);
4791 new_down_list.push_back(connection);
4796 PT(BamReaderAuxDataDown) aux = new BamReaderAuxDataDown;
4797 aux->_down_list.swap(new_down_list);
4798 manager->set_aux_tag(tag, aux);
4809 check_cached(
bool update_bounds)
const {
4811 ? _cdata->_last_bounds_update
4812 : _cdata->_last_update;
4814 if (last_update != _cdata->_next_update) {
4820 #ifdef DO_PIPELINING
4822 #endif // DO_PIPELINING
4824 int pipeline_stage = _current_thread->get_pipeline_stage();
4826 if (fresh_cdata->_last_update == fresh_cdata->_next_update &&
4827 (!update_bounds || fresh_cdata->_last_bounds_update == fresh_cdata->_next_update)) {
4831 if (_cdata != (
const PandaNode::CData *)fresh_cdata) {
4833 #ifdef DO_PIPELINING
4835 #endif // DO_PIPELINING
4841 PStatTimer timer(PandaNode::_update_bounds_pcollector);
4843 nassertv(cdataw->_last_update == cdataw->_next_update);
4846 if (_cdata != (
const PandaNode::CData *)cdataw) {
4848 #ifdef DO_PIPELINING
4850 #endif // DO_PIPELINING
4855 nassertv(_cdata->_last_update == _cdata->_next_update);
4856 nassertv(!update_bounds || _cdata->_last_bounds_update == _cdata->_next_update);
static BitMask< PN_uint32, nbits > bit(int index)
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 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.
A basic node of the scene graph or data graph.
virtual int get_visible_child() const
Returns the index number of the currently visible child of this node.
The abstract interface to all kinds of lights.
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
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.
This is our own Panda specialization on the default STL map.
DrawMask get_net_draw_control_mask() const
Returns the set of bits in get_net_draw_show_mask() that have been explicitly set via adjust_draw_mas...
void list_tags(ostream &out, const string &separator="\n") const
Writes a list of all the tag keys assigned to the node to the indicated stream.
void add_string(const string &str)
Adds a variable-length string to the datagram.
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.
PandaNode * get_parent(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth parent node of this node.
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...
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...
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...
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 is_collision_node() const
A simple downcast check.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
int get_num_stashed() const
Returns the number of stashed children of the node.
PandaNode * get_parent(int n) const
Returns the nth parent of the node.
virtual PandaNode * combine_with(PandaNode *other)
Collapses this PandaNode with the other PandaNode, if possible, and returns a pointer to the combined...
static void reset_all_prev_transform(Thread *current_thread=Thread::get_current_thread())
Visits all nodes in the world with the _dirty_prev_transform flag–that is, all nodes whose _prev_tran...
void write_recorder(BamWriter *manager, Datagram &dg)
This method is provided for the benefit of classes (like MouseRecorder) that inherit from PandaMode a...
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
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().
void set_effects(const RenderEffects *effects, Thread *current_thread=Thread::get_current_thread())
Sets the complete RenderEffects that will be applied this node.
void get_tag_keys(vector_string &keys) const
Fills the given vector up with the list of tags on this PandaNode.
void set_bounds(const BoundingVolume *volume)
Resets the bounding volume so that it is the indicated volume.
PandaNode * get_child(int n) const
Returns the nth child of the node.
static BitMask< PN_uint32, nbits > all_on()
bool stash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Stashes the indicated child node.
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.
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.
Base class for objects that can be written to and read from Bam files.
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
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_nested_vertices(Thread *current_thread=Thread::get_current_thread()) const
Returns the total number of vertices that will be rendered by this node and all of its descendents...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
BamReaderAuxData * get_aux_tag(const string &tag) const
Returns the value previously set via set_aux_tag().
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...
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< WType, 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...
PN_int32 get_int32()
Extracts a signed 32-bit integer.
PN_uint8 get_uint8()
Extracts an unsigned 8-bit integer.
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...
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 is_lod_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...
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 preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
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.
void mark_bounds_stale(Thread *current_thread=Thread::get_current_thread()) const
Indicates that the bounding volume, or something that influences the bounding volume (or any of the o...
string get_string()
Extracts a variable-length string.
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().
void clear_attrib(TypeHandle type)
Removes the render attribute of the given type from this 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.
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 ...
PandaNode * get_stashed(int n) const
Returns the nth stashed child of the node.
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node...
This is our own Panda specialization on the default STL vector.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
BoundingVolume::BoundsType get_bounds_type() const
Returns the bounding volume type set with set_bounds_type().
bool has_tags() const
Returns true if the node has any tags (or any Python tags) at all, false if it has none...
bool is_top_node(int pipeline_stage, Thread *current_thread) const
Returns true if this component represents the top node in the path.
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...
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...
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 ...
virtual bool safe_to_modify_transform() const
Returns true if it is safe to automatically adjust the transform on this kind of node.
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...
PandaNode * get_stashed(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth stashed child of this node.
A base class for all things which can have a name.
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...
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other...
void mark_internal_bounds_stale(Thread *current_thread=Thread::get_current_thread())
Should be called by a derived class to mark the internal bounding volume stale, so that compute_inter...
PandaNode * get_node() const
Returns the node referenced by this component.
virtual bool safe_to_combine() const
Returns true if it is generally safe to combine this particular kind of PandaNode with other kinds of...
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...
virtual CollideMask get_legal_collide_mask() const
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode...
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
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...
int get_num_children() const
Returns the number of children of the node.
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.
DrawMask get_draw_show_mask() const
Returns the hide/show bits of this particular node.
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_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...
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 read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of child nodes this node has.
void remove_stashed(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth stashed child from the node.
int get_int_tag(const string &tag) const
Returns the value previously set via set_int_tag().
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.
int get_num_parents() const
Returns the number of parents of the node.
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.
DrawMask get_draw_control_mask() const
Returns the set of bits in draw_show_mask that are considered meaningful.
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.
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 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()...
bool is_empty() const
Returns true if the state is empty, false otherwise.
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
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...
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.
This class is similar to CycleDataLockedReader, except it allows reading from a particular stage of t...
Similar to MutexHolder, but for a light reentrant mutex.
void finalize_now(TypedWritable *whom)
Forces the finalization of a particular object.
void set_attrib(const RenderAttrib *attrib, int override=0)
Adds the indicated render attribute to the scene graph on this node.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
int get_num_stashed(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of stashed nodes this node has.
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
This class is similar to CycleDataReader, except it allows reading from a particular stage of the pip...
A base class for all things that want to be reference-counted.
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...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
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.
A thread; that is, a lightweight process.
void add_uint32(PN_uint32 value)
Adds an unsigned 32-bit integer to the datagram.
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 ...
Encapsulates the data from a PandaNode, pre-fetched for one stage of the pipeline.
bool is_empty() const
Returns true if the state is empty, false otherwise.
void set_int_tag(const string &tag, int value)
Allows the creating object to store a temporary data value on the BamReader.
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...
virtual int get_unsafe_to_apply_attribs() const
Returns the union of all attributes from SceneGraphReducer::AttribTypes that may not safely be applie...
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.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
virtual bool is_geom_node() const
A simple downcast check.
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.
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 PandaNode * dupe_for_flatten() const
This is similar to make_copy(), but it makes a copy for the specific purpose of flatten.
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...
This is a sequence number that increments monotonically.
void add_child(PandaNode *child_node, int sort=0, Thread *current_thread=Thread::get_current_thread())
Adds a new child to the node.
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 prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state)
Walks through the scene graph beginning at this node, and does whatever initialization is required to...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
bool is_zero() const
Returns true if the entire bitmask is zero, false otherwise.
Thread * get_current_thread() const
Returns the Thread pointer of the currently-executing thread, as passed to the constructor of this ob...
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...
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_scene_root() const
Returns true if this particular node is known to be the render root of some active DisplayRegion asso...
void mark_bam_modified()
Increments the bam_modified counter, so that this object will be invalidated and retransmitted on any...
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
int get_pipeline_stage() const
Returns the Pipeline stage number associated with this thread.
int count_num_descendants() const
Returns the number of nodes at and below this level.
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.