diff --git a/panda/src/char/characterJoint.cxx b/panda/src/char/characterJoint.cxx index 2798860a45..7bbcd5ff31 100644 --- a/panda/src/char/characterJoint.cxx +++ b/panda/src/char/characterJoint.cxx @@ -89,27 +89,43 @@ update_internals(PartGroup *parent, bool self_changed, bool) { net_changed = true; } - if (net_changed) { + if (net_changed && !_net_transform_arcs.empty()) { PT(TransformTransition) t = new TransformTransition(_net_transform); - ArcList::const_iterator ai; - for (ai = _net_transform_arcs.begin(); - ai != _net_transform_arcs.end(); - ++ai) { + ArcList::iterator ai; + ai = _net_transform_arcs.begin(); + while (ai != _net_transform_arcs.end()) { NodeRelation *arc = *ai; - arc->set_transition(t); + if (arc->is_attached()) { + arc->set_transition(t); + ++ai; + } else { + // The arc is now invalid; its geometry must have been + // removed. Remove the arc from our set. + ArcList::iterator invalid = ai; + ++ai; + _net_transform_arcs.erase(invalid); + } } } - if (self_changed) { + if (self_changed && !_local_transform_arcs.empty()) { PT(TransformTransition) t = new TransformTransition(_value); - ArcList::const_iterator ai; - for (ai = _local_transform_arcs.begin(); - ai != _local_transform_arcs.end(); - ++ai) { + ArcList::iterator ai; + ai = _local_transform_arcs.begin(); + while (ai != _local_transform_arcs.end()) { NodeRelation *arc = *ai; - arc->set_transition(t); + if (arc->is_attached()) { + arc->set_transition(t); + ++ai; + } else { + // The arc is now invalid; its geometry must have been + // removed. Remove the arc from our set. + ArcList::iterator invalid = ai; + ++ai; + _local_transform_arcs.erase(invalid); + } } } } @@ -229,11 +245,39 @@ write_datagram(BamWriter *manager, Datagram &me) { ArcList::iterator ai; + // First, make sure all of our arcs are still valid, before we try + // to write them out. Remove any invalid arcs. + ai = _net_transform_arcs.begin(); + while (ai != _net_transform_arcs.end()) { + NodeRelation *arc = *ai; + if (arc->is_attached()) { + ++ai; + } else { + // The arc is now invalid; its geometry must have been + // removed. Remove the arc from our set. + ArcList::iterator invalid = ai; + ++ai; + _net_transform_arcs.erase(invalid); + } + } + ai = _local_transform_arcs.begin(); + while (ai != _local_transform_arcs.end()) { + NodeRelation *arc = *ai; + if (arc->is_attached()) { + ++ai; + } else { + // The arc is now invalid; its geometry must have been + // removed. Remove the arc from our set. + ArcList::iterator invalid = ai; + ++ai; + _local_transform_arcs.erase(invalid); + } + } + MovingPartMatrix::write_datagram(manager, me); me.add_uint16(_net_transform_arcs.size()); - for(ai = _net_transform_arcs.begin(); ai != _net_transform_arcs.end(); ai++) - { + for(ai = _net_transform_arcs.begin(); ai != _net_transform_arcs.end(); ai++) { manager->write_pointer(me, (*ai)); } diff --git a/panda/src/glgsg/glGraphicsStateGuardian.cxx b/panda/src/glgsg/glGraphicsStateGuardian.cxx index 15a90d098b..26e6bcf29a 100644 --- a/panda/src/glgsg/glGraphicsStateGuardian.cxx +++ b/panda/src/glgsg/glGraphicsStateGuardian.cxx @@ -491,31 +491,27 @@ render_frame(const AllAttributesWrapper &initial_state) { if (_win->is_channel_defined(c)) { GraphicsChannel *chan = _win->get_channel(c); if (chan->is_active()) { - int num_layers = chan->get_num_layers(); - for (int l = 0; l < num_layers; l++) { - GraphicsLayer *layer = chan->get_layer(l); - if (layer->is_active()) { - int num_drs = layer->get_num_drs(); - for (int d = 0; d < num_drs; d++) { - DisplayRegion *dr = layer->get_dr(d); - if (dr == (DisplayRegion*)NULL) - { - cerr << "null camera layer " << endl; - exit(0); - } - Camera *cam = dr->get_camera(); - - // For each display region, render from the camera's view. - if (dr->is_active() && cam != (Camera *)NULL && - cam->is_active() && cam->get_scene() != (Node *)NULL) { - DisplayRegionStack old_dr = push_display_region(dr); - prepare_display_region(); - render_scene(cam->get_scene(), cam, initial_state); - pop_display_region(old_dr); - } - } - } - } + int num_layers = chan->get_num_layers(); + for (int l = 0; l < num_layers; l++) { + GraphicsLayer *layer = chan->get_layer(l); + if (layer->is_active()) { + int num_drs = layer->get_num_drs(); + for (int d = 0; d < num_drs; d++) { + DisplayRegion *dr = layer->get_dr(d); + nassertv(dr != (DisplayRegion *)NULL); + Camera *cam = dr->get_camera(); + + // For each display region, render from the camera's view. + if (dr->is_active() && cam != (Camera *)NULL && + cam->is_active() && cam->get_scene() != (Node *)NULL) { + DisplayRegionStack old_dr = push_display_region(dr); + prepare_display_region(); + render_scene(cam->get_scene(), cam, initial_state); + pop_display_region(old_dr); + } + } + } + } } } } @@ -523,28 +519,28 @@ render_frame(const AllAttributesWrapper &initial_state) { // Now we're done with the frame processing. Clean up. if(_lighting_enabled) { - // Let's turn off all the lights we had on, and clear the light - // cache--to force the lights to be reissued next frame, in case - // their parameters or positions have changed between frames. - - for (int i = 0; i < _max_lights; i++) { - if (_light_enabled[i]) { - enable_light(i, false); - } - _available_light_ids[i] = NULL; - } - - // Also force the lighting state to unlit, so that issue_light() - // will be guaranteed to be called next frame even if we have the - // same set of light pointers we had this frame. - NodeAttributes state; - state.set_attribute(LightTransition::get_class_type(), new LightAttribute); - set_state(state, false); - - // All this work to undo the lighting state each frame doesn't seem - // ideal--there may be a better way. Maybe if the lights were just - // more aware of whether their parameters or positions have changed - // at all? + // Let's turn off all the lights we had on, and clear the light + // cache--to force the lights to be reissued next frame, in case + // their parameters or positions have changed between frames. + + for (int i = 0; i < _max_lights; i++) { + if (_light_enabled[i]) { + enable_light(i, false); + } + _available_light_ids[i] = NULL; + } + + // Also force the lighting state to unlit, so that issue_light() + // will be guaranteed to be called next frame even if we have the + // same set of light pointers we had this frame. + NodeAttributes state; + state.set_attribute(LightTransition::get_class_type(), new LightAttribute); + set_state(state, false); + + // All this work to undo the lighting state each frame doesn't seem + // ideal--there may be a better way. Maybe if the lights were just + // more aware of whether their parameters or positions have changed + // at all? } #ifndef NDEBUG diff --git a/panda/src/graph/nodeRelation.I b/panda/src/graph/nodeRelation.I index dbab622bef..db95d83c85 100644 --- a/panda/src/graph/nodeRelation.I +++ b/panda/src/graph/nodeRelation.I @@ -81,6 +81,21 @@ get_graph_type() const { return _graph_type; } +//////////////////////////////////////////////////////////////////// +// Function: NodeRelation::is_attached +// Access: Public +// Description: Returns true if this arc is attached to the scene +// graph, false otherwise. Normally, an arc should +// always be attached; generally you will only see an +// unattached arc if the arc (or some parent of the arc) +// has been disconnected from all nodes via +// remove_arc(). +//////////////////////////////////////////////////////////////////// +INLINE_GRAPH bool NodeRelation:: +is_attached() const { + return _attached; +} + //////////////////////////////////////////////////////////////////// // Function: NodeRelation::change_parent // Access: Public diff --git a/panda/src/graph/nodeRelation.h b/panda/src/graph/nodeRelation.h index 2c4b863013..73d4a3fa02 100644 --- a/panda/src/graph/nodeRelation.h +++ b/panda/src/graph/nodeRelation.h @@ -80,6 +80,8 @@ PUBLISHED: INLINE_GRAPH int get_sort() const; INLINE_GRAPH TypeHandle get_graph_type() const; + INLINE_GRAPH bool is_attached() const; + void ref_parent(); void unref_parent();