more pgraph refinements

This commit is contained in:
David Rose 2002-03-20 01:27:29 +00:00
parent 7ac1742772
commit 29e70407b5
20 changed files with 263 additions and 61 deletions

View File

@ -160,6 +160,30 @@ update_internals(PartGroup *parent, bool self_changed, bool parent_changed) {
}
}
if (net_changed && !_net_transform_nodes.empty()) {
CPT(TransformState) t = TransformState::make_mat(_net_transform);
NodeList::iterator ai;
ai = _net_transform_nodes.begin();
while (ai != _net_transform_nodes.end()) {
PandaNode *node = *ai;
node->set_transform(t);
++ai;
}
}
if (self_changed && !_local_transform_nodes.empty()) {
CPT(TransformState) t = TransformState::make_mat(_value);
NodeList::iterator ai;
ai = _local_transform_nodes.begin();
while (ai != _local_transform_nodes.end()) {
PandaNode *node = *ai;
node->set_transform(t);
++ai;
}
}
return self_changed || net_changed;
}
@ -203,18 +227,6 @@ has_net_transform(NodeRelation *arc) const {
return (_net_transform_arcs.count(arc) > 0);
}
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::clear_net_transforms
// Access: Public
// Description: Removes all arcs from the list of arcs that will be
// updated each frame with the joint's net transform
// from the root.
////////////////////////////////////////////////////////////////////
void CharacterJoint::
clear_net_transforms() {
_net_transform_arcs.clear();
}
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::add_local_transform
// Access: Public
@ -255,16 +267,110 @@ has_local_transform(NodeRelation *arc) const {
return (_local_transform_arcs.count(arc) > 0);
}
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::add_net_transform
// Access: Public
// Description: Adds the indicated node to the list of nodes that will
// be updated each frame with the joint's net transform
// from the root. Returns true if the node is
// successfully added, false if it had already been
// added.
////////////////////////////////////////////////////////////////////
bool CharacterJoint::
add_net_transform(PandaNode *node) {
return _net_transform_nodes.insert(node).second;
}
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::remove_net_transform
// Access: Public
// Description: Removes the indicated node from the list of nodes that
// will be updated each frame with the joint's net
// transform from the root. Returns true if the node is
// successfully removed, false if it was not on the
// list.
////////////////////////////////////////////////////////////////////
bool CharacterJoint::
remove_net_transform(PandaNode *node) {
return (_net_transform_nodes.erase(node) > 0);
}
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::has_net_transform
// Access: Public
// Description: Returns true if the node is on the list of nodes that
// will be updated each frame with the joint's net
// transform from the root, false otherwise.
////////////////////////////////////////////////////////////////////
bool CharacterJoint::
has_net_transform(PandaNode *node) const {
return (_net_transform_nodes.count(node) > 0);
}
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::clear_net_transforms
// Access: Public
// Description: Removes all nodes from the list of nodes that will be
// updated each frame with the joint's net transform
// from the root.
////////////////////////////////////////////////////////////////////
void CharacterJoint::
clear_net_transforms() {
_net_transform_arcs.clear();
_net_transform_nodes.clear();
}
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::add_local_transform
// Access: Public
// Description: Adds the indicated node to the list of nodes that will
// be updated each frame with the joint's local
// transform from its parent. Returns true if the node
// is successfully added, false if it had already been
// added.
////////////////////////////////////////////////////////////////////
bool CharacterJoint::
add_local_transform(PandaNode *node) {
return _local_transform_nodes.insert(node).second;
}
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::remove_local_transform
// Access: Public
// Description: Removes the indicated node from the list of nodes that
// will be updated each frame with the joint's local
// transform from its parent. Returns true if the node
// is successfully removed, false if it was not on the
// list.
////////////////////////////////////////////////////////////////////
bool CharacterJoint::
remove_local_transform(PandaNode *node) {
return (_local_transform_nodes.erase(node) > 0);
}
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::has_local_transform
// Access: Public
// Description: Returns true if the node is on the list of nodes that
// will be updated each frame with the joint's local
// transform from its parent, false otherwise.
////////////////////////////////////////////////////////////////////
bool CharacterJoint::
has_local_transform(PandaNode *node) const {
return (_local_transform_nodes.count(node) > 0);
}
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::clear_local_transforms
// Access: Public
// Description: Removes all arcs from the list of arcs that will be
// Description: Removes all nodes from the list of nodes that will be
// updated each frame with the joint's local transform
// from its parent.
////////////////////////////////////////////////////////////////////
void CharacterJoint::
clear_local_transforms() {
_local_transform_arcs.clear();
_local_transform_nodes.clear();
}
////////////////////////////////////////////////////////////////////

