add set_python_tag() etc.

This commit is contained in:
David Rose 2005-07-06 22:43:53 +00:00
parent 3fff6285ce
commit 7a249dde55
6 changed files with 363 additions and 3 deletions

View File

@ -1832,7 +1832,128 @@ get_net_tag(const string &key) const {
////////////////////////////////////////////////////////////////////
INLINE bool NodePath::
has_net_tag(const string &key) const {
return find_net_tag(key).has_tag(key);
return !find_net_tag(key).is_empty();
}
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_python_tag
// Access: Published
// Description: Associates an arbitrary Python object with a
// user-defined key which is stored on the node. This
// object has no meaning to Panda; but it is stored
// indefinitely on the node until it is requested again.
//
// Each unique key stores a different Python object.
// There is no effective limit on the number of
// different keys that may be stored or on the nature of
// any one key's object.
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
set_python_tag(const string &key, PyObject *value) {
nassertv_always(!is_empty());
node()->set_python_tag(key, value);
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_python_tag
// Access: Published
// Description: Retrieves the Python object that was previously
// set on this node for the particular key, if any. If
// no object has been previously set, returns None.
// See also get_net_python_tag().
////////////////////////////////////////////////////////////////////
INLINE PyObject *NodePath::
get_python_tag(const string &key) const {
// An empty NodePath quietly returns no tags. This makes
// get_net_python_tag() easier to implement.
if (is_empty()) {
return Py_None;
}
return node()->get_python_tag(key);
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::has_python_tag
// Access: Published
// Description: Returns true if a Python object has been defined on
// this node for the particular key (even if that value
// is the empty string), or false if no value has been
// set. See also has_net_python_tag().
////////////////////////////////////////////////////////////////////
INLINE bool NodePath::
has_python_tag(const string &key) const {
// An empty NodePath quietly has no tags. This makes has_net_python_tag()
// easier to implement.
if (is_empty()) {
return false;
}
return node()->has_python_tag(key);
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::clear_python_tag
// Access: Published
// Description: Removes the Python object defined for this key on this
// particular node. After a call to clear_python_tag(),
// has_python_tag() will return false for the indicated
// key.
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
clear_python_tag(const string &key) {
nassertv_always(!is_empty());
node()->clear_python_tag(key);
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_net_python_tag
// Access: Published
// Description: Returns the Python object that has been defined on
// this node, or the nearest ancestor node, for the
// indicated key. If no value has been defined for the
// indicated key on any ancestor node, returns None.
// See also get_python_tag().
////////////////////////////////////////////////////////////////////
INLINE PyObject *NodePath::
get_net_python_tag(const string &key) const {
return find_net_python_tag(key).get_python_tag(key);
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::has_net_python_tag
// Access: Published
// Description: Returns true if the indicated Python object has been
// defined on this node or on any ancestor node, or
// false otherwise. See also has_python_tag().
////////////////////////////////////////////////////////////////////
INLINE bool NodePath::
has_net_python_tag(const string &key) const {
return !find_net_python_tag(key).is_empty();
}
#endif // HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::list_tags
// Access: Published
// Description: Lists the tags to the nout stream, one per line. See
// PandaNode::list_tags() for a variant that allows you
// to specify the output stream.
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
list_tags() const {
nassertv_always(!is_empty());
node()->list_tags(nout);
nout << "\n";
}
////////////////////////////////////////////////////////////////////

View File

@ -4998,6 +4998,27 @@ find_net_tag(const string &key) const {
return get_parent().find_net_tag(key);
}
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::find_net_python_tag
// Access: Published
// Description: Returns the lowest ancestor of this node that
// contains a tag definition with the indicated key, if
// any, or an empty NodePath if no ancestor of this node
// contains this tag definition. See set_python_tag().
////////////////////////////////////////////////////////////////////
NodePath NodePath::
find_net_python_tag(const string &key) const {
if (is_empty()) {
return NodePath::not_found();
}
if (has_python_tag(key)) {
return *this;
}
return get_parent().find_net_python_tag(key);
}
#endif // HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::write_bam_file
// Access: Published

View File

@ -727,6 +727,18 @@ PUBLISHED:
INLINE bool has_net_tag(const string &key) const;
NodePath find_net_tag(const string &key) const;
#ifdef HAVE_PYTHON
INLINE void set_python_tag(const string &key, PyObject *value);
INLINE PyObject *get_python_tag(const string &key) const;
INLINE bool has_python_tag(const string &key) const;
INLINE void clear_python_tag(const string &key);
INLINE PyObject *get_net_python_tag(const string &key) const;
INLINE bool has_net_python_tag(const string &key) const;
NodePath find_net_python_tag(const string &key) const;
#endif // HAVE_PYTHON
INLINE void list_tags() const;
INLINE void set_name(const string &name);
INLINE string get_name() const;

View File

@ -772,6 +772,121 @@ clear_tag(const string &key) {
cdata->_tag_data.erase(key);
}
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: PandaNode::set_python_tag
// Access: Published
// Description: Associates an arbitrary Python object with a
// user-defined key which is stored on the node. This
// is similar to set_tag(), except it can store any
// Python object instead of just a string. However, the
// Python object is not recorded to a bam file.
//
// Each unique key stores a different string value.
// There is no effective limit on the number of
// different keys that may be stored or on the length of
// any one key's value.
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
set_python_tag(const string &key, PyObject *value) {
CDWriter cdata(_cycler);
Py_XINCREF(value);
pair<PythonTagData::iterator, bool> result;
result = cdata->_python_tag_data.insert(PythonTagData::value_type(key, value));
if (!result.second) {
// The insert was unsuccessful; that means the key was already
// present in the map. In this case, we should decrement the
// original value's reference count and replace it with the new
// object.
PythonTagData::iterator ti = result.first;
PyObject *old_value = (*ti).second;
Py_XDECREF(old_value);
(*ti).second = value;
}
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_python_tag
// Access: Published
// Description: Retrieves the Python object that was previously
// set on this node for the particular key, if any. If
// no value has been previously set, returns None.
////////////////////////////////////////////////////////////////////
INLINE PyObject *PandaNode::
get_python_tag(const string &key) const {
CDReader cdata(_cycler);
PythonTagData::const_iterator ti;
ti = cdata->_python_tag_data.find(key);
if (ti != cdata->_python_tag_data.end()) {
return (*ti).second;
}
return Py_None;
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: PandaNode::has_python_tag
// Access: Published
// Description: Returns true if a Python object has been defined on
// this node for the particular key (even if that object
// is None), or false if no object has been set.
////////////////////////////////////////////////////////////////////
INLINE bool PandaNode::
has_python_tag(const string &key) const {
CDReader cdata(_cycler);
PythonTagData::const_iterator ti;
ti = cdata->_python_tag_data.find(key);
return (ti != cdata->_python_tag_data.end());
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: PandaNode::clear_python_tag
// Access: Published
// Description: Removes the Python object defined for this key on
// this particular node. After a call to
// clear_python_tag(), has_python_tag() will return
// false for the indicated key.
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
clear_python_tag(const string &key) {
CDWriter cdata(_cycler);
PythonTagData::iterator ti;
ti = cdata->_python_tag_data.find(key);
if (ti != cdata->_python_tag_data.end()) {
PyObject *value = (*ti).second;
Py_XDECREF(value);
cdata->_python_tag_data.erase(ti);
}
}
#endif // HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: PandaNode::has_tags
// Access: Published
// Description: Returns true if the node has any tags (or any Python
// tags) at all, false if it has none.
////////////////////////////////////////////////////////////////////
INLINE bool PandaNode::
has_tags() const {
CDReader cdata(_cycler);
if (!cdata->_tag_data.empty()) {
return true;
}
#ifdef HAVE_PYTHON
if (!cdata->_python_tag_data.empty()) {
return true;
}
#endif // HAVE_PYTHON
return false;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::ls
// Access: Published

View File

@ -357,6 +357,20 @@ PandaNode::
#endif // NDEBUG
remove_all_children();
#ifdef HAVE_PYTHON
{
// Free all of the Python objects held by this node.
CDReader cdata(_cycler);
PythonTagData::const_iterator ti;
for (ti = cdata->_python_tag_data.begin();
ti != cdata->_python_tag_data.end();
++ti) {
PyObject *value = (*ti).second;
Py_XDECREF(value);
}
}
#endif // HAVE_PYTHON
}
////////////////////////////////////////////////////////////////////
@ -385,6 +399,20 @@ PandaNode(const PandaNode &copy) :
cdata->_draw_mask = copy_cdata->_draw_mask;
cdata->_into_collide_mask = copy_cdata->_into_collide_mask;
cdata->_fixed_internal_bound = copy_cdata->_fixed_internal_bound;
#ifdef HAVE_PYTHON
// Copy and increment all of the Python objects held by the other
// node.
cdata->_python_tag_data = copy_cdata->_python_tag_data;
PythonTagData::const_iterator ti;
for (ti = cdata->_python_tag_data.begin();
ti != cdata->_python_tag_data.end();
++ti) {
PyObject *value = (*ti).second;
Py_XINCREF(value);
}
#endif // HAVE_PYTHON
}
////////////////////////////////////////////////////////////////////
@ -1248,6 +1276,31 @@ copy_tags(PandaNode *other) {
++ti) {
cdataw->_tag_data[(*ti).first] = (*ti).second;
}
#ifdef HAVE_PYTHON
PythonTagData::const_iterator pti;
for (pti = cdatar->_python_tag_data.begin();
pti != cdatar->_python_tag_data.end();
++pti) {
const string &key = (*pti).first;
PyObject *value = (*pti).second;
Py_XINCREF(value);
pair<PythonTagData::iterator, bool> result;
result = cdataw->_python_tag_data.insert(PythonTagData::value_type(key, value));
if (!result.second) {
// The insert was unsuccessful; that means the key was already
// present in the map. In this case, we should decrement the
// original value's reference count and replace it with the new
// object.
PythonTagData::iterator wpti = result.first;
PyObject *old_value = (*wpti).second;
Py_XDECREF(old_value);
(*wpti).second = value;
}
}
#endif // HAVE_PYTHON
}
////////////////////////////////////////////////////////////////////
@ -1274,6 +1327,21 @@ list_tags(ostream &out, const string &separator) const {
++ti;
}
}
#ifdef HAVE_PYTHON
if (!cdata->_python_tag_data.empty()) {
if (!cdata->_tag_data.empty()) {
out << separator;
}
PythonTagData::const_iterator ti = cdata->_python_tag_data.begin();
out << (*ti).first;
++ti;
while (ti != cdata->_python_tag_data.end()) {
out << separator << (*ti).first;
++ti;
}
}
#endif // HAVE_PYTHON
}
////////////////////////////////////////////////////////////////////
@ -1311,7 +1379,7 @@ void PandaNode::
write(ostream &out, int indent_level) const {
indent(out, indent_level) << *this;
CDReader cdata(_cycler);
if (!cdata->_tag_data.empty()) {
if (has_tags()) {
out << " [";
list_tags(out, " ");
out << "]";
@ -2025,7 +2093,7 @@ void PandaNode::
r_list_descendants(ostream &out, int indent_level) const {
CDReader cdata(_cycler);
indent(out, indent_level) << *this;
if (!cdata->_tag_data.empty()) {
if (has_tags()) {
out << " [";
list_tags(out, " ");
out << "]";

View File

@ -41,6 +41,14 @@
#include "pointerToArray.h"
#include "notify.h"
#ifdef HAVE_PYTHON
#undef HAVE_LONG_LONG // NSPR and Python both define this.
#undef _POSIX_C_SOURCE
#include <Python.h>
#endif // HAVE_PYTHON
class NodePathComponent;
class CullTraverser;
class CullTraverserData;
@ -159,6 +167,15 @@ PUBLISHED:
INLINE string get_tag(const string &key) const;
INLINE bool has_tag(const string &key) const;
INLINE void clear_tag(const string &key);
#ifdef HAVE_PYTHON
INLINE void set_python_tag(const string &key, PyObject *value);
INLINE PyObject *get_python_tag(const string &key) const;
INLINE bool has_python_tag(const string &key) const;
INLINE void clear_python_tag(const string &key);
#endif // HAVE_PYTHON
INLINE bool has_tags() const;
void copy_tags(PandaNode *other);
void list_tags(ostream &out, const string &separator = "\n") const;
@ -286,6 +303,9 @@ private:
// This is used to maintain a table of keyed data on each node, for
// the user's purposes.
typedef phash_map<string, string, string_hash> TagData;
#ifdef HAVE_PYTHON
typedef phash_map<string, PyObject *, string_hash> PythonTagData;
#endif // HAVE_PYTHON
// This is the data that must be cycled between pipeline stages.
@ -322,6 +342,9 @@ private:
NCPT(TransformState) _prev_transform;
TagData _tag_data;
#ifdef HAVE_PYTHON
PythonTagData _python_tag_data;
#endif // HAVE_PYTHON
// This is the draw_mask of this particular node.
DrawMask _draw_mask;