open_toontown_panda3d/panda/src/pgraph/pandaNode_ext.cxx

260 lines
9.3 KiB
C++

// Filename: pandaNode_ext.cxx
// Created by: CFSworks (30Mar14)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "pandaNode_ext.h"
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: Extension<PandaNode>::__copy__
// Access: Published
// Description: A special Python method that is invoked by
// copy.copy(node). Unlike the PandaNode copy
// constructor, which creates a new node without
// children, this shares child pointers (essentially
// making every child an instance). This is intended to
// simulate the behavior of copy.copy() for other
// objects.
////////////////////////////////////////////////////////////////////
PT(PandaNode) Extension<PandaNode>::
__copy__() const {
Thread *current_thread = Thread::get_current_thread();
PT(PandaNode) node_dupe = _this->make_copy();
PandaNode::Children children = _this->get_children(current_thread);
int num_children = children.get_num_children();
for (int i = 0; i < num_children; ++i) {
node_dupe->add_child(children.get_child(i), children.get_child_sort(i));
}
return node_dupe;
}
////////////////////////////////////////////////////////////////////
// Function: Extension<PandaNode>::__deepcopy__
// Access: Published
// Description: A special Python method that is invoked by
// copy.deepcopy(node). This calls copy_subgraph()
// unless the node is already present in the provided
// dictionary.
////////////////////////////////////////////////////////////////////
PyObject *Extension<PandaNode>::
__deepcopy__(PyObject *self, PyObject *memo) const {
extern struct Dtool_PyTypedObject Dtool_PandaNode;
// Borrowed reference.
PyObject *dupe = PyDict_GetItem(memo, self);
if (dupe != NULL) {
// Already in the memo dictionary.
Py_INCREF(dupe);
return dupe;
}
PT(PandaNode) node_dupe = _this->copy_subgraph();
// DTool_CreatePyInstanceTyped() steals a C++ reference.
node_dupe->ref();
dupe = DTool_CreatePyInstanceTyped
((void *)node_dupe.p(), Dtool_PandaNode, true, false,
node_dupe->get_type_index());
if (PyDict_SetItem(memo, self, dupe) != 0) {
Py_DECREF(dupe);
return NULL;
}
return dupe;
}
////////////////////////////////////////////////////////////////////
// Function: Extension<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.
////////////////////////////////////////////////////////////////////
void Extension<PandaNode>::
set_python_tag(const string &key, PyObject *value) {
Thread *current_thread = Thread::get_current_thread();
int pipeline_stage = current_thread->get_pipeline_stage();
nassertv(pipeline_stage == 0);
PandaNode::CDWriter cdata(_this->_cycler);
Py_XINCREF(value);
pair<PandaNode::PythonTagData::iterator, bool> result;
result = cdata->_python_tag_data.insert(PandaNode::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.
PandaNode::PythonTagData::iterator ti = result.first;
PyObject *old_value = (*ti).second;
Py_XDECREF(old_value);
(*ti).second = value;
}
// Even though the python tag isn't recorded in the bam stream?
_this->mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
// Function: Extension<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.
////////////////////////////////////////////////////////////////////
PyObject *Extension<PandaNode>::
get_python_tag(const string &key) const {
PandaNode::CDReader cdata(_this->_cycler);
PandaNode::PythonTagData::const_iterator ti;
ti = cdata->_python_tag_data.find(key);
if (ti != cdata->_python_tag_data.end()) {
PyObject *result = (*ti).second;
Py_XINCREF(result);
return result;
}
Py_INCREF(Py_None);
return Py_None;
}
////////////////////////////////////////////////////////////////////
// Function: Extension<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.
////////////////////////////////////////////////////////////////////
bool Extension<PandaNode>::
has_python_tag(const string &key) const {
PandaNode::CDReader cdata(_this->_cycler);
PandaNode::PythonTagData::const_iterator ti;
ti = cdata->_python_tag_data.find(key);
return (ti != cdata->_python_tag_data.end());
}
////////////////////////////////////////////////////////////////////
// Function: Extension<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.
////////////////////////////////////////////////////////////////////
void Extension<PandaNode>::
clear_python_tag(const string &key) {
Thread *current_thread = Thread::get_current_thread();
int pipeline_stage = current_thread->get_pipeline_stage();
nassertv(pipeline_stage == 0);
PandaNode::CDWriter cdata(_this->_cycler, current_thread);
PandaNode::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);
}
// Even though the python tag isn't recorded in the bam stream?
_this->mark_bam_modified();
}
////////////////////////////////////////////////////////////////////
// Function: Extension<PandaNode>::get_python_tag_keys
// Access: Published
// Description: Fills the given vector up with the
// list of Python tags on this PandaNode.
//
// It is the user's responsibility to ensure that the
// keys vector is empty before making this call;
// otherwise, the new files will be appended to it.
////////////////////////////////////////////////////////////////////
void Extension<PandaNode>::
get_python_tag_keys(vector_string &keys) const {
PandaNode::CDReader cdata(_this->_cycler);
if (!cdata->_python_tag_data.empty()) {
PandaNode::PythonTagData::const_iterator ti = cdata->_python_tag_data.begin();
while (ti != cdata->_python_tag_data.end()) {
keys.push_back((*ti).first);
++ti;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: Extension<PandaNode>::get_tag_keys
// Access: Published
// Description: This variant on get_tag_keys returns
// a Python list of strings.
////////////////////////////////////////////////////////////////////
PyObject *Extension<PandaNode>::
get_tag_keys() const {
vector_string keys;
_this->get_tag_keys(keys);
PyObject *result = PyList_New(keys.size());
for (size_t i = 0; i < keys.size(); ++i) {
const string &tag_name = keys[i];
#if PY_MAJOR_VERSION >= 3
PyObject *str = PyUnicode_FromStringAndSize(tag_name.data(), tag_name.size());
#else
PyObject *str = PyString_FromStringAndSize(tag_name.data(), tag_name.size());
#endif
PyList_SET_ITEM(result, i, str);
}
return result;
}
////////////////////////////////////////////////////////////////////
// Function: Extension<PandaNode>::get_python_tag_keys
// Access: Published
// Description: This variant on get_python_tag_keys returns
// a Python list of strings.
////////////////////////////////////////////////////////////////////
PyObject *Extension<PandaNode>::
get_python_tag_keys() const {
vector_string keys;
get_python_tag_keys(keys);
PyObject *result = PyList_New(keys.size());
for (size_t i = 0; i < keys.size(); ++i) {
const string &tag_name = keys[i];
#if PY_MAJOR_VERSION >= 3
PyObject *str = PyUnicode_FromStringAndSize(tag_name.data(), tag_name.size());
#else
PyObject *str = PyString_FromStringAndSize(tag_name.data(), tag_name.size());
#endif
PyList_SET_ITEM(result, i, str);
}
return result;
}
#endif // HAVE_PYTHON