View File

@ -50,11 +50,19 @@ PUBLISHED:
bool add_net_transform(NodeRelation *arc);
bool remove_net_transform(NodeRelation *arc);
bool has_net_transform(NodeRelation *arc) const;
void clear_net_transforms();
bool add_local_transform(NodeRelation *arc);
bool remove_local_transform(NodeRelation *arc);
bool has_local_transform(NodeRelation *arc) const;
bool add_net_transform(PandaNode *node);
bool remove_net_transform(PandaNode *node);
bool has_net_transform(PandaNode *node) const;
void clear_net_transforms();
bool add_local_transform(PandaNode *node);
bool remove_local_transform(PandaNode *node);
bool has_local_transform(PandaNode *node) const;
void clear_local_transforms();
private:
@ -62,6 +70,10 @@ private:
ArcList _net_transform_arcs;
ArcList _local_transform_arcs;
typedef pset< PT(PandaNode) > NodeList;
NodeList _net_transform_nodes;
NodeList _local_transform_nodes;
public:
static void register_with_read_factory(void);
virtual void write_datagram(BamWriter* manager, Datagram &me);

View File

@ -39,6 +39,8 @@ qpCollisionNode(const string &name) :
_into_collide_mask(CollideMask::all_on()),
_collide_geom(false)
{
// CollisionNodes are hidden by default.
set_draw_mask(DrawMask::all_off());
}
////////////////////////////////////////////////////////////////////

View File

