diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index e5376e40ef..684572e620 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -3200,8 +3200,7 @@ if (not RUNTIME): TargetAdd('libp3pgraph.in', opts=OPTS, input=IGATEFILES) TargetAdd('libp3pgraph.in', opts=['IMOD:core', 'ILIB:libp3pgraph', 'SRCDIR:panda/src/pgraph']) TargetAdd('libp3pgraph_igate.obj', input='libp3pgraph.in', opts=["DEPENDENCYONLY","BIGOBJ"]) - TargetAdd('p3pgraph_nodePath_ext.obj', opts=OPTS, input='nodePath_ext.cxx') - TargetAdd('p3pgraph_nodePathCollection_ext.obj', opts=OPTS, input='nodePathCollection_ext.cxx') + TargetAdd('p3pgraph_ext_composite.obj', opts=OPTS, input='p3pgraph_ext_composite.cxx') # # DIRECTORY: panda/src/cull/ @@ -3543,8 +3542,7 @@ if (not RUNTIME): TargetAdd('libpanda.dll', input='p3putil_typedWritable_ext.obj') TargetAdd('libpanda.dll', input='p3pnmimage_pfmFile_ext.obj') TargetAdd('libpanda.dll', input='p3gobj_geomVertexArrayData_ext.obj') - TargetAdd('libpanda.dll', input='p3pgraph_nodePath_ext.obj') - TargetAdd('libpanda.dll', input='p3pgraph_nodePathCollection_ext.obj') + TargetAdd('libpanda.dll', input='p3pgraph_ext_composite.obj') TargetAdd('libpanda.dll', input='p3display_graphicsStateGuardian_ext.obj') if PkgSkip("FREETYPE")==0: diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index d0ddb0e0df..5908e7b551 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -116,7 +116,8 @@ #define COMBINED_SOURCES \ $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx \ - $[TARGET]_composite3.cxx $[TARGET]_composite4.cxx + $[TARGET]_composite3.cxx $[TARGET]_composite4.cxx \ + $[TARGET]_ext_composite.cxx #define INCLUDED_SOURCES \ accumulatedAttribs.cxx \ alphaTestAttrib.cxx \ @@ -277,6 +278,7 @@ occluderEffect.I occluderEffect.h \ occluderNode.I occluderNode.h \ pandaNode.I pandaNode.h \ + pandaNode_ext.h pandaNode_ext.cxx \ pandaNodeChain.I pandaNodeChain.h \ planeNode.I planeNode.h \ polylightEffect.I polylightEffect.h \ @@ -289,6 +291,7 @@ renderEffects.I renderEffects.h \ renderModeAttrib.I renderModeAttrib.h \ renderState.I renderState.h \ + renderState_ext.h renderState_ext.cxx \ rescaleNormalAttrib.I rescaleNormalAttrib.h \ sceneGraphReducer.I sceneGraphReducer.h \ sceneSetup.I sceneSetup.h \ @@ -307,6 +310,7 @@ texGenAttrib.I texGenAttrib.h \ textureStageCollection.I textureStageCollection.h \ transformState.I transformState.h \ + transformState_ext.h transformState_ext.cxx \ transparencyAttrib.I transparencyAttrib.h \ weakNodePath.I weakNodePath.h \ workingNodePath.I workingNodePath.h diff --git a/panda/src/pgraph/nodePath_ext.I b/panda/src/pgraph/nodePath_ext.I index a97a29fb59..3888d6f8f2 100644 --- a/panda/src/pgraph/nodePath_ext.I +++ b/panda/src/pgraph/nodePath_ext.I @@ -12,6 +12,8 @@ // //////////////////////////////////////////////////////////////////// +#include "pandaNode_ext.h" + #ifndef CPPPARSER #ifdef STDFLOAT_DOUBLE IMPORT_THIS struct Dtool_PyTypedObject Dtool_LPoint3d; @@ -33,7 +35,7 @@ IMPORT_THIS struct Dtool_PyTypedObject Dtool_LPoint3f; INLINE void Extension:: get_python_tag_keys(vector_string &keys) const { nassertv_always(!_this->is_empty()); - _this->node()->get_python_tag_keys(keys); + invoke_extension(_this->node()).get_python_tag_keys(keys); } //////////////////////////////////////////////////////////////////// @@ -49,7 +51,7 @@ get_tag_keys() const { Py_INCREF(Py_None); return Py_None; } - return _this->node()->get_tag_keys(); + return invoke_extension(_this->node()).get_tag_keys(); } //////////////////////////////////////////////////////////////////// @@ -66,7 +68,7 @@ get_python_tag_keys() const { Py_INCREF(Py_None); return Py_None; } - return _this->node()->get_python_tag_keys(); + return invoke_extension(_this->node()).get_python_tag_keys(); } //////////////////////////////////////////////////////////////////// @@ -85,7 +87,7 @@ get_python_tag_keys() const { INLINE void Extension:: set_python_tag(const string &key, PyObject *value) { nassertv_always(!_this->is_empty()); - _this->node()->set_python_tag(key, value); + invoke_extension(_this->node()).set_python_tag(key, value); } //////////////////////////////////////////////////////////////////// @@ -104,7 +106,7 @@ get_python_tag(const string &key) const { Py_INCREF(Py_None); return Py_None; } - return _this->node()->get_python_tag(key); + return invoke_extension(_this->node()).get_python_tag(key); } //////////////////////////////////////////////////////////////////// @@ -122,7 +124,7 @@ has_python_tag(const string &key) const { if (_this->is_empty()) { return false; } - return _this->node()->has_python_tag(key); + return invoke_extension(_this->node()).has_python_tag(key); } //////////////////////////////////////////////////////////////////// @@ -136,7 +138,7 @@ has_python_tag(const string &key) const { INLINE void Extension:: clear_python_tag(const string &key) { nassertv_always(!_this->is_empty()); - _this->node()->clear_python_tag(key); + invoke_extension(_this->node()).clear_python_tag(key); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/nodePath_ext.cxx b/panda/src/pgraph/nodePath_ext.cxx index da66754c42..0a9b570194 100644 --- a/panda/src/pgraph/nodePath_ext.cxx +++ b/panda/src/pgraph/nodePath_ext.cxx @@ -40,7 +40,7 @@ __copy__() const { // If we do have a node, duplicate it, and wrap it in a new // NodePath. - return NodePath(_this->node()->__copy__()); + return NodePath(invoke_extension(_this->node()).__copy__()); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/p3pgraph_ext_composite.cxx b/panda/src/pgraph/p3pgraph_ext_composite.cxx new file mode 100644 index 0000000000..6dc854b914 --- /dev/null +++ b/panda/src/pgraph/p3pgraph_ext_composite.cxx @@ -0,0 +1,5 @@ +#include "nodePath_ext.cxx" +#include "nodePathCollection_ext.cxx" +#include "pandaNode_ext.cxx" +#include "renderState_ext.cxx" +#include "transformState_ext.cxx" diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index ec4a2c4639..2dd7f5a5b6 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -632,73 +632,6 @@ copy_subgraph(Thread *current_thread) const { return r_copy_subgraph(inst_map, current_thread); } -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: 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) PandaNode:: -__copy__() const { - Thread *current_thread = Thread::get_current_thread(); - - PT(PandaNode) node_dupe = make_copy(); - - Children children = 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; -} -#endif // HAVE_PYTHON - -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: 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 *PandaNode:: -__deepcopy__(PyObject *self, PyObject *memo) const { - IMPORT_THIS 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 = 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; -} -#endif // HAVE_PYTHON - //////////////////////////////////////////////////////////////////// // Function: PandaNode::count_num_descendants // Access: Published @@ -1509,118 +1442,6 @@ clear_tag(const string &key, Thread *current_thread) { mark_bam_modified(); } -#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. -//////////////////////////////////////////////////////////////////// -void 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); - - CDWriter cdata(_cycler); - Py_XINCREF(value); - - pair 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; - } - - // Even though the python tag isn't recorded in the bam stream? - mark_bam_modified(); -} -#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. -//////////////////////////////////////////////////////////////////// -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()) { - PyObject *result = (*ti).second; - Py_XINCREF(result); - return result; - } - Py_INCREF(Py_None); - 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. -//////////////////////////////////////////////////////////////////// -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. -//////////////////////////////////////////////////////////////////// -void 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); - - CDWriter cdata(_cycler, current_thread); - 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? - mark_bam_modified(); -} -#endif // HAVE_PYTHON - //////////////////////////////////////////////////////////////////// // Function: PandaNode::copy_tags // Access: Published @@ -1743,80 +1564,6 @@ get_tag_keys(vector_string &keys) const { } } -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: Filename::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 PandaNode:: -get_python_tag_keys(vector_string &keys) const { - CDReader cdata(_cycler); - if (!cdata->_python_tag_data.empty()) { - PythonTagData::const_iterator ti = cdata->_python_tag_data.begin(); - while (ti != cdata->_python_tag_data.end()) { - keys.push_back((*ti).first); - ++ti; - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: Filename::get_tag_keys -// Access: Published -// Description: This variant on get_tag_keys returns -// a Python list of strings. -//////////////////////////////////////////////////////////////////// -PyObject *PandaNode:: -get_tag_keys() const { - vector_string keys; - 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: Filename::get_python_tag_keys -// Access: Published -// Description: This variant on get_python_tag_keys returns -// a Python list of strings. -//////////////////////////////////////////////////////////////////// -PyObject *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 - //////////////////////////////////////////////////////////////////// // Function: PandaNode::compare_tags // Access: Published diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 5970d086dd..17d93d8248 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -45,6 +45,7 @@ #include "copyOnWriteObject.h" #include "copyOnWritePointer.h" #include "lightReMutex.h" +#include "extension.h" #ifdef HAVE_PYTHON @@ -118,10 +119,8 @@ PUBLISHED: virtual PandaNode *make_copy() const; PT(PandaNode) copy_subgraph(Thread *current_thread = Thread::get_current_thread()) const; -#ifdef HAVE_PYTHON - PT(PandaNode) __copy__() const; - PyObject *__deepcopy__(PyObject *self, PyObject *memo) const; -#endif + EXTENSION(PT(PandaNode) __copy__() const); + EXTENSION(PyObject *__deepcopy__(PyObject *self, PyObject *memo) const); INLINE int get_num_parents(Thread *current_thread = Thread::get_current_thread()) const; INLINE PandaNode *get_parent(int n, Thread *current_thread = Thread::get_current_thread()) const; @@ -202,16 +201,15 @@ PUBLISHED: void clear_tag(const string &key, Thread *current_thread = Thread::get_current_thread()); void get_tag_keys(vector_string &keys) const; -#ifdef HAVE_PYTHON - PyObject *get_tag_keys() const; - void set_python_tag(const string &key, PyObject *value); - PyObject *get_python_tag(const string &key) const; - bool has_python_tag(const string &key) const; - void clear_python_tag(const string &key); - void get_python_tag_keys(vector_string &keys) const; - PyObject *get_python_tag_keys() const; -#endif // HAVE_PYTHON + EXTENSION(PyObject *get_tag_keys() const); + + EXTENSION(void set_python_tag(const string &key, PyObject *value)); + EXTENSION(PyObject *get_python_tag(const string &key) const); + EXTENSION(bool has_python_tag(const string &key) const); + EXTENSION(void clear_python_tag(const string &key)); + EXTENSION(void get_python_tag_keys(vector_string &keys) const); + EXTENSION(PyObject *get_python_tag_keys() const); INLINE bool has_tags() const; void copy_tags(PandaNode *other); @@ -784,6 +782,7 @@ private: friend class WorkingNodePath; friend class PandaNodePipelineReader; friend class EggLoader; + friend class Extension; }; //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/pandaNode_ext.cxx b/panda/src/pgraph/pandaNode_ext.cxx new file mode 100644 index 0000000000..515b704574 --- /dev/null +++ b/panda/src/pgraph/pandaNode_ext.cxx @@ -0,0 +1,259 @@ +// 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::__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:: +__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::__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:: +__deepcopy__(PyObject *self, PyObject *memo) const { + IMPORT_THIS 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::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:: +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 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::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:: +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::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:: +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::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:: +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::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:: +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::get_tag_keys +// Access: Published +// Description: This variant on get_tag_keys returns +// a Python list of strings. +//////////////////////////////////////////////////////////////////// +PyObject *Extension:: +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::get_python_tag_keys +// Access: Published +// Description: This variant on get_python_tag_keys returns +// a Python list of strings. +//////////////////////////////////////////////////////////////////// +PyObject *Extension:: +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 + diff --git a/panda/src/pgraph/pandaNode_ext.h b/panda/src/pgraph/pandaNode_ext.h new file mode 100644 index 0000000000..a19dc50db9 --- /dev/null +++ b/panda/src/pgraph/pandaNode_ext.h @@ -0,0 +1,50 @@ +// Filename: pandaNode_ext.h +// 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." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PANDANODE_EXT_H +#define PANDANODE_EXT_H + +#include "dtoolbase.h" + +#ifdef HAVE_PYTHON + +#include "extension.h" +#include "pandaNode.h" +#include "py_panda.h" + +//////////////////////////////////////////////////////////////////// +// Class : Extension +// Description : This class defines the extension methods for +// PandaNode, which are called instead of +// any C++ methods with the same prototype. +//////////////////////////////////////////////////////////////////// +template<> +class Extension : public ExtensionBase { +public: + PT(PandaNode) __copy__() const; + PyObject *__deepcopy__(PyObject *self, PyObject *memo) const; + + PyObject *get_tag_keys() const; + + void set_python_tag(const string &key, PyObject *value); + PyObject *get_python_tag(const string &key) const; + bool has_python_tag(const string &key) const; + void clear_python_tag(const string &key); + void get_python_tag_keys(vector_string &keys) const; + PyObject *get_python_tag_keys() const; +}; + +#endif // HAVE_PYTHON + +#endif // PANDANODE_EXT_H diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index 27bdb08cff..d417221be8 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -733,126 +733,6 @@ unref() const { return false; } -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: RenderState::get_composition_cache -// Access: Published -// Description: Returns a list of 2-tuples that represents the -// composition cache. For each tuple in the list, the -// first element is the source render, and the second -// is the result render. If both are None, there is -// no entry in the cache at that slot. -// -// In general, a->compose(source) == result. -// -// This has no practical value other than for examining -// the cache for performance analysis. -//////////////////////////////////////////////////////////////////// -PyObject *RenderState:: -get_composition_cache() const { - IMPORT_THIS struct Dtool_PyTypedObject Dtool_RenderState; - LightReMutexHolder holder(*_states_lock); - size_t cache_size = _composition_cache.get_size(); - PyObject *list = PyList_New(cache_size); - - for (size_t i = 0; i < cache_size; ++i) { - PyObject *tuple = PyTuple_New(2); - PyObject *a, *b; - if (!_composition_cache.has_element(i)) { - a = Py_None; - Py_INCREF(a); - b = Py_None; - Py_INCREF(b); - } else { - const RenderState *source = _composition_cache.get_key(i); - if (source == (RenderState *)NULL) { - a = Py_None; - Py_INCREF(a); - } else { - source->ref(); - a = DTool_CreatePyInstanceTyped((void *)source, Dtool_RenderState, - true, true, source->get_type_index()); - } - const RenderState *result = _composition_cache.get_data(i)._result; - if (result == (RenderState *)NULL) { - b = Py_None; - Py_INCREF(b); - } else { - result->ref(); - b = DTool_CreatePyInstanceTyped((void *)result, Dtool_RenderState, - true, true, result->get_type_index()); - } - } - PyTuple_SET_ITEM(tuple, 0, a); - PyTuple_SET_ITEM(tuple, 1, b); - - PyList_SET_ITEM(list, i, tuple); - } - - return list; -} -#endif // HAVE_PYTHON - -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: RenderState::get_invert_composition_cache -// Access: Published -// Description: Returns a list of 2-tuples that represents the -// invert_composition cache. For each tuple in the list, the -// first element is the source render, and the second -// is the result render. If both are None, there is -// no entry in the cache at that slot. -// -// In general, a->invert_compose(source) == result. -// -// This has no practical value other than for examining -// the cache for performance analysis. -//////////////////////////////////////////////////////////////////// -PyObject *RenderState:: -get_invert_composition_cache() const { - IMPORT_THIS struct Dtool_PyTypedObject Dtool_RenderState; - LightReMutexHolder holder(*_states_lock); - size_t cache_size = _invert_composition_cache.get_size(); - PyObject *list = PyList_New(cache_size); - - for (size_t i = 0; i < cache_size; ++i) { - PyObject *tuple = PyTuple_New(2); - PyObject *a, *b; - if (!_invert_composition_cache.has_element(i)) { - a = Py_None; - Py_INCREF(a); - b = Py_None; - Py_INCREF(b); - } else { - const RenderState *source = _invert_composition_cache.get_key(i); - if (source == (RenderState *)NULL) { - a = Py_None; - Py_INCREF(a); - } else { - source->ref(); - a = DTool_CreatePyInstanceTyped((void *)source, Dtool_RenderState, - true, true, source->get_type_index()); - } - const RenderState *result = _invert_composition_cache.get_data(i)._result; - if (result == (RenderState *)NULL) { - b = Py_None; - Py_INCREF(b); - } else { - result->ref(); - b = DTool_CreatePyInstanceTyped((void *)result, Dtool_RenderState, - true, true, result->get_type_index()); - } - } - PyTuple_SET_ITEM(tuple, 0, a); - PyTuple_SET_ITEM(tuple, 1, b); - - PyList_SET_ITEM(list, i, tuple); - } - - return list; -} -#endif // HAVE_PYTHON - //////////////////////////////////////////////////////////////////// // Function: RenderState::get_auto_shader_state // Access: Published @@ -2271,45 +2151,6 @@ update_pstats(int old_referenced_bits, int new_referenced_bits) { #endif // DO_PSTATS } -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: RenderState::get_states -// Access: Published, Static -// Description: Returns a list of all of the RenderState objects -// in the state cache. The order of elements in this -// cache is arbitrary. -//////////////////////////////////////////////////////////////////// -PyObject *RenderState:: -get_states() { - IMPORT_THIS struct Dtool_PyTypedObject Dtool_RenderState; - if (_states == (States *)NULL) { - return PyList_New(0); - } - LightReMutexHolder holder(*_states_lock); - - size_t num_states = _states->get_num_entries(); - PyObject *list = PyList_New(num_states); - size_t i = 0; - - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { - if (!_states->has_element(si)) { - continue; - } - const RenderState *state = _states->get_key(si); - state->ref(); - PyObject *a = - DTool_CreatePyInstanceTyped((void *)state, Dtool_RenderState, - true, true, state->get_type_index()); - nassertr(i < num_states, list); - PyList_SET_ITEM(list, i, a); - ++i; - } - nassertr(i == num_states, list); - return list; -} -#endif // HAVE_PYTHON - //////////////////////////////////////////////////////////////////// // Function: RenderState::init_states // Access: Public, Static diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index 8c5fc27a8b..0100049c1c 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -126,10 +126,8 @@ PUBLISHED: INLINE int get_invert_composition_cache_size() const; INLINE const RenderState *get_invert_composition_cache_source(int n) const; INLINE const RenderState *get_invert_composition_cache_result(int n) const; -#ifdef HAVE_PYTHON - PyObject *get_composition_cache() const; - PyObject *get_invert_composition_cache() const; -#endif // HAVE_PYTHON + EXTENSION(PyObject *get_composition_cache() const); + EXTENSION(PyObject *get_invert_composition_cache() const); const RenderState *get_auto_shader_state() const; @@ -146,9 +144,7 @@ PUBLISHED: static void list_cycles(ostream &out); static void list_states(ostream &out); static bool validate_states(); -#ifdef HAVE_PYTHON - static PyObject *get_states(); -#endif // HAVE_PYTHON + EXTENSION(static PyObject *get_states()); PUBLISHED: // These methods are intended for use by low-level code, but they're @@ -363,6 +359,7 @@ private: friend class GraphicsStateGuardian; friend class RenderAttribRegistry; + friend class Extension; }; INLINE ostream &operator << (ostream &out, const RenderState &state) { diff --git a/panda/src/pgraph/renderState_ext.cxx b/panda/src/pgraph/renderState_ext.cxx new file mode 100644 index 0000000000..70b214fbb3 --- /dev/null +++ b/panda/src/pgraph/renderState_ext.cxx @@ -0,0 +1,174 @@ +// Filename: renderState_ext.cxx +// Created by: CFSworks (31Mar14) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "renderState_ext.h" + +#ifdef HAVE_PYTHON + +//////////////////////////////////////////////////////////////////// +// Function: Extension::get_composition_cache +// Access: Published +// Description: Returns a list of 2-tuples that represents the +// composition cache. For each tuple in the list, the +// first element is the source render, and the second +// is the result render. If both are None, there is +// no entry in the cache at that slot. +// +// In general, a->compose(source) == result. +// +// This has no practical value other than for examining +// the cache for performance analysis. +//////////////////////////////////////////////////////////////////// +PyObject *Extension:: +get_composition_cache() const { + IMPORT_THIS struct Dtool_PyTypedObject Dtool_RenderState; + LightReMutexHolder holder(*RenderState::_states_lock); + size_t cache_size = _this->_composition_cache.get_size(); + PyObject *list = PyList_New(cache_size); + + for (size_t i = 0; i < cache_size; ++i) { + PyObject *tuple = PyTuple_New(2); + PyObject *a, *b; + if (!_this->_composition_cache.has_element(i)) { + a = Py_None; + Py_INCREF(a); + b = Py_None; + Py_INCREF(b); + } else { + const RenderState *source = _this->_composition_cache.get_key(i); + if (source == (RenderState *)NULL) { + a = Py_None; + Py_INCREF(a); + } else { + source->ref(); + a = DTool_CreatePyInstanceTyped((void *)source, Dtool_RenderState, + true, true, source->get_type_index()); + } + const RenderState *result = _this->_composition_cache.get_data(i)._result; + if (result == (RenderState *)NULL) { + b = Py_None; + Py_INCREF(b); + } else { + result->ref(); + b = DTool_CreatePyInstanceTyped((void *)result, Dtool_RenderState, + true, true, result->get_type_index()); + } + } + PyTuple_SET_ITEM(tuple, 0, a); + PyTuple_SET_ITEM(tuple, 1, b); + + PyList_SET_ITEM(list, i, tuple); + } + + return list; +} + +//////////////////////////////////////////////////////////////////// +// Function: Extension::get_invert_composition_cache +// Access: Published +// Description: Returns a list of 2-tuples that represents the +// invert_composition cache. For each tuple in the list, the +// first element is the source render, and the second +// is the result render. If both are None, there is +// no entry in the cache at that slot. +// +// In general, a->invert_compose(source) == result. +// +// This has no practical value other than for examining +// the cache for performance analysis. +//////////////////////////////////////////////////////////////////// +PyObject *Extension:: +get_invert_composition_cache() const { + IMPORT_THIS struct Dtool_PyTypedObject Dtool_RenderState; + LightReMutexHolder holder(*RenderState::_states_lock); + size_t cache_size = _this->_invert_composition_cache.get_size(); + PyObject *list = PyList_New(cache_size); + + for (size_t i = 0; i < cache_size; ++i) { + PyObject *tuple = PyTuple_New(2); + PyObject *a, *b; + if (!_this->_invert_composition_cache.has_element(i)) { + a = Py_None; + Py_INCREF(a); + b = Py_None; + Py_INCREF(b); + } else { + const RenderState *source = _this->_invert_composition_cache.get_key(i); + if (source == (RenderState *)NULL) { + a = Py_None; + Py_INCREF(a); + } else { + source->ref(); + a = DTool_CreatePyInstanceTyped((void *)source, Dtool_RenderState, + true, true, source->get_type_index()); + } + const RenderState *result = _this->_invert_composition_cache.get_data(i)._result; + if (result == (RenderState *)NULL) { + b = Py_None; + Py_INCREF(b); + } else { + result->ref(); + b = DTool_CreatePyInstanceTyped((void *)result, Dtool_RenderState, + true, true, result->get_type_index()); + } + } + PyTuple_SET_ITEM(tuple, 0, a); + PyTuple_SET_ITEM(tuple, 1, b); + + PyList_SET_ITEM(list, i, tuple); + } + + return list; +} + +//////////////////////////////////////////////////////////////////// +// Function: Extension::get_states +// Access: Published, Static +// Description: Returns a list of all of the RenderState objects +// in the state cache. The order of elements in this +// cache is arbitrary. +//////////////////////////////////////////////////////////////////// +PyObject *Extension:: +get_states() { + IMPORT_THIS struct Dtool_PyTypedObject Dtool_RenderState; + if (RenderState::_states == (RenderState::States *)NULL) { + return PyList_New(0); + } + LightReMutexHolder holder(*RenderState::_states_lock); + + size_t num_states = RenderState::_states->get_num_entries(); + PyObject *list = PyList_New(num_states); + size_t i = 0; + + int size = RenderState::_states->get_size(); + for (int si = 0; si < size; ++si) { + if (!RenderState::_states->has_element(si)) { + continue; + } + const RenderState *state = RenderState::_states->get_key(si); + state->ref(); + PyObject *a = + DTool_CreatePyInstanceTyped((void *)state, Dtool_RenderState, + true, true, state->get_type_index()); + nassertr(i < num_states, list); + PyList_SET_ITEM(list, i, a); + ++i; + } + nassertr(i == num_states, list); + return list; +} + + + +#endif // HAVE_PYTHON diff --git a/panda/src/pgraph/renderState_ext.h b/panda/src/pgraph/renderState_ext.h new file mode 100644 index 0000000000..43830e8021 --- /dev/null +++ b/panda/src/pgraph/renderState_ext.h @@ -0,0 +1,42 @@ +// Filename: renderState_ext.h +// Created by: CFSworks (31Mar14) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#ifndef RENDERSTATE_EXT_H +#define RENDERSTATE_EXT_H + +#include "dtoolbase.h" + +#ifdef HAVE_PYTHON + +#include "extension.h" +#include "renderState.h" +#include "py_panda.h" + +//////////////////////////////////////////////////////////////////// +// Class : Extension +// Description : This class defines the extension methods for +// RenderState, which are called instead of +// any C++ methods with the same prototype. +//////////////////////////////////////////////////////////////////// +template<> +class Extension : public ExtensionBase { +public: + PyObject *get_composition_cache() const; + PyObject *get_invert_composition_cache() const; + static PyObject *get_states(); +}; + +#endif // HAVE_PYTHON + +#endif // RENDERSTATE_EXT_H diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index e990cca0f1..84fa387080 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -818,134 +818,6 @@ validate_composition_cache() const { return true; } -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: TransformState::get_composition_cache -// Access: Published -// Description: Returns a list of 2-tuples that represents the -// composition cache. For each tuple in the list, the -// first element is the source transform, and the second -// is the result transform. If both are None, there is -// no entry in the cache at that slot. -// -// In general, a->compose(source) == result. -// -// This has no practical value other than for examining -// the cache for performance analysis. -//////////////////////////////////////////////////////////////////// -PyObject *TransformState:: -get_composition_cache() const { - IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; - LightReMutexHolder holder(*_states_lock); - - size_t num_states = _composition_cache.get_num_entries(); - PyObject *list = PyList_New(num_states); - size_t i = 0; - - int size = _composition_cache.get_size(); - for (int si = 0; si < size; ++si) { - if (!_composition_cache.has_element(si)) { - continue; - } - - PyObject *tuple = PyTuple_New(2); - PyObject *a, *b; - - const TransformState *source = _composition_cache.get_key(si); - if (source == (TransformState *)NULL) { - a = Py_None; - Py_INCREF(a); - } else { - source->ref(); - a = DTool_CreatePyInstanceTyped((void *)source, Dtool_TransformState, - true, true, source->get_type_index()); - } - const TransformState *result = _composition_cache.get_data(si)._result; - if (result == (TransformState *)NULL) { - b = Py_None; - Py_INCREF(b); - } else { - result->ref(); - b = DTool_CreatePyInstanceTyped((void *)result, Dtool_TransformState, - true, true, result->get_type_index()); - } - - PyTuple_SET_ITEM(tuple, 0, a); - PyTuple_SET_ITEM(tuple, 1, b); - - nassertr(i < num_states, list); - PyList_SET_ITEM(list, i, tuple); - ++i; - } - nassertr(i == num_states, list); - return list; -} -#endif // HAVE_PYTHON - -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: TransformState::get_invert_composition_cache -// Access: Published -// Description: Returns a list of 2-tuples that represents the -// invert_composition cache. For each tuple in the list, the -// first element is the source transform, and the second -// is the result transform. If both are None, there is -// no entry in the cache at that slot. -// -// In general, a->invert_compose(source) == result. -// -// This has no practical value other than for examining -// the cache for performance analysis. -//////////////////////////////////////////////////////////////////// -PyObject *TransformState:: -get_invert_composition_cache() const { - IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; - LightReMutexHolder holder(*_states_lock); - - size_t num_states = _invert_composition_cache.get_num_entries(); - PyObject *list = PyList_New(num_states); - size_t i = 0; - - int size = _invert_composition_cache.get_size(); - for (int si = 0; si < size; ++si) { - if (!_invert_composition_cache.has_element(si)) { - continue; - } - - PyObject *tuple = PyTuple_New(2); - PyObject *a, *b; - - const TransformState *source = _invert_composition_cache.get_key(si); - if (source == (TransformState *)NULL) { - a = Py_None; - Py_INCREF(a); - } else { - source->ref(); - a = DTool_CreatePyInstanceTyped((void *)source, Dtool_TransformState, - true, true, source->get_type_index()); - } - const TransformState *result = _invert_composition_cache.get_data(si)._result; - if (result == (TransformState *)NULL) { - b = Py_None; - Py_INCREF(b); - } else { - result->ref(); - b = DTool_CreatePyInstanceTyped((void *)result, Dtool_TransformState, - true, true, result->get_type_index()); - } - - PyTuple_SET_ITEM(tuple, 0, a); - PyTuple_SET_ITEM(tuple, 1, b); - - nassertr(i < num_states, list); - PyList_SET_ITEM(list, i, tuple); - ++i; - } - nassertr(i == num_states, list); - return list; -} -#endif // HAVE_PYTHON - //////////////////////////////////////////////////////////////////// // Function: TransformState::output // Access: Published @@ -1529,81 +1401,6 @@ validate_states() { return true; } -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: TransformState::get_states -// Access: Published, Static -// Description: Returns a list of all of the TransformState objects -// in the state cache. The order of elements in this -// cache is arbitrary. -//////////////////////////////////////////////////////////////////// -PyObject *TransformState:: -get_states() { - IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; - if (_states == (States *)NULL) { - return PyList_New(0); - } - LightReMutexHolder holder(*_states_lock); - - size_t num_states = _states->get_num_entries(); - PyObject *list = PyList_New(num_states); - size_t i = 0; - - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { - if (!_states->has_element(si)) { - continue; - } - const TransformState *state = _states->get_key(si); - state->ref(); - PyObject *a = - DTool_CreatePyInstanceTyped((void *)state, Dtool_TransformState, - true, true, state->get_type_index()); - nassertr(i < num_states, list); - PyList_SET_ITEM(list, i, a); - ++i; - } - nassertr(i == num_states, list); - return list; -} -#endif // HAVE_PYTHON - -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: TransformState::get_unused_states -// Access: Published, Static -// Description: Returns a list of all of the "unused" TransformState -// objects in the state cache. See -// get_num_unused_states(). -//////////////////////////////////////////////////////////////////// -PyObject *TransformState:: -get_unused_states() { - IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; - if (_states == (States *)NULL) { - return PyList_New(0); - } - LightReMutexHolder holder(*_states_lock); - - PyObject *list = PyList_New(0); - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { - if (!_states->has_element(si)) { - continue; - } - const TransformState *state = _states->get_key(si); - if (state->get_cache_ref_count() == state->get_ref_count()) { - state->ref(); - PyObject *a = - DTool_CreatePyInstanceTyped((void *)state, Dtool_TransformState, - true, true, state->get_type_index()); - PyList_Append(list, a); - Py_DECREF(a); - } - } - return list; -} -#endif // HAVE_PYTHON - //////////////////////////////////////////////////////////////////// // Function: TransformState::init_states // Access: Public, Static diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index 915eb7f504..e6e3223cb9 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -32,6 +32,7 @@ #include "deletedChain.h" #include "simpleHashMap.h" #include "cacheStats.h" +#include "extension.h" class GraphicsStateGuardianBase; class FactoryParams; @@ -190,10 +191,8 @@ PUBLISHED: INLINE const TransformState *get_invert_composition_cache_source(int n) const; INLINE const TransformState *get_invert_composition_cache_result(int n) const; bool validate_composition_cache() const; -#ifdef HAVE_PYTHON - PyObject *get_composition_cache() const; - PyObject *get_invert_composition_cache() const; -#endif // HAVE_PYTHON + EXTENSION(PyObject *get_composition_cache() const); + EXTENSION(PyObject *get_invert_composition_cache() const); void output(ostream &out) const; void write(ostream &out, int indent_level) const; @@ -206,10 +205,8 @@ PUBLISHED: static void list_cycles(ostream &out); static void list_states(ostream &out); static bool validate_states(); -#ifdef HAVE_PYTHON - static PyObject *get_states(); - static PyObject *get_unused_states(); -#endif // HAVE_PYTHON + EXTENSION(static PyObject *get_states()); + EXTENSION(static PyObject *get_unused_states()); public: @@ -405,6 +402,8 @@ public: private: static TypeHandle _type_handle; + + friend class Extension; }; INLINE ostream &operator << (ostream &out, const TransformState &state) { diff --git a/panda/src/pgraph/transformState_ext.cxx b/panda/src/pgraph/transformState_ext.cxx new file mode 100644 index 0000000000..c66fd87943 --- /dev/null +++ b/panda/src/pgraph/transformState_ext.cxx @@ -0,0 +1,214 @@ +// Filename: transformState_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 "transformState_ext.h" + +#ifdef HAVE_PYTHON + +//////////////////////////////////////////////////////////////////// +// Function: Extension::get_composition_cache +// Access: Published +// Description: Returns a list of 2-tuples that represents the +// composition cache. For each tuple in the list, the +// first element is the source transform, and the second +// is the result transform. If both are None, there is +// no entry in the cache at that slot. +// +// In general, a->compose(source) == result. +// +// This has no practical value other than for examining +// the cache for performance analysis. +//////////////////////////////////////////////////////////////////// +PyObject *Extension:: +get_composition_cache() const { + IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; + LightReMutexHolder holder(*_this->_states_lock); + + size_t num_states = _this->_composition_cache.get_num_entries(); + PyObject *list = PyList_New(num_states); + size_t i = 0; + + int size = _this->_composition_cache.get_size(); + for (int si = 0; si < size; ++si) { + if (!_this->_composition_cache.has_element(si)) { + continue; + } + + PyObject *tuple = PyTuple_New(2); + PyObject *a, *b; + + const TransformState *source = _this->_composition_cache.get_key(si); + if (source == (TransformState *)NULL) { + a = Py_None; + Py_INCREF(a); + } else { + source->ref(); + a = DTool_CreatePyInstanceTyped((void *)source, Dtool_TransformState, + true, true, source->get_type_index()); + } + const TransformState *result = _this->_composition_cache.get_data(si)._result; + if (result == (TransformState *)NULL) { + b = Py_None; + Py_INCREF(b); + } else { + result->ref(); + b = DTool_CreatePyInstanceTyped((void *)result, Dtool_TransformState, + true, true, result->get_type_index()); + } + + PyTuple_SET_ITEM(tuple, 0, a); + PyTuple_SET_ITEM(tuple, 1, b); + + nassertr(i < num_states, list); + PyList_SET_ITEM(list, i, tuple); + ++i; + } + nassertr(i == num_states, list); + return list; +} + +//////////////////////////////////////////////////////////////////// +// Function: Extension::get_invert_composition_cache +// Access: Published +// Description: Returns a list of 2-tuples that represents the +// invert_composition cache. For each tuple in the list, the +// first element is the source transform, and the second +// is the result transform. If both are None, there is +// no entry in the cache at that slot. +// +// In general, a->invert_compose(source) == result. +// +// This has no practical value other than for examining +// the cache for performance analysis. +//////////////////////////////////////////////////////////////////// +PyObject *Extension:: +get_invert_composition_cache() const { + IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; + LightReMutexHolder holder(*_this->_states_lock); + + size_t num_states = _this->_invert_composition_cache.get_num_entries(); + PyObject *list = PyList_New(num_states); + size_t i = 0; + + int size = _this->_invert_composition_cache.get_size(); + for (int si = 0; si < size; ++si) { + if (!_this->_invert_composition_cache.has_element(si)) { + continue; + } + + PyObject *tuple = PyTuple_New(2); + PyObject *a, *b; + + const TransformState *source = _this->_invert_composition_cache.get_key(si); + if (source == (TransformState *)NULL) { + a = Py_None; + Py_INCREF(a); + } else { + source->ref(); + a = DTool_CreatePyInstanceTyped((void *)source, Dtool_TransformState, + true, true, source->get_type_index()); + } + const TransformState *result = _this->_invert_composition_cache.get_data(si)._result; + if (result == (TransformState *)NULL) { + b = Py_None; + Py_INCREF(b); + } else { + result->ref(); + b = DTool_CreatePyInstanceTyped((void *)result, Dtool_TransformState, + true, true, result->get_type_index()); + } + + PyTuple_SET_ITEM(tuple, 0, a); + PyTuple_SET_ITEM(tuple, 1, b); + + nassertr(i < num_states, list); + PyList_SET_ITEM(list, i, tuple); + ++i; + } + nassertr(i == num_states, list); + return list; +} + +//////////////////////////////////////////////////////////////////// +// Function: Extension::get_states +// Access: Published, Static +// Description: Returns a list of all of the TransformState objects +// in the state cache. The order of elements in this +// cache is arbitrary. +//////////////////////////////////////////////////////////////////// +PyObject *Extension:: +get_states() { + IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; + if (TransformState::_states == (TransformState::States *)NULL) { + return PyList_New(0); + } + LightReMutexHolder holder(*TransformState::_states_lock); + + size_t num_states = TransformState::_states->get_num_entries(); + PyObject *list = PyList_New(num_states); + size_t i = 0; + + int size = TransformState::_states->get_size(); + for (int si = 0; si < size; ++si) { + if (!TransformState::_states->has_element(si)) { + continue; + } + const TransformState *state = TransformState::_states->get_key(si); + state->ref(); + PyObject *a = + DTool_CreatePyInstanceTyped((void *)state, Dtool_TransformState, + true, true, state->get_type_index()); + nassertr(i < num_states, list); + PyList_SET_ITEM(list, i, a); + ++i; + } + nassertr(i == num_states, list); + return list; +} + +//////////////////////////////////////////////////////////////////// +// Function: Extension::get_unused_states +// Access: Published, Static +// Description: Returns a list of all of the "unused" TransformState +// objects in the state cache. See +// get_num_unused_states(). +//////////////////////////////////////////////////////////////////// +PyObject *Extension:: +get_unused_states() { + IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; + if (TransformState::_states == (TransformState::States *)NULL) { + return PyList_New(0); + } + LightReMutexHolder holder(*TransformState::_states_lock); + + PyObject *list = PyList_New(0); + int size = TransformState::_states->get_size(); + for (int si = 0; si < size; ++si) { + if (!TransformState::_states->has_element(si)) { + continue; + } + const TransformState *state = TransformState::_states->get_key(si); + if (state->get_cache_ref_count() == state->get_ref_count()) { + state->ref(); + PyObject *a = + DTool_CreatePyInstanceTyped((void *)state, Dtool_TransformState, + true, true, state->get_type_index()); + PyList_Append(list, a); + Py_DECREF(a); + } + } + return list; +} + +#endif // HAVE_PYTHON diff --git a/panda/src/pgraph/transformState_ext.h b/panda/src/pgraph/transformState_ext.h new file mode 100644 index 0000000000..81f3312eb6 --- /dev/null +++ b/panda/src/pgraph/transformState_ext.h @@ -0,0 +1,43 @@ +// Filename: transformState_ext.h +// Created by: CFSworks (31Mar14) +// +//////////////////////////////////////////////////////////////////// +// +// 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." +// +//////////////////////////////////////////////////////////////////// + +#ifndef TRANSFORMSTATE_EXT_H +#define TRANSFORMSTATE_EXT_H + +#include "dtoolbase.h" + +#ifdef HAVE_PYTHON + +#include "extension.h" +#include "transformState.h" +#include "py_panda.h" + +//////////////////////////////////////////////////////////////////// +// Class : Extension +// Description : This class defines the extension methods for +// TransformState, which are called instead of +// any C++ methods with the same prototype. +//////////////////////////////////////////////////////////////////// +template<> +class Extension : public ExtensionBase { +public: + PyObject *get_composition_cache() const; + PyObject *get_invert_composition_cache() const; + static PyObject *get_states(); + static PyObject *get_unused_states(); +}; + +#endif // HAVE_PYTHON + +#endif // TRANSFORMSTATE_EXT_H