@ -129,8 +129,17 @@ convert_mat(CoordinateSystem from, CoordinateSystem to) {
////////////////////////////////////////////////////////////////////
int FLOATNAME(LMatrix4)::
compare_to(const FLOATNAME(LMatrix4) &other, FLOATTYPE threshold) const {
for (int i = 0; i < 16; i++) {
if (!IS_THRESHOLD_EQUAL(_m.data[i], other._m.data[i], threshold)) {
FLOATTYPE scale = 1.0f / threshold;
// We compare values in reverse order, since the last row of the
// matrix is most likely to be different between different matrices.
for (int i = 15; i >= 0; i--) {
// We scale both elements into the same range and truncate, rather
// than comparing the absolute values of their differences with
// IS_THRESHOLD_EQUAL. This prevents a slippery-slope effect
// where a == b and b == c but a != c.
if (cfloor(_m.data[i] * scale + 0.5) !=
cfloor(other._m.data[i] * scale + 0.5)) {
return (_m.data[i] < other._m.data[i]) ? -1 : 1;
}
}

View File

@ -98,7 +98,14 @@ int FogAttrib::
compare_to_impl(const RenderAttrib *other) const {
const FogAttrib *ta;
DCAST_INTO_R(ta, other, 0);
return (int)(_fog - ta->_fog);
// Comparing pointers by subtraction is problematic. Instead of
// doing this, we'll just depend on the built-in != and < operators
// for comparing pointers.
if (_fog != ta->_fog) {
return _fog < ta->_fog ? -1 : 1;
}
return 0;
}
////////////////////////////////////////////////////////////////////

View File

@ -98,7 +98,14 @@ int MaterialAttrib::
compare_to_impl(const RenderAttrib *other) const {
const MaterialAttrib *ta;
DCAST_INTO_R(ta, other, 0);
return (int)(_material - ta->_material);
// Comparing pointers by subtraction is problematic. Instead of
// doing this, we'll just depend on the built-in != and < operators
// for comparing pointers.
if (_material != ta->_material) {
return _material < ta->_material ? -1 : 1;
}
return 0;
}
////////////////////////////////////////////////////////////////////

View File

@ -398,6 +398,7 @@ PandaNode(const PandaNode &copy) :
cdata->_state = copy_cdata->_state;
cdata->_effects = copy_cdata->_effects;
cdata->_transform = copy_cdata->_transform;
cdata->_draw_mask = copy_cdata->_draw_mask;
}
////////////////////////////////////////////////////////////////////
@ -1261,12 +1262,6 @@ children_changed() {
////////////////////////////////////////////////////////////////////
PT(PandaNode) PandaNode::
r_copy_subgraph(PandaNode::InstanceMap &inst_map) const {
if (!safe_to_flatten()) {
// If this kind of node cannot be copied, quietly return the same
// pointer, making an instance instead of a copy.
return (PandaNode *)this;
}
PT(PandaNode) copy = make_copy();
nassertr(copy != (PandaNode *)NULL, NULL);
if (copy->get_type() != get_type()) {

View File

@ -131,19 +131,21 @@ traverse_below(PandaNode *node, const CullTraverserData &data) {
}
}
// Now visit all the node's children.
PandaNode::Children cr = node->get_children();
int num_children = cr.get_num_children();
// Now visit all the node's children. We cannot use the
// node->get_children() interface, because that will keep a read
// pointer open, and we might end up changing this node during the
// traversal.
int num_children = node->get_num_children();
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
while (i < num_children) {
traverse(cr.get_child(i), data);
traverse(node->get_child(i), data);
i = node->get_next_visible_child(i);
}
} else {
for (int i = 0; i < num_children; i++) {
traverse(cr.get_child(i), data);
traverse(node->get_child(i), data);
}
}
}

View File

@ -713,7 +713,7 @@ do_flatten_siblings(PandaNode *parent_node, PandaNode *child1,
<< "Collapsing " << *child1 << " and " << *child2 << "\n";
}
PT(PandaNode) new_child = collapse_nodes(child1, child2, true);
PT(PandaNode) new_child = collapse_nodes(child2, child1, true);
if (new_child == (PandaNode *)NULL) {
if (pgraph_cat.is_debug()) {
pgraph_cat.debug()
@ -722,7 +722,7 @@ do_flatten_siblings(PandaNode *parent_node, PandaNode *child1,
return NULL;
}
choose_name(new_child, child1, child2);
choose_name(new_child, child2, child1);
if (new_child == child1) {
new_child->steal_children(child2);

View File

@ -20,7 +20,7 @@
#include "bamReader.h"
#include "indent.h"
RenderAttrib::Attribs RenderAttrib::_attribs;
RenderAttrib::Attribs *RenderAttrib::_attribs = NULL;
TypeHandle RenderAttrib::_type_handle;
////////////////////////////////////////////////////////////////////
@ -30,7 +30,15 @@ TypeHandle RenderAttrib::_type_handle;
////////////////////////////////////////////////////////////////////
RenderAttrib::
RenderAttrib() {
_saved_entry = _attribs.end();
if (_attribs == (Attribs *)NULL) {
// Make sure the global _attribs map is allocated. This only has
// to be done once. We could make this map static, but then we
// run into problems if anyone creates a RenderState object at
// static init time; it also seems to cause problems when the
// Panda shared library is unloaded at application exit time.
_attribs = new Attribs;
}
_saved_entry = _attribs->end();
}
////////////////////////////////////////////////////////////////////
@ -61,9 +69,23 @@ operator = (const RenderAttrib &) {
////////////////////////////////////////////////////////////////////
RenderAttrib::
~RenderAttrib() {
if (_saved_entry != _attribs.end()) {
_attribs.erase(_saved_entry);
_saved_entry = _attribs.end();
if (_saved_entry != _attribs->end()) {
// We cannot make this assertion, because the RenderAttrib has
// already partially destructed--this means we cannot look up the
// object in the map. In fact, the map is temporarily invalid
// until we finish destructing, since we screwed up the ordering
// when we changed the return value of get_type().
// nassertv(_attribs->find(this) == _saved_entry);
// Note: this isn't thread-safe, because once the derived class
// destructor exits and before this destructor completes, the map
// is invalid, and other threads may inadvertently attempt to read
// the invalid map. To make it thread-safe, we need to move this
// functionality to a separate method, that is to be called from
// *each* derived class's destructor (and then we can put the
// above assert back in).
_attribs->erase(_saved_entry);
_saved_entry = _attribs->end();
}
}
@ -120,13 +142,13 @@ return_new(RenderAttrib *attrib) {
// This should be a newly allocated pointer, not one that was used
// for anything else.
nassertr(attrib->_saved_entry == _attribs.end(), attrib);
nassertr(attrib->_saved_entry == _attribs->end(), attrib);
// Save the attrib in a local PointerTo so that it will be freed at
// the end of this function if no one else uses it.
CPT(RenderAttrib) pt_attrib = attrib;
pair<Attribs::iterator, bool> result = _attribs.insert(attrib);
pair<Attribs::iterator, bool> result = _attribs->insert(attrib);
if (result.second) {
// The attribute was inserted; save the iterator and return the
// input attribute.

View File

@ -85,7 +85,7 @@ protected:
private:
typedef pset<const RenderAttrib *, IndirectCompareTo<RenderAttrib> > Attribs;
static Attribs _attribs;
static Attribs *_attribs;
Attribs::iterator _saved_entry;

View File

@ -62,6 +62,7 @@ operator = (const RenderEffect &) {
RenderEffect::
~RenderEffect() {
if (_saved_entry != _effects.end()) {
nassertv(_effects.find(this) == _saved_entry);
_effects.erase(_saved_entry);
_saved_entry = _effects.end();
}
@ -153,6 +154,7 @@ return_new(RenderEffect *effect) {
// The effect was inserted; save the iterator and return the
// input effect.
effect->_saved_entry = result.first;
effect->ref(); // **** TEMPORARY HACK
return pt_effect;
}

View File

@ -113,7 +113,7 @@ compare_to(const Attribute &other) const {
return _type.get_index() - other._type.get_index();
}
if (_attrib != other._attrib) {
return _attrib - other._attrib;
return _attrib < other._attrib ? -1 : 1;
}
return _override - other._override;
}

View File

@ -27,10 +27,11 @@
#include "indent.h"
#include "compareTo.h"
RenderState::States RenderState::_states;
RenderState::States *RenderState::_states = NULL;
CPT(RenderState) RenderState::_empty_state;
TypeHandle RenderState::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: RenderState::Constructor
// Access: Protected
@ -40,7 +41,15 @@ TypeHandle RenderState::_type_handle;
////////////////////////////////////////////////////////////////////
RenderState::
RenderState() {
_saved_entry = _states.end();
if (_states == (States *)NULL) {
// Make sure the global _states map is allocated. This only has
// to be done once. We could make this map static, but then we
// run into problems if anyone creates a RenderState object at
// static init time; it also seems to cause problems when the
// Panda shared library is unloaded at application exit time.
_states = new States;
}
_saved_entry = _states->end();
_self_compose = (RenderState *)NULL;
_flags = 0;
}
@ -73,10 +82,10 @@ operator = (const RenderState &) {
////////////////////////////////////////////////////////////////////
RenderState::
~RenderState() {
// Remove the deleted RenderState object from the global pool.
if (_saved_entry != _states.end()) {
_states.erase(_saved_entry);
_saved_entry = _states.end();
if (_saved_entry != _states->end()) {
nassertv(_states->find(this) == _saved_entry);
_states->erase(_saved_entry);
_saved_entry = _states->end();
}
// Now make sure we clean up all other floating pointers to the
@ -725,20 +734,21 @@ return_new(RenderState *state) {
// This should be a newly allocated pointer, not one that was used
// for anything else.
nassertr(state->_saved_entry == _states.end(), state);
nassertr(state->_saved_entry == _states->end(), state);
// Save the state in a local PointerTo so that it will be freed at
// the end of this function if no one else uses it.
CPT(RenderState) pt_state = state;
pair<States::iterator, bool> result = _states.insert(state);
pair<States::iterator, bool> result = _states->insert(state);
if (result.second) {
// The state was inserted; save the iterator and return the
// input state.
state->_saved_entry = result.first;
return pt_state;
}
// The state was not inserted; there must be an equivalent one
// already in the set. Return that one.
return *(result.first);
@ -976,8 +986,8 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
// Now make sure the array is properly sorted. (It won't
// necessarily preserve its correct sort after being read from bam,
// because the sort is based on TypeHandle indices, which can change
// from session to session.)
// because the sort is based on TypeHandle indices and raw pointers,
// both of which can change from session to session.)
_attributes.sort();
return pi;

View File

@ -106,7 +106,7 @@ private:
private:
typedef pset<const RenderState *, IndirectLess<RenderState> > States;
static States _states;
static States *_states;
static CPT(RenderState) _empty_state;
// This iterator records the entry corresponding to this RenderState

View File

@ -98,7 +98,14 @@ int TextureAttrib::
compare_to_impl(const RenderAttrib *other) const {
const TextureAttrib *ta;
DCAST_INTO_R(ta, other, 0);
return (int)(_texture - ta->_texture);
// Comparing pointers by subtraction is problematic. Instead of
// doing this, we'll just depend on the built-in != and < operators
// for comparing pointers.
if (_texture != ta->_texture) {
return _texture < ta->_texture ? -1 : 1;
}
return 0;
}
////////////////////////////////////////////////////////////////////

View File

@ -24,7 +24,7 @@
#include "indent.h"
#include "compareTo.h"
TransformState::States TransformState::_states;
TransformState::States *TransformState::_states = NULL;
CPT(TransformState) TransformState::_identity_state;
TypeHandle TransformState::_type_handle;
@ -37,7 +37,15 @@ TypeHandle TransformState::_type_handle;
////////////////////////////////////////////////////////////////////
TransformState::
TransformState() {
_saved_entry = _states.end();
if (_states == (States *)NULL) {
// Make sure the global _states map is allocated. This only has
// to be done once. We could make this map static, but then we
// run into problems if anyone creates a RenderState object at
// static init time; it also seems to cause problems when the
// Panda shared library is unloaded at application exit time.
_states = new States;
}
_saved_entry = _states->end();
_self_compose = (TransformState *)NULL;
_flags = F_is_identity | F_singular_known;
_inv_mat = (LMatrix4f *)NULL;
@ -77,9 +85,10 @@ TransformState::
}
// Remove the deleted TransformState object from the global pool.
if (_saved_entry != _states.end()) {
_states.erase(_saved_entry);
_saved_entry = _states.end();
if (_saved_entry != _states->end()) {
nassertv(_states->find(this) == _saved_entry);
_states->erase(_saved_entry);
_saved_entry = _states->end();
}
// Now make sure we clean up all other floating pointers to the
@ -540,13 +549,13 @@ return_new(TransformState *state) {
// This should be a newly allocated pointer, not one that was used
// for anything else.
nassertr(state->_saved_entry == _states.end(), state);
nassertr(state->_saved_entry == _states->end(), state);
// Save the state in a local PointerTo so that it will be freed at
// the end of this function if no one else uses it.
CPT(TransformState) pt_state = state;
pair<States::iterator, bool> result = _states.insert(state);
pair<States::iterator, bool> result = _states->insert(state);
if (result.second) {
// The state was inserted; save the iterator and return the
// input state.

View File

@ -109,7 +109,7 @@ private:
private:
typedef pset<const TransformState *, IndirectLess<TransformState> > States;
static States _states;
static States *_states;
static CPT(TransformState) _identity_state;
// This iterator records the entry corresponding to this TransformState

View File

@ -20,6 +20,7 @@
#include "pgItem.h"
#include "pgMouseWatcherGroup.h"
#include "pgCullTraverser.h"
#include "cullBinAttrib.h"
#include "omniBoundingVolume.h"
@ -40,6 +41,14 @@ qpPGTop(const string &name) :
// culling.
set_bound(OmniBoundingVolume());
set_final(true);
// Also, screw state sorting. By default, everything under PGTop
// will be unsorted: rendered in scene graph order. This is closer
// to what the user wants anyway in a 2-d scene graph.
// This override of 1000 should really be a system constant
// somewhere.
set_attrib(CullBinAttrib::make("unsorted", 0), 1000);
}
////////////////////////////////////////////////////////////////////

View File

@ -81,10 +81,13 @@ init_libtext() {
string text_encoding = config_text.GetString("text-encoding", "iso8859");
if (text_encoding == "iso8859") {
TextNode::_default_encoding = TextNode::E_iso8859;
qpTextNode::_default_encoding = qpTextNode::E_iso8859;
} else if (text_encoding == "utf8") {
TextNode::_default_encoding = TextNode::E_utf8;
qpTextNode::_default_encoding = qpTextNode::E_utf8;
} else if (text_encoding == "unicode") {
TextNode::_default_encoding = TextNode::E_unicode;
qpTextNode::_default_encoding = qpTextNode::E_unicode;
} else {
text_cat.error()
<< "Invalid text-encoding: " << text_encoding << "\n";