Browse Source

Merge branch 'master' into deploy-ng

rdb 7 years ago
parent
commit
cf65010a54
45 changed files with 1249 additions and 1468 deletions
  1. 4 2
      .travis.yml
  2. 0 2
      dtool/src/dtoolbase/dtoolbase.h
  3. 15 0
      dtool/src/dtoolbase/typeHandle.cxx
  4. 4 0
      dtool/src/dtoolbase/typeHandle.h
  5. 2 1
      dtool/src/dtoolbase/typeHandle_ext.cxx
  6. 18 0
      dtool/src/dtoolbase/typeRegistry.cxx
  7. 3 0
      dtool/src/dtoolbase/typeRegistry.h
  8. 13 0
      dtool/src/dtoolbase/typeRegistryNode.I
  9. 23 0
      dtool/src/dtoolbase/typeRegistryNode.cxx
  10. 5 0
      dtool/src/dtoolbase/typeRegistryNode.h
  11. 75 41
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  12. 0 3
      dtool/src/interrogate/interrogate.cxx
  13. 9 14
      dtool/src/interrogate/interrogate_module.cxx
  14. 0 3
      dtool/src/interrogate/parse_file.cxx
  15. 103 91
      dtool/src/interrogatedb/dtool_super_base.cxx
  16. 0 1
      dtool/src/interrogatedb/p3interrogatedb_composite1.cxx
  17. 0 3
      dtool/src/interrogatedb/p3interrogatedb_composite2.cxx
  18. 0 7
      dtool/src/interrogatedb/py_compat.cxx
  19. 1 8
      dtool/src/interrogatedb/py_compat.h
  20. 17 12
      dtool/src/interrogatedb/py_panda.I
  21. 48 174
      dtool/src/interrogatedb/py_panda.cxx
  22. 42 53
      dtool/src/interrogatedb/py_panda.h
  23. 299 674
      dtool/src/interrogatedb/py_wrappers.cxx
  24. 6 23
      dtool/src/interrogatedb/py_wrappers.h
  25. 8 0
      dtool/src/pystub/pystub.cxx
  26. 0 3
      dtool/src/test_interrogate/test_interrogate.cxx
  27. 16 5
      makepanda/installer.nsi
  28. 6 1
      makepanda/installpanda.py
  29. 218 266
      makepanda/makepanda.py
  30. 128 9
      makepanda/makepandacore.py
  31. 30 17
      makepanda/makewheel.py
  32. 1 1
      panda/src/audiotraits/fmodAudioSound.cxx
  33. 1 1
      panda/src/audiotraits/fmodAudioSound.h
  34. 1 8
      panda/src/event/asyncFuture_ext.cxx
  35. 72 0
      panda/src/glstuff/glShaderContext_src.cxx
  36. 1 5
      panda/src/gobj/internalName.h
  37. 12 2
      panda/src/gobj/internalName_ext.cxx
  38. 1 5
      panda/src/gobj/internalName_ext.h
  39. 1 3
      panda/src/ode/odeBody.I
  40. 4 23
      panda/src/ode/odeBody.cxx
  41. 8 7
      panda/src/ode/odeBody.h
  42. 13 0
      panda/src/ode/odeBody_ext.I
  43. 37 0
      panda/src/ode/odeBody_ext.cxx
  44. 3 0
      panda/src/ode/odeBody_ext.h
  45. 1 0
      panda/src/ode/p3ode_ext_composite.cxx

+ 4 - 2
.travis.yml

@@ -11,6 +11,8 @@ matrix:
       before_install:
       before_install:
         - export CC=gcc-4.7
         - export CC=gcc-4.7
         - export CXX=g++-4.7
         - export CXX=g++-4.7
+    - compiler: clang
+      env: PYTHONV=python3 FLAGS=--no-python SKIP_TESTS=1
 addons:
 addons:
   apt:
   apt:
     sources:
     sources:
@@ -42,8 +44,8 @@ install:
     - $PYTHONV -m pip install pytest
     - $PYTHONV -m pip install pytest
 script:
 script:
     - $PYTHONV makepanda/makepanda.py --everything --git-commit $TRAVIS_COMMIT $FLAGS --threads 4
     - $PYTHONV makepanda/makepanda.py --everything --git-commit $TRAVIS_COMMIT $FLAGS --threads 4
-    - LD_LIBRARY_PATH=built/lib PYTHONPATH=built $PYTHONV makepanda/test_imports.py
-    - LD_LIBRARY_PATH=built/lib PYTHONPATH=built $PYTHONV -m pytest -v tests
+    - test -n "$SKIP_TESTS" || LD_LIBRARY_PATH=built/lib PYTHONPATH=built $PYTHONV makepanda/test_imports.py
+    - test -n "$SKIP_TESTS" || LD_LIBRARY_PATH=built/lib PYTHONPATH=built $PYTHONV -m pytest -v tests
 notifications:
 notifications:
   irc:
   irc:
     channels:
     channels:

+ 0 - 2
dtool/src/dtoolbase/dtoolbase.h

@@ -138,12 +138,10 @@
 #endif
 #endif
 #endif
 #endif
 
 
-#ifdef HAVE_PYTHON
 // Instead of including the Python headers, which will implicitly add a linker
 // Instead of including the Python headers, which will implicitly add a linker
 // flag to link in Python, we'll just excerpt the forward declaration of
 // flag to link in Python, we'll just excerpt the forward declaration of
 // PyObject.
 // PyObject.
 typedef struct _object PyObject;
 typedef struct _object PyObject;
-#endif
 
 
 #ifndef HAVE_EIGEN
 #ifndef HAVE_EIGEN
 // If we don't have the Eigen library, don't define LINMATH_ALIGN.
 // If we don't have the Eigen library, don't define LINMATH_ALIGN.

+ 15 - 0
dtool/src/dtoolbase/typeHandle.cxx

@@ -153,6 +153,21 @@ deallocate_array(void *ptr) {
   PANDA_FREE_ARRAY(ptr);
   PANDA_FREE_ARRAY(ptr);
 }
 }
 
 
+#ifdef HAVE_PYTHON
+/**
+ * Returns the internal void pointer that is stored for interrogate's benefit.
+ */
+PyObject *TypeHandle::
+get_python_type() const {
+  TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, nullptr);
+  if (rnode != nullptr) {
+    return rnode->get_python_type();
+  } else {
+    return nullptr;
+  }
+}
+#endif
+
 /**
 /**
  * Return the Index of the BEst fit Classs from a set
  * Return the Index of the BEst fit Classs from a set
  */
  */

+ 4 - 0
dtool/src/dtoolbase/typeHandle.h

@@ -138,6 +138,10 @@ PUBLISHED:
   MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
   MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
 
 
 public:
 public:
+#ifdef HAVE_PYTHON
+  PyObject *get_python_type() const;
+#endif
+
   void *allocate_array(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
   void *allocate_array(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
   void *reallocate_array(void *ptr, size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
   void *reallocate_array(void *ptr, size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
   void deallocate_array(void *ptr);
   void deallocate_array(void *ptr);

+ 2 - 1
dtool/src/dtoolbase/typeHandle_ext.cxx

@@ -22,7 +22,8 @@
  */
  */
 TypeHandle Extension<TypeHandle>::
 TypeHandle Extension<TypeHandle>::
 make(PyTypeObject *tp) {
 make(PyTypeObject *tp) {
-  if (!PyType_IsSubtype(tp, &Dtool_DTOOL_SUPER_BASE._PyType)) {
+  Dtool_PyTypedObject *super_base = Dtool_GetSuperBase();
+  if (!PyType_IsSubtype(tp, (PyTypeObject *)super_base)) {
     PyErr_SetString(PyExc_TypeError, "a Panda type is required");
     PyErr_SetString(PyExc_TypeError, "a Panda type is required");
     return TypeHandle::none();
     return TypeHandle::none();
   }
   }

+ 18 - 0
dtool/src/dtoolbase/typeRegistry.cxx

@@ -207,6 +207,24 @@ record_alternate_name(TypeHandle type, const string &name) {
   _lock->unlock();
   _lock->unlock();
 }
 }
 
 
+#ifdef HAVE_PYTHON
+/**
+ * Records the given Python type pointer in the type registry for the benefit
+ * of interrogate.
+ */
+void TypeRegistry::
+record_python_type(TypeHandle type, PyObject *python_type) {
+  _lock->lock();
+
+  TypeRegistryNode *rnode = look_up(type, nullptr);
+  if (rnode != nullptr) {
+    rnode->_python_type = python_type;
+  }
+
+  _lock->unlock();
+}
+#endif
+
 /**
 /**
  * Looks for a previously-registered type of the given name.  Returns its
  * Looks for a previously-registered type of the given name.  Returns its
  * TypeHandle if it exists, or TypeHandle::none() if there is no such type.
  * TypeHandle if it exists, or TypeHandle::none() if there is no such type.

+ 3 - 0
dtool/src/dtoolbase/typeRegistry.h

@@ -45,6 +45,9 @@ PUBLISHED:
 
 
   void record_derivation(TypeHandle child, TypeHandle parent);
   void record_derivation(TypeHandle child, TypeHandle parent);
   void record_alternate_name(TypeHandle type, const std::string &name);
   void record_alternate_name(TypeHandle type, const std::string &name);
+#ifdef HAVE_PYTHON
+  void record_python_type(TypeHandle type, PyObject *python_type);
+#endif
 
 
   TypeHandle find_type(const std::string &name) const;
   TypeHandle find_type(const std::string &name) const;
   TypeHandle find_type_by_id(int id) const;
   TypeHandle find_type_by_id(int id) const;

+ 13 - 0
dtool/src/dtoolbase/typeRegistryNode.I

@@ -11,6 +11,19 @@
  * @date 2001-08-06
  * @date 2001-08-06
  */
  */
 
 
+/**
+ * Returns the Python type object associated with this node.
+ */
+INLINE PyObject *TypeRegistryNode::
+get_python_type() const {
+  if (_python_type != nullptr || _parent_classes.empty()) {
+    return _python_type;
+  } else {
+    // Recurse through parent classes.
+    return r_get_python_type();
+  }
+}
+
 /**
 /**
  *
  *
  */
  */

+ 23 - 0
dtool/src/dtoolbase/typeRegistryNode.cxx

@@ -308,6 +308,29 @@ r_build_subtrees(TypeRegistryNode *top, int bit_count,
   }
   }
 }
 }
 
 
+/**
+ * Recurses through the parent nodes to find the best Python type object to
+ * represent objects of this type.
+ */
+PyObject *TypeRegistryNode::
+r_get_python_type() const {
+  Classes::const_iterator ni;
+  for (ni = _parent_classes.begin(); ni != _parent_classes.end(); ++ni) {
+    const TypeRegistryNode *parent = *ni;
+    if (parent->_python_type != nullptr) {
+      return parent->_python_type;
+
+    } else if (!parent->_parent_classes.empty()) {
+      PyObject *py_type = parent->r_get_python_type();
+      if (py_type != nullptr) {
+        return py_type;
+      }
+    }
+  }
+
+  return nullptr;
+}
+
 /**
 /**
  * A recursive function to double-check the result of is_derived_from().  This
  * A recursive function to double-check the result of is_derived_from().  This
  * is the slow, examine-the-whole-graph approach, as opposed to the clever and
  * is the slow, examine-the-whole-graph approach, as opposed to the clever and

+ 5 - 0
dtool/src/dtoolbase/typeRegistryNode.h

@@ -37,6 +37,8 @@ public:
   static TypeHandle get_parent_towards(const TypeRegistryNode *child,
   static TypeHandle get_parent_towards(const TypeRegistryNode *child,
                                        const TypeRegistryNode *base);
                                        const TypeRegistryNode *base);
 
 
+  INLINE PyObject *get_python_type() const;
+
   void clear_subtree();
   void clear_subtree();
   void define_subtree();
   void define_subtree();
 
 
@@ -46,6 +48,7 @@ public:
   typedef std::vector<TypeRegistryNode *> Classes;
   typedef std::vector<TypeRegistryNode *> Classes;
   Classes _parent_classes;
   Classes _parent_classes;
   Classes _child_classes;
   Classes _child_classes;
+  PyObject *_python_type = nullptr;
 
 
   AtomicAdjust::Integer _memory_usage[TypeHandle::MC_limit];
   AtomicAdjust::Integer _memory_usage[TypeHandle::MC_limit];
 
 
@@ -77,6 +80,8 @@ private:
   void r_build_subtrees(TypeRegistryNode *top,
   void r_build_subtrees(TypeRegistryNode *top,
                         int bit_count, SubtreeMaskType bits);
                         int bit_count, SubtreeMaskType bits);
 
 
+  PyObject *r_get_python_type() const;
+
   static bool check_derived_from(const TypeRegistryNode *child,
   static bool check_derived_from(const TypeRegistryNode *child,
                                  const TypeRegistryNode *base);
                                  const TypeRegistryNode *base);
 
 

+ 75 - 41
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -821,10 +821,54 @@ write_prototypes(ostream &out_code, ostream *out_h) {
     }
     }
   }
   }
 
 
+  out_code << "/**\n";
+  out_code << " * Declarations for exported classes\n";
+  out_code << " */\n";
+
+  out_code << "static const Dtool_TypeDef exports[] = {\n";
+
+  for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
+    Object *object = (*oi).second;
+
+    if (object->_itype.is_class() || object->_itype.is_struct()) {
+      CPPType *type = object->_itype._cpptype;
+
+      if (isExportThisRun(type) && is_cpp_type_legal(type)) {
+        string class_name = type->get_local_name(&parser);
+        string safe_name = make_safe_name(class_name);
+
+        out_code << "  {\"" << class_name << "\", &Dtool_" << safe_name << "},\n";
+      }
+    }
+  }
+
+  out_code << "  {nullptr, nullptr},\n";
+  out_code << "};\n\n";
+
   out_code << "/**\n";
   out_code << "/**\n";
   out_code << " * Extern declarations for imported classes\n";
   out_code << " * Extern declarations for imported classes\n";
   out_code << " */\n";
   out_code << " */\n";
 
 
+  // Write out a table of the externally imported types that will be filled in
+  // upon module initialization.
+  if (!_external_imports.empty()) {
+    out_code << "#ifndef LINK_ALL_STATIC\n";
+    out_code << "static Dtool_TypeDef imports[] = {\n";
+
+    int idx = 0;
+    for (CPPType *type : _external_imports) {
+      string class_name = type->get_local_name(&parser);
+      string safe_name = make_safe_name(class_name);
+
+      out_code << "  {\"" << class_name << "\", nullptr},\n";
+      out_code << "#define Dtool_Ptr_" << safe_name << " (imports[" << idx << "].type)\n";
+      ++idx;
+    }
+    out_code << "  {nullptr, nullptr},\n";
+    out_code << "};\n";
+    out_code << "#endif\n\n";
+  }
+
   for (CPPType *type : _external_imports) {
   for (CPPType *type : _external_imports) {
     string class_name = type->get_local_name(&parser);
     string class_name = type->get_local_name(&parser);
     string safe_name = make_safe_name(class_name);
     string safe_name = make_safe_name(class_name);
@@ -834,7 +878,9 @@ write_prototypes(ostream &out_code, ostream *out_h) {
     out_code << "#ifndef LINK_ALL_STATIC\n";
     out_code << "#ifndef LINK_ALL_STATIC\n";
     // out_code << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" <<
     // out_code << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" <<
     // safe_name << ";\n";
     // safe_name << ";\n";
-    out_code << "static struct Dtool_PyTypedObject *Dtool_Ptr_" << safe_name << ";\n";
+    //if (has_get_class_type_function(type)) {
+    //  out_code << "static struct Dtool_PyTypedObject *Dtool_Ptr_" << safe_name << ";\n";
+    //}
     // out_code << "#define Dtool_Ptr_" << safe_name << " &Dtool_" <<
     // out_code << "#define Dtool_Ptr_" << safe_name << " &Dtool_" <<
     // safe_name << "\n"; out_code << "IMPORT_THIS void
     // safe_name << "\n"; out_code << "IMPORT_THIS void
     // Dtool_PyModuleClassInit_" << safe_name << "(PyObject *module);\n";
     // Dtool_PyModuleClassInit_" << safe_name << "(PyObject *module);\n";
@@ -1258,36 +1304,36 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
 
 
   Objects::iterator oi;
   Objects::iterator oi;
 
 
-  out << "void Dtool_" << def->library_name << "_RegisterTypes() {\n";
+  out << "void Dtool_" << def->library_name << "_RegisterTypes() {\n"
+         "  TypeRegistry *registry = TypeRegistry::ptr();\n"
+         "  nassertv(registry != nullptr);\n";
+
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     Object *object = (*oi).second;
     Object *object = (*oi).second;
-    if (object->_itype.is_class() ||
-        object->_itype.is_struct()) {
-      if (is_cpp_type_legal(object->_itype._cpptype) &&
-          isExportThisRun(object->_itype._cpptype)) {
-        string class_name = make_safe_name(object->_itype.get_scoped_name());
-        bool is_typed = has_get_class_type_function(object->_itype._cpptype);
+    if (object->_itype.is_class() || object->_itype.is_struct()) {
+      CPPType *type = object->_itype._cpptype;
+      if (is_cpp_type_legal(type) && isExportThisRun(type)) {
+        string class_name = object->_itype.get_scoped_name();
+        string safe_name = make_safe_name(class_name);
+        bool is_typed = has_get_class_type_function(type);
 
 
         if (is_typed) {
         if (is_typed) {
-          if (has_init_type_function(object->_itype._cpptype)) {
+          out << "  {\n";
+          if (has_init_type_function(type)) {
             // Call the init_type function.  This isn't necessary for all
             // Call the init_type function.  This isn't necessary for all
             // types as many of them are automatically initialized at static
             // types as many of them are automatically initialized at static
             // init type, but for some extension classes it's useful.
             // init type, but for some extension classes it's useful.
-            out << "  " << object->_itype._cpptype->get_local_name(&parser)
+            out << "    " << type->get_local_name(&parser)
                 << "::init_type();\n";
                 << "::init_type();\n";
           }
           }
-          out << "  Dtool_" << class_name << "._type = "
-              << object->_itype._cpptype->get_local_name(&parser)
-              << "::get_class_type();\n"
-              << "  RegisterRuntimeTypedClass(Dtool_" << class_name << ");\n";
-
+          out << "    TypeHandle handle = " << type->get_local_name(&parser)
+              << "::get_class_type();\n";
+          out << "    Dtool_" << safe_name << "._type = handle;\n";
+          out << "    registry->record_python_type(handle, "
+                 "(PyObject *)&Dtool_" << safe_name << ");\n";
+          out << "  }\n";
         } else {
         } else {
-          out << "#ifndef LINK_ALL_STATIC\n"
-              << "  RegisterNamedClass(\"" << object->_itype.get_scoped_name()
-              << "\", Dtool_" << class_name << ");\n"
-              << "#endif\n";
-
-          if (IsPandaTypedObject(object->_itype._cpptype->as_struct_type())) {
+          if (IsPandaTypedObject(type->as_struct_type())) {
             nout << object->_itype.get_scoped_name() << " derives from TypedObject, "
             nout << object->_itype.get_scoped_name() << " derives from TypedObject, "
                  << "but does not define a get_class_type() function.\n";
                  << "but does not define a get_class_type() function.\n";
           }
           }
@@ -1297,23 +1343,6 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
   }
   }
   out << "}\n\n";
   out << "}\n\n";
 
 
-  out << "void Dtool_" << def->library_name << "_ResolveExternals() {\n";
-  out << "#ifndef LINK_ALL_STATIC\n";
-  out << "  // Resolve externally imported types.\n";
-
-  for (CPPType *type : _external_imports) {
-    string class_name = type->get_local_name(&parser);
-    string safe_name = make_safe_name(class_name);
-
-    if (has_get_class_type_function(type)) {
-      out << "  Dtool_Ptr_" << safe_name << " = LookupRuntimeTypedClass(" << class_name << "::get_class_type());\n";
-    } else {
-      out << "  Dtool_Ptr_" << safe_name << " = LookupNamedClass(\"" << class_name << "\");\n";
-    }
-  }
-  out << "#endif\n";
-  out << "}\n\n";
-
   out << "void Dtool_" << def->library_name << "_BuildInstants(PyObject *module) {\n";
   out << "void Dtool_" << def->library_name << "_BuildInstants(PyObject *module) {\n";
   out << "  (void) module;\n";
   out << "  (void) module;\n";
 
 
@@ -1466,9 +1495,14 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
 
 
   out << "  {nullptr, nullptr, 0, nullptr}\n" << "};\n\n";
   out << "  {nullptr, nullptr, 0, nullptr}\n" << "};\n\n";
 
 
-  out << "struct LibraryDef " << def->library_name << "_moddef = {python_simple_funcs};\n";
+  out << "extern const struct LibraryDef " << def->library_name << "_moddef = {python_simple_funcs, exports, ";
+  if (_external_imports.empty()) {
+    out << "nullptr};\n";
+  } else {
+    out << "imports};\n";
+  }
   if (out_h != nullptr) {
   if (out_h != nullptr) {
-    *out_h << "extern struct LibraryDef " << def->library_name << "_moddef;\n";
+    *out_h << "extern const struct LibraryDef " << def->library_name << "_moddef;\n";
   }
   }
 }
 }
 
 
@@ -3063,7 +3097,7 @@ write_module_class(ostream &out, Object *obj) {
 
 
     out << "    Dtool_" << ClassName << "._PyType.tp_bases = PyTuple_Pack(" << bases.size() << baseargs << ");\n";
     out << "    Dtool_" << ClassName << "._PyType.tp_bases = PyTuple_Pack(" << bases.size() << baseargs << ");\n";
   } else {
   } else {
-    out << "    Dtool_" << ClassName << "._PyType.tp_base = (PyTypeObject *)&Dtool_DTOOL_SUPER_BASE;\n";
+    out << "    Dtool_" << ClassName << "._PyType.tp_base = (PyTypeObject *)Dtool_GetSuperBase();\n";
   }
   }
 
 
   int num_nested = obj->_itype.number_of_nested_types();
   int num_nested = obj->_itype.number_of_nested_types();

+ 0 - 3
dtool/src/interrogate/interrogate.cxx

@@ -19,7 +19,6 @@
 #include "pnotify.h"
 #include "pnotify.h"
 #include "panda_getopt_long.h"
 #include "panda_getopt_long.h"
 #include "preprocess_argv.h"
 #include "preprocess_argv.h"
-#include "pystub.h"
 #include <time.h>
 #include <time.h>
 
 
 using std::cerr;
 using std::cerr;
@@ -309,8 +308,6 @@ predefine_macro(CPPParser& parser, const string& inoption) {
 
 
 int
 int
 main(int argc, char **argv) {
 main(int argc, char **argv) {
-  pystub();
-
   preprocess_argv(argc, argv);
   preprocess_argv(argc, argv);
   string command_line;
   string command_line;
   int i;
   int i;

+ 9 - 14
dtool/src/interrogate/interrogate_module.cxx

@@ -19,7 +19,6 @@
 #include "interrogate_interface.h"
 #include "interrogate_interface.h"
 #include "interrogate_request.h"
 #include "interrogate_request.h"
 #include "load_dso.h"
 #include "load_dso.h"
-#include "pystub.h"
 #include "pnotify.h"
 #include "pnotify.h"
 #include "panda_getopt_long.h"
 #include "panda_getopt_long.h"
 #include "preprocess_argv.h"
 #include "preprocess_argv.h"
@@ -30,6 +29,9 @@
 using std::cerr;
 using std::cerr;
 using std::string;
 using std::string;
 
 
+// This contains a big source string determined at compile time.
+extern const char interrogate_preamble_python_native[];
+
 Filename output_code_filename;
 Filename output_code_filename;
 string module_name;
 string module_name;
 string library_name;
 string library_name;
@@ -286,9 +288,8 @@ int write_python_table_native(std::ostream &out) {
   vector_string::const_iterator ii;
   vector_string::const_iterator ii;
   for (ii = libraries.begin(); ii != libraries.end(); ++ii) {
   for (ii = libraries.begin(); ii != libraries.end(); ++ii) {
     printf("Referencing Library %s\n", (*ii).c_str());
     printf("Referencing Library %s\n", (*ii).c_str());
-    out << "extern LibraryDef " << *ii << "_moddef;\n";
+    out << "extern const struct LibraryDef " << *ii << "_moddef;\n";
     out << "extern void Dtool_" << *ii << "_RegisterTypes();\n";
     out << "extern void Dtool_" << *ii << "_RegisterTypes();\n";
-    out << "extern void Dtool_" << *ii << "_ResolveExternals();\n";
     out << "extern void Dtool_" << *ii << "_BuildInstants(PyObject *module);\n";
     out << "extern void Dtool_" << *ii << "_BuildInstants(PyObject *module);\n";
   }
   }
 
 
@@ -339,12 +340,9 @@ int write_python_table_native(std::ostream &out) {
   for (ii = libraries.begin(); ii != libraries.end(); ii++) {
   for (ii = libraries.begin(); ii != libraries.end(); ii++) {
     out << "  Dtool_" << *ii << "_RegisterTypes();\n";
     out << "  Dtool_" << *ii << "_RegisterTypes();\n";
   }
   }
-  for (ii = libraries.begin(); ii != libraries.end(); ii++) {
-    out << "  Dtool_" << *ii << "_ResolveExternals();\n";
-  }
   out << "\n";
   out << "\n";
 
 
-  out << "  LibraryDef *defs[] = {";
+  out << "  const LibraryDef *defs[] = {";
   for(ii = libraries.begin(); ii != libraries.end(); ii++) {
   for(ii = libraries.begin(); ii != libraries.end(); ii++) {
     out << "&" << *ii << "_moddef, ";
     out << "&" << *ii << "_moddef, ";
   }
   }
@@ -386,12 +384,9 @@ int write_python_table_native(std::ostream &out) {
   for (ii = libraries.begin(); ii != libraries.end(); ii++) {
   for (ii = libraries.begin(); ii != libraries.end(); ii++) {
     out << "  Dtool_" << *ii << "_RegisterTypes();\n";
     out << "  Dtool_" << *ii << "_RegisterTypes();\n";
   }
   }
-  for (ii = libraries.begin(); ii != libraries.end(); ii++) {
-    out << "  Dtool_" << *ii << "_ResolveExternals();\n";
-  }
   out << "\n";
   out << "\n";
 
 
-  out << "  LibraryDef *defs[] = {";
+  out << "  const LibraryDef *defs[] = {";
   for(ii = libraries.begin(); ii != libraries.end(); ii++) {
   for(ii = libraries.begin(); ii != libraries.end(); ii++) {
     out << "&" << *ii << "_moddef, ";
     out << "&" << *ii << "_moddef, ";
   }
   }
@@ -545,8 +540,6 @@ int main(int argc, char *argv[]) {
   extern int optind;
   extern int optind;
   int flag;
   int flag;
 
 
-  pystub();
-
   preprocess_argv(argc, argv);
   preprocess_argv(argc, argv);
   flag = getopt_long_only(argc, argv, short_options, long_options, nullptr);
   flag = getopt_long_only(argc, argv, short_options, long_options, nullptr);
   while (flag != EOF) {
   while (flag != EOF) {
@@ -642,8 +635,10 @@ int main(int argc, char *argv[]) {
 
 
       if (build_python_native_wrappers) {
       if (build_python_native_wrappers) {
         write_python_table_native(output_code);
         write_python_table_native(output_code);
-      }
 
 
+        // Output the support code.
+        output_code << interrogate_preamble_python_native << "\n";
+      }
     }
     }
   }
   }
 
 

+ 0 - 3
dtool/src/interrogate/parse_file.cxx

@@ -22,7 +22,6 @@
 #include "cppGlobals.h"
 #include "cppGlobals.h"
 #include "panda_getopt_long.h"
 #include "panda_getopt_long.h"
 #include "preprocess_argv.h"
 #include "preprocess_argv.h"
-#include "pystub.h"
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 using std::cerr;
 using std::cerr;
@@ -206,8 +205,6 @@ show_nested_types(const string &str) {
 
 
 int
 int
 main(int argc, char **argv) {
 main(int argc, char **argv) {
-  pystub();
-
   extern char *optarg;
   extern char *optarg;
   extern int optind;
   extern int optind;
   const char *optstr = "I:S:D:o:l:vp";
   const char *optstr = "I:S:D:o:l:vp";

+ 103 - 91
dtool/src/interrogatedb/dtool_super_base.cxx

@@ -15,120 +15,132 @@
 
 
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
 
 
-class EmptyClass {
-};
-Define_Module_Class_Private(dtoolconfig, DTOOL_SUPER_BASE, EmptyClass, DTOOL_SUPER_BASE111);
-
 static PyObject *GetSuperBase(PyObject *self) {
 static PyObject *GetSuperBase(PyObject *self) {
-  Py_INCREF((PyTypeObject *)&Dtool_DTOOL_SUPER_BASE); // order is important .. this is used for static functions
-  return (PyObject *) &Dtool_DTOOL_SUPER_BASE;
-};
-
-PyMethodDef Dtool_Methods_DTOOL_SUPER_BASE[] = {
-  { "DtoolGetSuperBase", (PyCFunction) &GetSuperBase, METH_NOARGS, "Will Return SUPERbase Class"},
-  { nullptr, nullptr, 0, nullptr }
+  Dtool_PyTypedObject *super_base = Dtool_GetSuperBase();
+  Py_XINCREF((PyTypeObject *)super_base); // order is important .. this is used for static functions
+  return (PyObject *)super_base;
 };
 };
 
 
-EXPCL_INTERROGATEDB void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module) {
-  static bool initdone = false;
-  if (!initdone) {
-
-    initdone = true;
-    Dtool_DTOOL_SUPER_BASE._PyType.tp_dict = PyDict_New();
-    PyDict_SetItemString(Dtool_DTOOL_SUPER_BASE._PyType.tp_dict, "DtoolClassDict", Dtool_DTOOL_SUPER_BASE._PyType.tp_dict);
-
-    if (PyType_Ready((PyTypeObject *)&Dtool_DTOOL_SUPER_BASE) < 0) {
-      PyErr_SetString(PyExc_TypeError, "PyType_Ready(Dtool_DTOOL_SUPER_BASE)");
-      return;
-    }
-    Py_INCREF((PyTypeObject *)&Dtool_DTOOL_SUPER_BASE);
-
-    PyDict_SetItemString(Dtool_DTOOL_SUPER_BASE._PyType.tp_dict, "DtoolGetSuperBase", PyCFunction_New(&Dtool_Methods_DTOOL_SUPER_BASE[0], (PyObject *)&Dtool_DTOOL_SUPER_BASE));
-  }
-
+static void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module) {
   if (module != nullptr) {
   if (module != nullptr) {
-    Py_INCREF((PyTypeObject *)&Dtool_DTOOL_SUPER_BASE);
-    PyModule_AddObject(module, "DTOOL_SUPER_BASE", (PyObject *)&Dtool_DTOOL_SUPER_BASE);
+    Dtool_PyTypedObject *super_base = Dtool_GetSuperBase();
+    Py_INCREF((PyTypeObject *)&super_base);
+    PyModule_AddObject(module, "DTOOL_SUPER_BASE", (PyObject *)&super_base);
   }
   }
 }
 }
 
 
-inline void *Dtool_DowncastInterface_DTOOL_SUPER_BASE(void *from_this, Dtool_PyTypedObject *from_type) {
+static void *Dtool_DowncastInterface_DTOOL_SUPER_BASE(void *from_this, Dtool_PyTypedObject *from_type) {
   return nullptr;
   return nullptr;
 }
 }
 
 
-inline void *Dtool_UpcastInterface_DTOOL_SUPER_BASE(PyObject *self, Dtool_PyTypedObject *requested_type) {
+static void *Dtool_UpcastInterface_DTOOL_SUPER_BASE(PyObject *self, Dtool_PyTypedObject *requested_type) {
   return nullptr;
   return nullptr;
 }
 }
 
 
-int Dtool_Init_DTOOL_SUPER_BASE(PyObject *self, PyObject *args, PyObject *kwds) {
+static int Dtool_Init_DTOOL_SUPER_BASE(PyObject *self, PyObject *args, PyObject *kwds) {
   assert(self != nullptr);
   assert(self != nullptr);
   PyErr_Format(PyExc_TypeError, "cannot init constant class %s", Py_TYPE(self)->tp_name);
   PyErr_Format(PyExc_TypeError, "cannot init constant class %s", Py_TYPE(self)->tp_name);
   return -1;
   return -1;
 }
 }
 
 
-EXPORT_THIS Dtool_PyTypedObject Dtool_DTOOL_SUPER_BASE = {
-  {
-    PyVarObject_HEAD_INIT(nullptr, 0)
-    "dtoolconfig.DTOOL_SUPER_BASE",
-    sizeof(Dtool_PyInstDef),
-    0, // tp_itemsize
-    &Dtool_FreeInstance_DTOOL_SUPER_BASE,
-    nullptr, // tp_print
-    nullptr, // tp_getattr
-    nullptr, // tp_setattr
+static void Dtool_FreeInstance_DTOOL_SUPER_BASE(PyObject *self) {
+  Py_TYPE(self)->tp_free(self);
+}
+
+/**
+ * Returns a pointer to the DTOOL_SUPER_BASE class that is the base class of
+ * all Panda types.  This pointer is shared by all modules.
+ */
+Dtool_PyTypedObject *Dtool_GetSuperBase() {
+  Dtool_TypeMap *type_map = Dtool_GetGlobalTypeMap();
+  auto it = type_map->find("DTOOL_SUPER_BASE");
+  if (it != type_map->end()) {
+    return it->second;
+  }
+
+  static PyMethodDef methods[] = {
+    { "DtoolGetSuperBase", (PyCFunction)&GetSuperBase, METH_NOARGS, "Will Return SUPERbase Class"},
+    { nullptr, nullptr, 0, nullptr }
+  };
+
+  static Dtool_PyTypedObject super_base_type = {
+    {
+      PyVarObject_HEAD_INIT(nullptr, 0)
+      "dtoolconfig.DTOOL_SUPER_BASE",
+      sizeof(Dtool_PyInstDef),
+      0, // tp_itemsize
+      &Dtool_FreeInstance_DTOOL_SUPER_BASE,
+      nullptr, // tp_print
+      nullptr, // tp_getattr
+      nullptr, // tp_setattr
 #if PY_MAJOR_VERSION >= 3
 #if PY_MAJOR_VERSION >= 3
-    nullptr, // tp_compare
+      nullptr, // tp_compare
 #else
 #else
-    &DtoolInstance_ComparePointers,
+      &DtoolInstance_ComparePointers,
 #endif
 #endif
-    nullptr, // tp_repr
-    nullptr, // tp_as_number
-    nullptr, // tp_as_sequence
-    nullptr, // tp_as_mapping
-    &DtoolInstance_HashPointer,
-    nullptr, // tp_call
-    nullptr, // tp_str
-    PyObject_GenericGetAttr,
-    PyObject_GenericSetAttr,
-    nullptr, // tp_as_buffer
-    (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES),
-    nullptr, // tp_doc
-    nullptr, // tp_traverse
-    nullptr, // tp_clear
+      nullptr, // tp_repr
+      nullptr, // tp_as_number
+      nullptr, // tp_as_sequence
+      nullptr, // tp_as_mapping
+      &DtoolInstance_HashPointer,
+      nullptr, // tp_call
+      nullptr, // tp_str
+      PyObject_GenericGetAttr,
+      PyObject_GenericSetAttr,
+      nullptr, // tp_as_buffer
+      (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES),
+      nullptr, // tp_doc
+      nullptr, // tp_traverse
+      nullptr, // tp_clear
 #if PY_MAJOR_VERSION >= 3
 #if PY_MAJOR_VERSION >= 3
-    &DtoolInstance_RichComparePointers,
+      &DtoolInstance_RichComparePointers,
 #else
 #else
-    nullptr, // tp_richcompare
+      nullptr, // tp_richcompare
 #endif
 #endif
-    0, // tp_weaklistoffset
-    nullptr, // tp_iter
-    nullptr, // tp_iternext
-    Dtool_Methods_DTOOL_SUPER_BASE,
-    standard_type_members,
-    nullptr, // tp_getset
-    nullptr, // tp_base
-    nullptr, // tp_dict
-    nullptr, // tp_descr_get
-    nullptr, // tp_descr_set
-    0, // tp_dictoffset
-    Dtool_Init_DTOOL_SUPER_BASE,
-    PyType_GenericAlloc,
-    Dtool_new_DTOOL_SUPER_BASE,
-    PyObject_Del,
-    nullptr, // tp_is_gc
-    nullptr, // tp_bases
-    nullptr, // tp_mro
-    nullptr, // tp_cache
-    nullptr, // tp_subclasses
-    nullptr, // tp_weaklist
-    nullptr, // tp_del
-  },
-  TypeHandle::none(),
-  Dtool_PyModuleClassInit_DTOOL_SUPER_BASE,
-  Dtool_UpcastInterface_DTOOL_SUPER_BASE,
-  Dtool_DowncastInterface_DTOOL_SUPER_BASE,
-  nullptr,
-  nullptr,
-};
+      0, // tp_weaklistoffset
+      nullptr, // tp_iter
+      nullptr, // tp_iternext
+      methods,
+      standard_type_members,
+      nullptr, // tp_getset
+      nullptr, // tp_base
+      nullptr, // tp_dict
+      nullptr, // tp_descr_get
+      nullptr, // tp_descr_set
+      0, // tp_dictoffset
+      Dtool_Init_DTOOL_SUPER_BASE,
+      PyType_GenericAlloc,
+      nullptr, // tp_new
+      PyObject_Del,
+      nullptr, // tp_is_gc
+      nullptr, // tp_bases
+      nullptr, // tp_mro
+      nullptr, // tp_cache
+      nullptr, // tp_subclasses
+      nullptr, // tp_weaklist
+      nullptr, // tp_del
+    },
+    TypeHandle::none(),
+    Dtool_PyModuleClassInit_DTOOL_SUPER_BASE,
+    Dtool_UpcastInterface_DTOOL_SUPER_BASE,
+    Dtool_DowncastInterface_DTOOL_SUPER_BASE,
+    nullptr,
+    nullptr,
+  };
+
+  super_base_type._PyType.tp_dict = PyDict_New();
+  PyDict_SetItemString(super_base_type._PyType.tp_dict, "DtoolClassDict", super_base_type._PyType.tp_dict);
+
+  if (PyType_Ready((PyTypeObject *)&super_base_type) < 0) {
+    PyErr_SetString(PyExc_TypeError, "PyType_Ready(Dtool_DTOOL_SUPER_BASE)");
+    return nullptr;
+  }
+  Py_INCREF((PyTypeObject *)&super_base_type);
+
+  PyDict_SetItemString(super_base_type._PyType.tp_dict, "DtoolGetSuperBase", PyCFunction_New(&methods[0], (PyObject *)&super_base_type));
+
+  (*type_map)["DTOOL_SUPER_BASE"] = &super_base_type;
+  return &super_base_type;
+}
 
 
 #endif  // HAVE_PYTHON
 #endif  // HAVE_PYTHON

+ 0 - 1
dtool/src/interrogatedb/p3interrogatedb_composite1.cxx

@@ -1,5 +1,4 @@
 #include "config_interrogatedb.cxx"
 #include "config_interrogatedb.cxx"
-#include "dtool_super_base.cxx"
 #include "indexRemapper.cxx"
 #include "indexRemapper.cxx"
 #include "interrogateComponent.cxx"
 #include "interrogateComponent.cxx"
 #include "interrogateDatabase.cxx"
 #include "interrogateDatabase.cxx"

+ 0 - 3
dtool/src/interrogatedb/p3interrogatedb_composite2.cxx

@@ -4,6 +4,3 @@
 #include "interrogate_datafile.cxx"
 #include "interrogate_datafile.cxx"
 #include "interrogate_interface.cxx"
 #include "interrogate_interface.cxx"
 #include "interrogate_request.cxx"
 #include "interrogate_request.cxx"
-#include "py_panda.cxx"
-#include "py_compat.cxx"
-#include "py_wrappers.cxx"

+ 0 - 7
dtool/src/interrogatedb/py_compat.cxx

@@ -1,11 +1,4 @@
 /**
 /**
- * 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."
- *
  * @file py_compat.cxx
  * @file py_compat.cxx
  * @author rdb
  * @author rdb
  * @date 2017-12-03
  * @date 2017-12-03

+ 1 - 8
dtool/src/interrogatedb/py_compat.h

@@ -1,11 +1,4 @@
 /**
 /**
- * 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."
- *
  * @file py_compat.h
  * @file py_compat.h
  * @author rdb
  * @author rdb
  * @date 2017-12-02
  * @date 2017-12-02
@@ -106,7 +99,7 @@ typedef int Py_ssize_t;
 // PyInt_FromSize_t automatically picks the right type.
 // PyInt_FromSize_t automatically picks the right type.
 #  define PyLongOrInt_AS_LONG PyInt_AsLong
 #  define PyLongOrInt_AS_LONG PyInt_AsLong
 
 
-EXPCL_INTERROGATEDB size_t PyLongOrInt_AsSize_t(PyObject *);
+size_t PyLongOrInt_AsSize_t(PyObject *);
 #endif
 #endif
 
 
 // Which character to use in PyArg_ParseTuple et al for a byte string.
 // Which character to use in PyArg_ParseTuple et al for a byte string.

+ 17 - 12
dtool/src/interrogatedb/py_panda.I

@@ -1,11 +1,4 @@
 /**
 /**
- * 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."
- *
  * @file py_panda.I
  * @file py_panda.I
  * @author rdb
  * @author rdb
  * @date 2016-06-06
  * @date 2016-06-06
@@ -26,7 +19,7 @@
 template<class T> INLINE bool
 template<class T> INLINE bool
 DtoolInstance_GetPointer(PyObject *self, T *&into) {
 DtoolInstance_GetPointer(PyObject *self, T *&into) {
   if (DtoolInstance_Check(self)) {
   if (DtoolInstance_Check(self)) {
-    Dtool_PyTypedObject *target_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
+    Dtool_PyTypedObject *target_class = (Dtool_PyTypedObject *)get_type_handle(T).get_python_type();
     if (target_class != nullptr) {
     if (target_class != nullptr) {
       if (_IS_FINAL(T)) {
       if (_IS_FINAL(T)) {
         if (DtoolInstance_TYPE(self) == target_class) {
         if (DtoolInstance_TYPE(self) == target_class) {
@@ -116,32 +109,44 @@ INLINE long Dtool_EnumValue_AsLong(PyObject *value) {
  */
  */
 template<class T> INLINE PyObject *
 template<class T> INLINE PyObject *
 DTool_CreatePyInstance(const T *obj, bool memory_rules) {
 DTool_CreatePyInstance(const T *obj, bool memory_rules) {
-  Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
+  Dtool_PyTypedObject *known_class = (Dtool_PyTypedObject *)get_type_handle(T).get_python_type();
   nassertr(known_class != nullptr, nullptr);
   nassertr(known_class != nullptr, nullptr);
   return DTool_CreatePyInstance((void*) obj, *known_class, memory_rules, true);
   return DTool_CreatePyInstance((void*) obj, *known_class, memory_rules, true);
 }
 }
 
 
 template<class T> INLINE PyObject *
 template<class T> INLINE PyObject *
 DTool_CreatePyInstance(T *obj, bool memory_rules) {
 DTool_CreatePyInstance(T *obj, bool memory_rules) {
-  Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
+  Dtool_PyTypedObject *known_class = (Dtool_PyTypedObject *)get_type_handle(T).get_python_type();
   nassertr(known_class != nullptr, nullptr);
   nassertr(known_class != nullptr, nullptr);
   return DTool_CreatePyInstance((void*) obj, *known_class, memory_rules, false);
   return DTool_CreatePyInstance((void*) obj, *known_class, memory_rules, false);
 }
 }
 
 
 template<class T> INLINE PyObject *
 template<class T> INLINE PyObject *
 DTool_CreatePyInstanceTyped(const T *obj, bool memory_rules) {
 DTool_CreatePyInstanceTyped(const T *obj, bool memory_rules) {
-  Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
+  Dtool_PyTypedObject *known_class = (Dtool_PyTypedObject *)get_type_handle(T).get_python_type();
   nassertr(known_class != nullptr, nullptr);
   nassertr(known_class != nullptr, nullptr);
   return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, true, obj->get_type().get_index());
   return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, true, obj->get_type().get_index());
 }
 }
 
 
 template<class T> INLINE PyObject *
 template<class T> INLINE PyObject *
 DTool_CreatePyInstanceTyped(T *obj, bool memory_rules) {
 DTool_CreatePyInstanceTyped(T *obj, bool memory_rules) {
-  Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
+  Dtool_PyTypedObject *known_class = (Dtool_PyTypedObject *)get_type_handle(T).get_python_type();
   nassertr(known_class != nullptr, nullptr);
   nassertr(known_class != nullptr, nullptr);
   return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, false, obj->get_type().get_index());
   return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, false, obj->get_type().get_index());
 }
 }
 
 
+/**
+ * Finishes initializing the Dtool_PyInstDef.
+ */
+INLINE int
+DTool_PyInit_Finalize(PyObject *self, void *local_this, Dtool_PyTypedObject *type, bool memory_rules, bool is_const) {
+  ((Dtool_PyInstDef *)self)->_My_Type = type;
+  ((Dtool_PyInstDef *)self)->_ptr_to_object = local_this;
+  ((Dtool_PyInstDef *)self)->_memory_rules = memory_rules;
+  ((Dtool_PyInstDef *)self)->_is_const = is_const;
+  return 0;
+}
+
 /**
 /**
  * Checks that the tuple is empty.
  * Checks that the tuple is empty.
  */
  */

+ 48 - 174
dtool/src/interrogatedb/py_panda.cxx

@@ -1,11 +1,4 @@
 /**
 /**
- * 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."
- *
  * @file py_panda.cxx
  * @file py_panda.cxx
  * @author drose
  * @author drose
  * @date 2005-07-04
  * @date 2005-07-04
@@ -29,10 +22,6 @@ PyMemberDef standard_type_members[] = {
   {nullptr}  /* Sentinel */
   {nullptr}  /* Sentinel */
 };
 };
 
 
-static RuntimeTypeMap runtime_type_map;
-static RuntimeTypeSet runtime_type_set;
-static NamedTypeMap named_type_map;
-
 /**
 /**
 
 
  */
  */
@@ -431,7 +420,7 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
   // IF the class is possibly a run time typed object
   // IF the class is possibly a run time typed object
   if (type_index > 0) {
   if (type_index > 0) {
     // get best fit class...
     // get best fit class...
-    Dtool_PyTypedObject *target_class = Dtool_RuntimeTypeDtoolType(type_index);
+    Dtool_PyTypedObject *target_class = (Dtool_PyTypedObject *)TypeHandle::from_index(type_index).get_python_type();
     if (target_class != nullptr) {
     if (target_class != nullptr) {
       // cast to the type...
       // cast to the type...
       void *new_local_this = target_class->_Dtool_DowncastInterface(local_this_in, &known_class_type);
       void *new_local_this = target_class->_Dtool_DowncastInterface(local_this_in, &known_class_type);
@@ -484,132 +473,26 @@ PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_class
   return (PyObject *)self;
   return (PyObject *)self;
 }
 }
 
 
-// Th Finalizer for simple instances..
-int DTool_PyInit_Finalize(PyObject *self, void *local_this, Dtool_PyTypedObject *type, bool memory_rules, bool is_const) {
-  // lets put some code in here that checks to see the memory is properly
-  // configured.. prior to my call ..
-
-  ((Dtool_PyInstDef *)self)->_My_Type = type;
-  ((Dtool_PyInstDef *)self)->_ptr_to_object = local_this;
-  ((Dtool_PyInstDef *)self)->_memory_rules = memory_rules;
-  ((Dtool_PyInstDef *)self)->_is_const = is_const;
-  return 0;
-}
-
-// A helper function to glue method definition together .. that can not be
-// done at code generation time because of multiple generation passes in
-// interrogate..
-void Dtool_Accum_MethDefs(PyMethodDef in[], MethodDefmap &themap) {
-  for (; in->ml_name != nullptr; in++) {
-    if (themap.find(in->ml_name) == themap.end()) {
-      themap[in->ml_name] = in;
-    }
-  }
-}
-
-// ** HACK ** alert.. Need to keep a runtime type dictionary ... that is
-// forward declared of typed object.  We rely on the fact that typed objects
-// are uniquly defined by an integer.
-void
-RegisterNamedClass(const string &name, Dtool_PyTypedObject &otype) {
-  std::pair<NamedTypeMap::iterator, bool> result =
-    named_type_map.insert(NamedTypeMap::value_type(name, &otype));
-
-  if (!result.second) {
-    // There was already a class with this name in the dictionary.
-    interrogatedb_cat.warning()
-      << "Double definition for class " << name << "\n";
-  }
-}
-
-void
-RegisterRuntimeTypedClass(Dtool_PyTypedObject &otype) {
-  int type_index = otype._type.get_index();
-
-  if (type_index == 0) {
-    interrogatedb_cat.warning()
-      << "Class " << otype._PyType.tp_name
-      << " has a zero TypeHandle value; check that init_type() is called.\n";
-
-  } else if (type_index < 0 || type_index >= TypeRegistry::ptr()->get_num_typehandles()) {
-    interrogatedb_cat.warning()
-      << "Class " << otype._PyType.tp_name
-      << " has an illegal TypeHandle value; check that init_type() is called.\n";
-
-  } else {
-    std::pair<RuntimeTypeMap::iterator, bool> result =
-      runtime_type_map.insert(RuntimeTypeMap::value_type(type_index, &otype));
-    if (!result.second) {
-      // There was already an entry in the dictionary for type_index.
-      Dtool_PyTypedObject *other_type = (*result.first).second;
-      interrogatedb_cat.warning()
-        << "Classes " << otype._PyType.tp_name
-        << " and " << other_type->_PyType.tp_name
-        << " share the same TypeHandle value (" << type_index
-        << "); check class definitions.\n";
-
-    } else {
-      runtime_type_set.insert(type_index);
-    }
-  }
-}
-
-Dtool_PyTypedObject *
-LookupNamedClass(const string &name) {
-  NamedTypeMap::const_iterator it;
-  it = named_type_map.find(name);
-
-  if (it == named_type_map.end()) {
-    // Find a type named like this in the type registry.
-    TypeHandle handle = TypeRegistry::ptr()->find_type(name);
-    if (handle.get_index() > 0) {
-      RuntimeTypeMap::const_iterator it2;
-      it2 = runtime_type_map.find(handle.get_index());
-      if (it2 != runtime_type_map.end()) {
-        return it2->second;
-      }
-    }
-
-    interrogatedb_cat.error()
-      << "Attempt to use type " << name << " which has not yet been defined!\n";
-    return nullptr;
-  } else {
-    return it->second;
-  }
-}
-
-Dtool_PyTypedObject *
-LookupRuntimeTypedClass(TypeHandle handle) {
-  RuntimeTypeMap::const_iterator it;
-  it = runtime_type_map.find(handle.get_index());
-
-  if (it == runtime_type_map.end()) {
-    interrogatedb_cat.error()
-      << "Attempt to use type " << handle << " which has not yet been defined!\n";
-    return nullptr;
-  } else {
-    return it->second;
-  }
-}
-
-Dtool_PyTypedObject *Dtool_RuntimeTypeDtoolType(int type) {
-  RuntimeTypeMap::iterator di = runtime_type_map.find(type);
-  if (di != runtime_type_map.end()) {
-    return di->second;
+/**
+ * Returns a borrowed reference to the global type dictionary.
+ */
+Dtool_TypeMap *Dtool_GetGlobalTypeMap() {
+  PyObject *capsule = PySys_GetObject((char *)"_interrogate_types");
+  if (capsule != nullptr) {
+    return (Dtool_TypeMap *)PyCapsule_GetPointer(capsule, nullptr);
   } else {
   } else {
-    int type2 = get_best_parent_from_Set(type, runtime_type_set);
-    di = runtime_type_map.find(type2);
-    if (di != runtime_type_map.end()) {
-      return di->second;
-    }
+    Dtool_TypeMap *type_map = new Dtool_TypeMap;
+    capsule = PyCapsule_New((void *)type_map, nullptr, nullptr);
+    PySys_SetObject((char *)"_interrogate_types", capsule);
+    Py_DECREF(capsule);
+    return type_map;
   }
   }
-  return nullptr;
 }
 }
 
 
 #if PY_MAJOR_VERSION >= 3
 #if PY_MAJOR_VERSION >= 3
-PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], PyModuleDef *module_def) {
+PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], PyModuleDef *module_def) {
 #else
 #else
-PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
+PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulename) {
 #endif
 #endif
   // Check the version so we can print a helpful error if it doesn't match.
   // Check the version so we can print a helpful error if it doesn't match.
   string version = Py_GetVersion();
   string version = Py_GetVersion();
@@ -627,55 +510,46 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
     return nullptr;
     return nullptr;
   }
   }
 
 
-  // Initialize the types we define in py_panda.
-  static bool dtool_inited = false;
-  if (!dtool_inited) {
-    dtool_inited = true;
-
-    if (PyType_Ready(&Dtool_SequenceWrapper_Type) < 0) {
-      return Dtool_Raise_TypeError("PyType_Ready(Dtool_SequenceWrapper)");
-    }
-
-    if (PyType_Ready(&Dtool_MutableSequenceWrapper_Type) < 0) {
-      return Dtool_Raise_TypeError("PyType_Ready(Dtool_MutableSequenceWrapper)");
-    }
-
-    if (PyType_Ready(&Dtool_MappingWrapper_Type) < 0) {
-      return Dtool_Raise_TypeError("PyType_Ready(Dtool_MappingWrapper)");
-    }
-
-    if (PyType_Ready(&Dtool_MutableMappingWrapper_Type) < 0) {
-      return Dtool_Raise_TypeError("PyType_Ready(Dtool_MutableMappingWrapper)");
-    }
+  Dtool_TypeMap *type_map = Dtool_GetGlobalTypeMap();
 
 
-    if (PyType_Ready(&Dtool_MappingWrapper_Keys_Type) < 0) {
-      return Dtool_Raise_TypeError("PyType_Ready(Dtool_MappingWrapper_Keys)");
-    }
+  // the module level function inits....
+  MethodDefmap functions;
+  for (size_t i = 0; defs[i] != nullptr; i++) {
+    const LibraryDef &def = *defs[i];
 
 
-    if (PyType_Ready(&Dtool_MappingWrapper_Values_Type) < 0) {
-      return Dtool_Raise_TypeError("PyType_Ready(Dtool_MappingWrapper_Values)");
+    // Accumulate method definitions.
+    for (PyMethodDef *meth = def._methods; meth->ml_name != nullptr; meth++) {
+      if (functions.find(meth->ml_name) == functions.end()) {
+        functions[meth->ml_name] = meth;
+      }
     }
     }
 
 
-    if (PyType_Ready(&Dtool_MappingWrapper_Items_Type) < 0) {
-      return Dtool_Raise_TypeError("PyType_Ready(Dtool_MappingWrapper_Items)");
+    // Define exported types.
+    const Dtool_TypeDef *types = def._types;
+    if (types != nullptr) {
+      while (types->name != nullptr) {
+        (*type_map)[std::string(types->name)] = types->type;
+        ++types;
+      }
     }
     }
+  }
 
 
-    if (PyType_Ready(&Dtool_GeneratorWrapper_Type) < 0) {
-      return Dtool_Raise_TypeError("PyType_Ready(Dtool_GeneratorWrapper)");
-    }
+  // Resolve external types, in a second pass.
+  for (size_t i = 0; defs[i] != nullptr; i++) {
+    const LibraryDef &def = *defs[i];
 
 
-    if (PyType_Ready(&Dtool_StaticProperty_Type) < 0) {
-      return Dtool_Raise_TypeError("PyType_Ready(Dtool_StaticProperty_Type)");
+    Dtool_TypeDef *types = def._external_types;
+    if (types != nullptr) {
+      while (types->name != nullptr) {
+        auto it = type_map->find(std::string(types->name));
+        if (it != type_map->end()) {
+          types->type = it->second;
+        } else {
+          return PyErr_Format(PyExc_NameError, "name '%s' is not defined", types->name);
+        }
+        ++types;
+      }
     }
     }
-
-    // Initialize the base class of everything.
-    Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(nullptr);
-  }
-
-  // the module level function inits....
-  MethodDefmap functions;
-  for (int xx = 0; defs[xx] != nullptr; xx++) {
-    Dtool_Accum_MethDefs(defs[xx]->_methods, functions);
   }
   }
 
 
   PyMethodDef *newdef = new PyMethodDef[functions.size() + 1];
   PyMethodDef *newdef = new PyMethodDef[functions.size() + 1];
@@ -801,7 +675,7 @@ PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject *args) {
 
 
 // We do expose a dictionay for dtool classes .. this should be removed at
 // We do expose a dictionay for dtool classes .. this should be removed at
 // some point..
 // some point..
-EXPCL_INTERROGATEDB PyObject *Dtool_AddToDictionary(PyObject *self1, PyObject *args) {
+PyObject *Dtool_AddToDictionary(PyObject *self1, PyObject *args) {
   PyObject *self;
   PyObject *self;
   PyObject *subject;
   PyObject *subject;
   PyObject *key;
   PyObject *key;

+ 42 - 53
dtool/src/interrogatedb/py_panda.h

@@ -1,11 +1,4 @@
 /**
 /**
- * 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."
- *
  * @file py_panda.h
  * @file py_panda.h
  */
  */
 
 
@@ -43,9 +36,6 @@ using namespace std;
 #endif
 #endif
 
 
 struct Dtool_PyTypedObject;
 struct Dtool_PyTypedObject;
-typedef std::map<int, Dtool_PyTypedObject *> RuntimeTypeMap;
-typedef std::set<int> RuntimeTypeSet;
-typedef std::map<std::string, Dtool_PyTypedObject *> NamedTypeMap;
 
 
 // used to stamp dtool instance..
 // used to stamp dtool instance..
 #define PY_PANDA_SIGNATURE 0xbeaf
 #define PY_PANDA_SIGNATURE 0xbeaf
@@ -78,7 +68,7 @@ struct Dtool_PyInstDef {
 };
 };
 
 
 // A Offset Dictionary Defining How to read the Above Object..
 // A Offset Dictionary Defining How to read the Above Object..
-extern EXPCL_INTERROGATEDB PyMemberDef standard_type_members[];
+extern PyMemberDef standard_type_members[];
 
 
 // The Class Definition Structor For a Dtool python type.
 // The Class Definition Structor For a Dtool python type.
 struct Dtool_PyTypedObject {
 struct Dtool_PyTypedObject {
@@ -190,25 +180,21 @@ static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
 // forward declared of typed object.  We rely on the fact that typed objects
 // forward declared of typed object.  We rely on the fact that typed objects
 // are uniquly defined by an integer.
 // are uniquly defined by an integer.
 
 
-EXPCL_INTERROGATEDB void RegisterNamedClass(const std::string &name, Dtool_PyTypedObject &otype);
-EXPCL_INTERROGATEDB void RegisterRuntimeTypedClass(Dtool_PyTypedObject &otype);
+typedef std::map<std::string, Dtool_PyTypedObject *> Dtool_TypeMap;
 
 
-EXPCL_INTERROGATEDB Dtool_PyTypedObject *LookupNamedClass(const std::string &name);
-EXPCL_INTERROGATEDB Dtool_PyTypedObject *LookupRuntimeTypedClass(TypeHandle handle);
-
-EXPCL_INTERROGATEDB Dtool_PyTypedObject *Dtool_RuntimeTypeDtoolType(int type);
+Dtool_TypeMap *Dtool_GetGlobalTypeMap();
 
 
 /**
 /**
 
 
  */
  */
-EXPCL_INTERROGATEDB void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject *classdef, void **answer);
+void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject *classdef, void **answer);
 
 
-EXPCL_INTERROGATEDB void *DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, int param, const std::string &function_name, bool const_ok, bool report_errors);
+void *DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, int param, const std::string &function_name, bool const_ok, bool report_errors);
 
 
-EXPCL_INTERROGATEDB bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer);
+bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer);
 
 
-EXPCL_INTERROGATEDB bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef,
-                                                              void **answer, const char *method_name);
+bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef,
+                                            void **answer, const char *method_name);
 
 
 template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into);
 template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into);
 template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into, Dtool_PyTypedObject &classdef);
 template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into, Dtool_PyTypedObject &classdef);
@@ -218,7 +204,7 @@ INLINE int DtoolInstance_ComparePointers(PyObject *v1, PyObject *v2);
 INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, int op);
 INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, int op);
 
 
 // Functions related to error reporting.
 // Functions related to error reporting.
-EXPCL_INTERROGATEDB bool _Dtool_CheckErrorOccurred();
+bool _Dtool_CheckErrorOccurred();
 
 
 #ifdef NDEBUG
 #ifdef NDEBUG
 #define Dtool_CheckErrorOccurred() (UNLIKELY(_PyErr_OCCURRED() != nullptr))
 #define Dtool_CheckErrorOccurred() (UNLIKELY(_PyErr_OCCURRED() != nullptr))
@@ -226,12 +212,12 @@ EXPCL_INTERROGATEDB bool _Dtool_CheckErrorOccurred();
 #define Dtool_CheckErrorOccurred() (UNLIKELY(_Dtool_CheckErrorOccurred()))
 #define Dtool_CheckErrorOccurred() (UNLIKELY(_Dtool_CheckErrorOccurred()))
 #endif
 #endif
 
 
-EXPCL_INTERROGATEDB PyObject *Dtool_Raise_AssertionError();
-EXPCL_INTERROGATEDB PyObject *Dtool_Raise_TypeError(const char *message);
-EXPCL_INTERROGATEDB PyObject *Dtool_Raise_ArgTypeError(PyObject *obj, int param, const char *function_name, const char *type_name);
-EXPCL_INTERROGATEDB PyObject *Dtool_Raise_AttributeError(PyObject *obj, const char *attribute);
+PyObject *Dtool_Raise_AssertionError();
+PyObject *Dtool_Raise_TypeError(const char *message);
+PyObject *Dtool_Raise_ArgTypeError(PyObject *obj, int param, const char *function_name, const char *type_name);
+PyObject *Dtool_Raise_AttributeError(PyObject *obj, const char *attribute);
 
 
-EXPCL_INTERROGATEDB PyObject *_Dtool_Raise_BadArgumentsError();
+PyObject *_Dtool_Raise_BadArgumentsError();
 #ifdef NDEBUG
 #ifdef NDEBUG
 // Define it to a function that just prints a generic message.
 // Define it to a function that just prints a generic message.
 #define Dtool_Raise_BadArgumentsError(x) _Dtool_Raise_BadArgumentsError()
 #define Dtool_Raise_BadArgumentsError(x) _Dtool_Raise_BadArgumentsError()
@@ -243,9 +229,9 @@ EXPCL_INTERROGATEDB PyObject *_Dtool_Raise_BadArgumentsError();
 // These functions are similar to Dtool_WrapValue, except that they also
 // These functions are similar to Dtool_WrapValue, except that they also
 // contain code for checking assertions and exceptions when compiling with
 // contain code for checking assertions and exceptions when compiling with
 // NDEBUG mode on.
 // NDEBUG mode on.
-EXPCL_INTERROGATEDB PyObject *_Dtool_Return_None();
-EXPCL_INTERROGATEDB PyObject *Dtool_Return_Bool(bool value);
-EXPCL_INTERROGATEDB PyObject *_Dtool_Return(PyObject *value);
+PyObject *_Dtool_Return_None();
+PyObject *Dtool_Return_Bool(bool value);
+PyObject *_Dtool_Return(PyObject *value);
 
 
 #ifdef NDEBUG
 #ifdef NDEBUG
 #define Dtool_Return_None() (LIKELY(_PyErr_OCCURRED() == nullptr) ? (Py_INCREF(Py_None), Py_None) : nullptr)
 #define Dtool_Return_None() (LIKELY(_PyErr_OCCURRED() == nullptr) ? (Py_INCREF(Py_None), Py_None) : nullptr)
@@ -258,19 +244,19 @@ EXPCL_INTERROGATEDB PyObject *_Dtool_Return(PyObject *value);
 /**
 /**
  * Wrapper around Python 3.4's enum library, which does not have a C API.
  * Wrapper around Python 3.4's enum library, which does not have a C API.
  */
  */
-EXPCL_INTERROGATEDB PyTypeObject *Dtool_EnumType_Create(const char *name, PyObject *names,
+PyTypeObject *Dtool_EnumType_Create(const char *name, PyObject *names,
                                                         const char *module = nullptr);
                                                         const char *module = nullptr);
-EXPCL_INTERROGATEDB INLINE long Dtool_EnumValue_AsLong(PyObject *value);
+INLINE long Dtool_EnumValue_AsLong(PyObject *value);
 
 
 
 
 /**
 /**
 
 
  */
  */
-EXPCL_INTERROGATEDB PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &known_class_type, bool memory_rules, bool is_const, int RunTimeType);
+PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &known_class_type, bool memory_rules, bool is_const, int RunTimeType);
 
 
 // DTool_CreatePyInstance .. wrapper function to finalize the existance of a
 // DTool_CreatePyInstance .. wrapper function to finalize the existance of a
 // general dtool py instance..
 // general dtool py instance..
-EXPCL_INTERROGATEDB PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_classdef, bool memory_rules, bool is_const);
+PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_classdef, bool memory_rules, bool is_const);
 
 
 // These template methods allow use when the Dtool_PyTypedObject is not known.
 // These template methods allow use when the Dtool_PyTypedObject is not known.
 // They require a get_class_type() to be defined for the class.
 // They require a get_class_type() to be defined for the class.
@@ -314,43 +300,49 @@ Define_Dtool_FreeInstanceRef(CLASS_NAME,CNAME)\
 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
 
 
 // The finalizer for simple instances.
 // The finalizer for simple instances.
-EXPCL_INTERROGATEDB int DTool_PyInit_Finalize(PyObject *self, void *This, Dtool_PyTypedObject *type, bool memory_rules, bool is_const);
+INLINE int DTool_PyInit_Finalize(PyObject *self, void *This, Dtool_PyTypedObject *type, bool memory_rules, bool is_const);
 
 
 // A heler function to glu methed definition together .. that can not be done
 // A heler function to glu methed definition together .. that can not be done
 // at code generation time becouse of multiple generation passes in
 // at code generation time becouse of multiple generation passes in
 // interigate..
 // interigate..
 typedef std::map<std::string, PyMethodDef *> MethodDefmap;
 typedef std::map<std::string, PyMethodDef *> MethodDefmap;
 
 
-EXPCL_INTERROGATEDB void Dtool_Accum_MethDefs(PyMethodDef in[], MethodDefmap &themap);
-
 // We need a way to runtime merge compile units into a python "Module" .. this
 // We need a way to runtime merge compile units into a python "Module" .. this
 // is done with the fallowing structors and code.. along with the support of
 // is done with the fallowing structors and code.. along with the support of
 // interigate_module
 // interigate_module
+
+struct Dtool_TypeDef {
+  const char *const name;
+  Dtool_PyTypedObject *type;
+};
+
 struct LibraryDef {
 struct LibraryDef {
-  PyMethodDef *_methods;
+  PyMethodDef *const _methods;
+  const Dtool_TypeDef *const _types;
+  Dtool_TypeDef *const _external_types;
 };
 };
 
 
 #if PY_MAJOR_VERSION >= 3
 #if PY_MAJOR_VERSION >= 3
-EXPCL_INTERROGATEDB PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], PyModuleDef *module_def);
+PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], PyModuleDef *module_def);
 #else
 #else
-EXPCL_INTERROGATEDB PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename);
+PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulename);
 #endif
 #endif
 
 
 // HACK.... Be carefull Dtool_BorrowThisReference This function can be used to
 // HACK.... Be carefull Dtool_BorrowThisReference This function can be used to
 // grab the "THIS" pointer from an object and use it Required to support fom
 // grab the "THIS" pointer from an object and use it Required to support fom
 // historical inharatence in the for of "is this instance of"..
 // historical inharatence in the for of "is this instance of"..
-EXPCL_INTERROGATEDB PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject *args);
+PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject *args);
 
 
 #define DTOOL_PyObject_HashPointer DtoolInstance_HashPointer
 #define DTOOL_PyObject_HashPointer DtoolInstance_HashPointer
 #define DTOOL_PyObject_ComparePointers DtoolInstance_ComparePointers
 #define DTOOL_PyObject_ComparePointers DtoolInstance_ComparePointers
 
 
-EXPCL_INTERROGATEDB PyObject *
+PyObject *
 copy_from_make_copy(PyObject *self, PyObject *noargs);
 copy_from_make_copy(PyObject *self, PyObject *noargs);
 
 
-EXPCL_INTERROGATEDB PyObject *
+PyObject *
 copy_from_copy_constructor(PyObject *self, PyObject *noargs);
 copy_from_copy_constructor(PyObject *self, PyObject *noargs);
 
 
-EXPCL_INTERROGATEDB PyObject *
+PyObject *
 map_deepcopy_to_copy(PyObject *self, PyObject *args);
 map_deepcopy_to_copy(PyObject *self, PyObject *args);
 
 
 /**
 /**
@@ -359,13 +351,13 @@ map_deepcopy_to_copy(PyObject *self, PyObject *args);
  */
  */
 ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args);
 ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args);
 ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args, PyObject *kwds);
 ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args, PyObject *kwds);
-EXPCL_INTERROGATEDB bool Dtool_ExtractArg(PyObject **result, PyObject *args,
+bool Dtool_ExtractArg(PyObject **result, PyObject *args,
                                           PyObject *kwds, const char *keyword);
                                           PyObject *kwds, const char *keyword);
-EXPCL_INTERROGATEDB bool Dtool_ExtractArg(PyObject **result, PyObject *args,
+bool Dtool_ExtractArg(PyObject **result, PyObject *args,
                                           PyObject *kwds);
                                           PyObject *kwds);
-EXPCL_INTERROGATEDB bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
+bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
                                                   PyObject *kwds, const char *keyword);
                                                   PyObject *kwds, const char *keyword);
-EXPCL_INTERROGATEDB bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
+bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
                                                   PyObject *kwds);
                                                   PyObject *kwds);
 
 
 /**
 /**
@@ -401,10 +393,7 @@ ALWAYS_INLINE PyObject *Dtool_WrapValue(Py_buffer *value);
 template<class T1, class T2>
 template<class T1, class T2>
 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::pair<T1, T2> &value);
 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::pair<T1, T2> &value);
 
 
-EXPCL_INTERROGATEDB extern struct Dtool_PyTypedObject Dtool_DTOOL_SUPER_BASE;
-EXPCL_INTERROGATEDB extern void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module);
-
-#define Dtool_Ptr_DTOOL_SUPER_BASE (&Dtool_DTOOL_SUPER_BASE)
+Dtool_PyTypedObject *Dtool_GetSuperBase();
 
 
 #include "py_panda.I"
 #include "py_panda.I"
 
 

File diff suppressed because it is too large
+ 299 - 674
dtool/src/interrogatedb/py_wrappers.cxx


+ 6 - 23
dtool/src/interrogatedb/py_wrappers.h

@@ -1,11 +1,4 @@
 /**
 /**
- * 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."
- *
  * @file py_wrappers.h
  * @file py_wrappers.h
  * @author rdb
  * @author rdb
  * @date 2017-11-26
  * @date 2017-11-26
@@ -56,22 +49,12 @@ struct Dtool_GeneratorWrapper {
   iternextfunc _iternext_func;
   iternextfunc _iternext_func;
 };
 };
 
 
-EXPCL_INTERROGATEDB extern PyTypeObject Dtool_SequenceWrapper_Type;
-EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MutableSequenceWrapper_Type;
-EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MappingWrapper_Type;
-EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MutableMappingWrapper_Type;
-EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MappingWrapper_Items_Type;
-EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MappingWrapper_Keys_Type;
-EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MappingWrapper_Values_Type;
-EXPCL_INTERROGATEDB extern PyTypeObject Dtool_GeneratorWrapper_Type;
-EXPCL_INTERROGATEDB extern PyTypeObject Dtool_StaticProperty_Type;
-
-EXPCL_INTERROGATEDB Dtool_SequenceWrapper *Dtool_NewSequenceWrapper(PyObject *self, const char *name);
-EXPCL_INTERROGATEDB Dtool_MutableSequenceWrapper *Dtool_NewMutableSequenceWrapper(PyObject *self, const char *name);
-EXPCL_INTERROGATEDB Dtool_MappingWrapper *Dtool_NewMappingWrapper(PyObject *self, const char *name);
-EXPCL_INTERROGATEDB Dtool_MappingWrapper *Dtool_NewMutableMappingWrapper(PyObject *self, const char *name);
-EXPCL_INTERROGATEDB PyObject *Dtool_NewGenerator(PyObject *self, const char *name, iternextfunc func);
-EXPCL_INTERROGATEDB PyObject *Dtool_NewStaticProperty(PyTypeObject *obj, const PyGetSetDef *getset);
+Dtool_SequenceWrapper *Dtool_NewSequenceWrapper(PyObject *self, const char *name);
+Dtool_MutableSequenceWrapper *Dtool_NewMutableSequenceWrapper(PyObject *self, const char *name);
+Dtool_MappingWrapper *Dtool_NewMappingWrapper(PyObject *self, const char *name);
+Dtool_MappingWrapper *Dtool_NewMutableMappingWrapper(PyObject *self, const char *name);
+PyObject *Dtool_NewGenerator(PyObject *self, iternextfunc func);
+PyObject *Dtool_NewStaticProperty(PyTypeObject *obj, const PyGetSetDef *getset);
 
 
 #endif  // HAVE_PYTHON
 #endif  // HAVE_PYTHON
 
 

+ 8 - 0
dtool/src/pystub/pystub.cxx

@@ -27,6 +27,8 @@ extern "C" {
   EXPCL_PYSTUB int PyCFunction_New(...);
   EXPCL_PYSTUB int PyCFunction_New(...);
   EXPCL_PYSTUB int PyCFunction_NewEx(...);
   EXPCL_PYSTUB int PyCFunction_NewEx(...);
   EXPCL_PYSTUB int PyCallable_Check(...);
   EXPCL_PYSTUB int PyCallable_Check(...);
+  EXPCL_PYSTUB int PyCapsule_GetPointer(...);
+  EXPCL_PYSTUB int PyCapsule_New(...);
   EXPCL_PYSTUB int PyDict_DelItem(...);
   EXPCL_PYSTUB int PyDict_DelItem(...);
   EXPCL_PYSTUB int PyDict_DelItemString(...);
   EXPCL_PYSTUB int PyDict_DelItemString(...);
   EXPCL_PYSTUB int PyDict_GetItem(...);
   EXPCL_PYSTUB int PyDict_GetItem(...);
@@ -133,6 +135,7 @@ extern "C" {
   EXPCL_PYSTUB int PyString_InternInPlace(...);
   EXPCL_PYSTUB int PyString_InternInPlace(...);
   EXPCL_PYSTUB int PyString_Size(...);
   EXPCL_PYSTUB int PyString_Size(...);
   EXPCL_PYSTUB int PySys_GetObject(...);
   EXPCL_PYSTUB int PySys_GetObject(...);
+  EXPCL_PYSTUB int PySys_SetObject(...);
   EXPCL_PYSTUB int PyThreadState_Clear(...);
   EXPCL_PYSTUB int PyThreadState_Clear(...);
   EXPCL_PYSTUB int PyThreadState_Delete(...);
   EXPCL_PYSTUB int PyThreadState_Delete(...);
   EXPCL_PYSTUB int PyThreadState_Get(...);
   EXPCL_PYSTUB int PyThreadState_Get(...);
@@ -216,6 +219,7 @@ extern "C" {
   EXPCL_PYSTUB extern void *PyExc_ImportError;
   EXPCL_PYSTUB extern void *PyExc_ImportError;
   EXPCL_PYSTUB extern void *PyExc_IndexError;
   EXPCL_PYSTUB extern void *PyExc_IndexError;
   EXPCL_PYSTUB extern void *PyExc_KeyError;
   EXPCL_PYSTUB extern void *PyExc_KeyError;
+  EXPCL_PYSTUB extern void *PyExc_NameError;
   EXPCL_PYSTUB extern void *PyExc_OSError;
   EXPCL_PYSTUB extern void *PyExc_OSError;
   EXPCL_PYSTUB extern void *PyExc_OverflowError;
   EXPCL_PYSTUB extern void *PyExc_OverflowError;
   EXPCL_PYSTUB extern void *PyExc_RuntimeError;
   EXPCL_PYSTUB extern void *PyExc_RuntimeError;
@@ -257,6 +261,8 @@ int PyBytes_Size(...) { return 0; }
 int PyCFunction_New(...) { return 0; };
 int PyCFunction_New(...) { return 0; };
 int PyCFunction_NewEx(...) { return 0; };
 int PyCFunction_NewEx(...) { return 0; };
 int PyCallable_Check(...) { return 0; }
 int PyCallable_Check(...) { return 0; }
+int PyCapsule_GetPointer(...) { return 0; }
+int PyCapsule_New(...) { return 0; }
 int PyDict_DelItem(...) { return 0; }
 int PyDict_DelItem(...) { return 0; }
 int PyDict_DelItemString(...) { return 0; }
 int PyDict_DelItemString(...) { return 0; }
 int PyDict_GetItem(...) { return 0; }
 int PyDict_GetItem(...) { return 0; }
@@ -363,6 +369,7 @@ int PyString_FromStringAndSize(...) { return 0; }
 int PyString_InternFromString(...) { return 0; }
 int PyString_InternFromString(...) { return 0; }
 int PyString_InternInPlace(...) { return 0; }
 int PyString_InternInPlace(...) { return 0; }
 int PySys_GetObject(...) { return 0; }
 int PySys_GetObject(...) { return 0; }
+int PySys_SetObject(...) { return 0; }
 int PyThreadState_Clear(...) { return 0; }
 int PyThreadState_Clear(...) { return 0; }
 int PyThreadState_Delete(...) { return 0; }
 int PyThreadState_Delete(...) { return 0; }
 int PyThreadState_Get(...) { return 0; }
 int PyThreadState_Get(...) { return 0; }
@@ -452,6 +459,7 @@ void *PyExc_FutureWarning = nullptr;
 void *PyExc_ImportError = nullptr;
 void *PyExc_ImportError = nullptr;
 void *PyExc_IndexError = nullptr;
 void *PyExc_IndexError = nullptr;
 void *PyExc_KeyError = nullptr;
 void *PyExc_KeyError = nullptr;
+void *PyExc_NameError = nullptr;
 void *PyExc_OSError = nullptr;
 void *PyExc_OSError = nullptr;
 void *PyExc_OverflowError = nullptr;
 void *PyExc_OverflowError = nullptr;
 void *PyExc_RuntimeError = nullptr;
 void *PyExc_RuntimeError = nullptr;

+ 0 - 3
dtool/src/test_interrogate/test_interrogate.cxx

@@ -17,7 +17,6 @@
 #include "interrogate_request.h"
 #include "interrogate_request.h"
 #include "load_dso.h"
 #include "load_dso.h"
 #include "filename.h"
 #include "filename.h"
-#include "pystub.h"
 #include "panda_getopt.h"
 #include "panda_getopt.h"
 #include "preprocess_argv.h"
 #include "preprocess_argv.h"
 
 
@@ -526,8 +525,6 @@ main(int argc, char **argv) {
   extern int optind;
   extern int optind;
   const char *optstr = "p:ftqh";
   const char *optstr = "p:ftqh";
 
 
-  pystub();
-
   bool all_functions = false;
   bool all_functions = false;
   bool all_types = false;
   bool all_types = false;
   bool quick_load = false;
   bool quick_load = false;

+ 16 - 5
makepanda/installer.nsi

@@ -329,13 +329,24 @@ SectionGroup "Python support"
         SetOutPath $INSTDIR\panda3d
         SetOutPath $INSTDIR\panda3d
         File /r "${BUILT}\panda3d\*.py"
         File /r "${BUILT}\panda3d\*.py"
 
 
-        File /r /x bullet.pyd /x ode.pyd /x physx.pyd /x rocket.pyd "${BUILT}\panda3d\*.pyd"
+        File /nonfatal /r "${BUILT}\panda3d\core${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\ai${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\awesomium${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\direct${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\egg${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\fx${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\interrogatedb${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\physics${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\_rplight${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\skel${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\vision${EXT_SUFFIX}"
+        File /nonfatal /r "${BUILT}\panda3d\vrpn${EXT_SUFFIX}"
 
 
         !ifdef HAVE_BULLET
         !ifdef HAVE_BULLET
             SectionGetFlags ${SecBullet} $R0
             SectionGetFlags ${SecBullet} $R0
             IntOp $R0 $R0 & ${SF_SELECTED}
             IntOp $R0 $R0 & ${SF_SELECTED}
             StrCmp $R0 ${SF_SELECTED} 0 SkipBulletPyd
             StrCmp $R0 ${SF_SELECTED} 0 SkipBulletPyd
-            File /nonfatal /r "${BUILT}\panda3d\bullet.pyd"
+            File /nonfatal /r "${BUILT}\panda3d\bullet${EXT_SUFFIX}"
             SkipBulletPyd:
             SkipBulletPyd:
         !endif
         !endif
 
 
@@ -343,7 +354,7 @@ SectionGroup "Python support"
             SectionGetFlags ${SecODE} $R0
             SectionGetFlags ${SecODE} $R0
             IntOp $R0 $R0 & ${SF_SELECTED}
             IntOp $R0 $R0 & ${SF_SELECTED}
             StrCmp $R0 ${SF_SELECTED} 0 SkipODEPyd
             StrCmp $R0 ${SF_SELECTED} 0 SkipODEPyd
-            File /nonfatal /r "${BUILT}\panda3d\ode.pyd"
+            File /nonfatal /r "${BUILT}\panda3d\ode${EXT_SUFFIX}"
             SkipODEPyd:
             SkipODEPyd:
         !endif
         !endif
 
 
@@ -351,7 +362,7 @@ SectionGroup "Python support"
             SectionGetFlags ${SecPhysX} $R0
             SectionGetFlags ${SecPhysX} $R0
             IntOp $R0 $R0 & ${SF_SELECTED}
             IntOp $R0 $R0 & ${SF_SELECTED}
             StrCmp $R0 ${SF_SELECTED} 0 SkipPhysXPyd
             StrCmp $R0 ${SF_SELECTED} 0 SkipPhysXPyd
-            File /nonfatal /r "${BUILT}\panda3d\physx.pyd"
+            File /nonfatal /r "${BUILT}\panda3d\physx${EXT_SUFFIX}"
             SkipPhysXPyd:
             SkipPhysXPyd:
         !endif
         !endif
 
 
@@ -359,7 +370,7 @@ SectionGroup "Python support"
             SectionGetFlags ${SecRocket} $R0
             SectionGetFlags ${SecRocket} $R0
             IntOp $R0 $R0 & ${SF_SELECTED}
             IntOp $R0 $R0 & ${SF_SELECTED}
             StrCmp $R0 ${SF_SELECTED} 0 SkipRocketPyd
             StrCmp $R0 ${SF_SELECTED} 0 SkipRocketPyd
-            File /nonfatal /r "${BUILT}\panda3d\rocket.pyd"
+            File /nonfatal /r "${BUILT}\panda3d\rocket${EXT_SUFFIX}"
             SkipRocketPyd:
             SkipRocketPyd:
         !endif
         !endif
 
 

+ 6 - 1
makepanda/installpanda.py

@@ -175,6 +175,7 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir(
     oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/applications")
     oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/applications")
     oscmd("mkdir -m 0755 -p "+destdir+libdir+"/panda3d")
     oscmd("mkdir -m 0755 -p "+destdir+libdir+"/panda3d")
     oscmd("mkdir -m 0755 -p "+destdir+PPATH)
     oscmd("mkdir -m 0755 -p "+destdir+PPATH)
+    oscmd("mkdir -m 0755 -p "+destdir+PPATH+"/panda3d")
 
 
     if (sys.platform.startswith("freebsd")):
     if (sys.platform.startswith("freebsd")):
         oscmd("mkdir -m 0755 -p "+destdir+prefix+"/etc")
         oscmd("mkdir -m 0755 -p "+destdir+prefix+"/etc")
@@ -194,13 +195,17 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir(
 
 
     oscmd("cp -R "+outputdir+"/include          "+destdir+prefix+"/include/panda3d")
     oscmd("cp -R "+outputdir+"/include          "+destdir+prefix+"/include/panda3d")
     oscmd("cp -R "+outputdir+"/pandac           "+destdir+prefix+"/share/panda3d/")
     oscmd("cp -R "+outputdir+"/pandac           "+destdir+prefix+"/share/panda3d/")
-    oscmd("cp -R "+outputdir+"/panda3d          "+destdir+PPATH+"/")
     oscmd("cp -R "+outputdir+"/models           "+destdir+prefix+"/share/panda3d/")
     oscmd("cp -R "+outputdir+"/models           "+destdir+prefix+"/share/panda3d/")
     if os.path.isdir("samples"):             oscmd("cp -R samples               "+destdir+prefix+"/share/panda3d/")
     if os.path.isdir("samples"):             oscmd("cp -R samples               "+destdir+prefix+"/share/panda3d/")
     if os.path.isdir(outputdir+"/direct"):   oscmd("cp -R "+outputdir+"/direct           "+destdir+prefix+"/share/panda3d/")
     if os.path.isdir(outputdir+"/direct"):   oscmd("cp -R "+outputdir+"/direct           "+destdir+prefix+"/share/panda3d/")
     if os.path.isdir(outputdir+"/Pmw"):      oscmd("cp -R "+outputdir+"/Pmw     "+destdir+prefix+"/share/panda3d/")
     if os.path.isdir(outputdir+"/Pmw"):      oscmd("cp -R "+outputdir+"/Pmw     "+destdir+prefix+"/share/panda3d/")
     if os.path.isdir(outputdir+"/plugins"):  oscmd("cp -R "+outputdir+"/plugins "+destdir+prefix+"/share/panda3d/")
     if os.path.isdir(outputdir+"/plugins"):  oscmd("cp -R "+outputdir+"/plugins "+destdir+prefix+"/share/panda3d/")
 
 
+    suffix = GetExtensionSuffix()
+    for base in os.listdir(outputdir + "/panda3d"):
+        if base.endswith(".py") or (base.endswith(suffix) and '.' not in base[:-len(suffix)]):
+            oscmd("cp "+outputdir+"/panda3d/"+base+" "+destdir+PPATH+"/panda3d/"+base)
+
     WriteMimeFile(destdir+prefix+"/share/mime-info/panda3d.mime", MIME_INFO)
     WriteMimeFile(destdir+prefix+"/share/mime-info/panda3d.mime", MIME_INFO)
     WriteKeysFile(destdir+prefix+"/share/mime-info/panda3d.keys", MIME_INFO)
     WriteKeysFile(destdir+prefix+"/share/mime-info/panda3d.keys", MIME_INFO)
     WriteMimeXMLFile(destdir+prefix+"/share/mime/packages/panda3d.xml", MIME_INFO)
     WriteMimeXMLFile(destdir+prefix+"/share/mime/packages/panda3d.xml", MIME_INFO)

File diff suppressed because it is too large
+ 218 - 266
makepanda/makepanda.py


+ 128 - 9
makepanda/makepandacore.py

@@ -3190,6 +3190,48 @@ def WriteResourceFile(basename, **kwargs):
     ConditionalWriteFile(basename, GenerateResourceFile(**kwargs))
     ConditionalWriteFile(basename, GenerateResourceFile(**kwargs))
     return basename
     return basename
 
 
+
+def WriteEmbeddedStringFile(basename, inputs, string_name=None):
+    if os.path.splitext(basename)[1] not in SUFFIX_INC:
+        basename += '.cxx'
+    target = GetOutputDir() + "/tmp/" + basename
+
+    if string_name is None:
+        string_name = os.path.basename(os.path.splitext(target)[0])
+        string_name = string_name.replace('-', '_')
+
+    data = bytearray()
+    for input in inputs:
+        fp = open(input, 'rb')
+
+        # Insert a #line so that we get meaningful compile/assert errors when
+        # the result is inserted by interrogate_module into generated code.
+        if os.path.splitext(input)[1] in SUFFIX_INC:
+            line = '#line 1 "%s"\n' % (input)
+            data += bytearray(line.encode('ascii', 'replace'))
+
+        data += bytearray(fp.read())
+        fp.close()
+
+    data.append(0)
+
+    output = 'extern const char %s[] = {\n' % (string_name)
+
+    i = 0
+    for byte in data:
+        if i == 0:
+            output += ' '
+
+        output += ' 0x%02x,' % (byte)
+        i += 1
+        if i >= 12:
+            output += '\n'
+            i = 0
+
+    output += '\n};\n'
+    ConditionalWriteFile(target, output)
+    return target
+
 ########################################################################
 ########################################################################
 ##
 ##
 ## FindLocation
 ## FindLocation
@@ -3197,6 +3239,8 @@ def WriteResourceFile(basename, **kwargs):
 ########################################################################
 ########################################################################
 
 
 ORIG_EXT = {}
 ORIG_EXT = {}
+PYABI_SPECIFIC = set()
+WARNED_FILES = set()
 
 
 def GetOrigExt(x):
 def GetOrigExt(x):
     return ORIG_EXT[x]
     return ORIG_EXT[x]
@@ -3207,14 +3251,42 @@ def SetOrigExt(x, v):
 def GetExtensionSuffix():
 def GetExtensionSuffix():
     if sys.version_info >= (3, 0):
     if sys.version_info >= (3, 0):
         suffix = sysconfig.get_config_var('EXT_SUFFIX')
         suffix = sysconfig.get_config_var('EXT_SUFFIX')
-        if suffix:
+        if suffix == '.so':
+            # On my FreeBSD system, this is not set correctly, but SOABI is.
+            soabi = sysconfig.get_config_var('SOABI')
+            if soabi:
+                return '.%s.so' % (soabi)
+        elif suffix:
             return suffix
             return suffix
+
     target = GetTarget()
     target = GetTarget()
     if target == 'windows':
     if target == 'windows':
         return '.pyd'
         return '.pyd'
     else:
     else:
         return '.so'
         return '.so'
 
 
+def GetPythonABI():
+    soabi = sysconfig.get_config_var('SOABI')
+    if soabi:
+        return soabi
+
+    soabi = 'cpython-%d%d' % (sys.version_info[:2])
+
+    debug_flag = sysconfig.get_config_var('Py_DEBUG')
+    if (debug_flag is None and hasattr(sys, 'gettotalrefcount')) or debug_flag:
+        soabi += 'd'
+
+    malloc_flag = sysconfig.get_config_var('WITH_PYMALLOC')
+    if malloc_flag is None or malloc_flag:
+        soabi += 'm'
+
+    if sys.version_info < (3, 3):
+        usize = sysconfig.get_config_var('Py_UNICODE_SIZE')
+        if (usize is None and sys.maxunicode == 0x10ffff) or usize == 4:
+            soabi += 'u'
+
+    return soabi
+
 def CalcLocation(fn, ipath):
 def CalcLocation(fn, ipath):
     if fn.startswith("panda3d/") and fn.endswith(".py"):
     if fn.startswith("panda3d/") and fn.endswith(".py"):
         return OUTPUTDIR + "/" + fn
         return OUTPUTDIR + "/" + fn
@@ -3285,11 +3357,25 @@ def CalcLocation(fn, ipath):
     return fn
     return fn
 
 
 
 
-def FindLocation(fn, ipath):
+def FindLocation(fn, ipath, pyabi=None):
     if (GetLinkAllStatic() and fn.endswith(".dll")):
     if (GetLinkAllStatic() and fn.endswith(".dll")):
         fn = fn[:-4] + ".lib"
         fn = fn[:-4] + ".lib"
     loc = CalcLocation(fn, ipath)
     loc = CalcLocation(fn, ipath)
     base, ext = os.path.splitext(fn)
     base, ext = os.path.splitext(fn)
+
+    # If this is a target created with PyTargetAdd, we need to make sure it
+    # it put in a Python-version-specific directory.
+    if loc in PYABI_SPECIFIC:
+        if loc.startswith(OUTPUTDIR + "/tmp"):
+            if pyabi is not None:
+                loc = OUTPUTDIR + "/tmp/" + pyabi + loc[len(OUTPUTDIR) + 4:]
+            else:
+                raise RuntimeError("%s is a Python-specific target, use PyTargetAdd instead of TargetAdd" % (fn))
+
+        elif ext != ".pyd" and loc not in WARNED_FILES:
+            WARNED_FILES.add(loc)
+            print("%sWARNING:%s file depends on Python but is not in an ABI-specific directory: %s%s%s" % (GetColor("red"), GetColor(), GetColor("green"), loc, GetColor()))
+
     ORIG_EXT[loc] = ext
     ORIG_EXT[loc] = ext
     return loc
     return loc
 
 
@@ -3335,6 +3421,11 @@ def FindLocation(fn, ipath):
 ## be inserted: bison generates an OBJ and a secondary header
 ## be inserted: bison generates an OBJ and a secondary header
 ## file, interrogate generates an IN and a secondary IGATE.OBJ.
 ## file, interrogate generates an IN and a secondary IGATE.OBJ.
 ##
 ##
+## PyTargetAdd is a special version for targets that depend on Python.
+## It will create a target for each Python version we are building with,
+## ensuring that builds with different Python versions won't conflict
+## when we build for multiple Python ABIs side-by-side.
+##
 ########################################################################
 ########################################################################
 
 
 class Target:
 class Target:
@@ -3343,7 +3434,7 @@ class Target:
 TARGET_LIST = []
 TARGET_LIST = []
 TARGET_TABLE = {}
 TARGET_TABLE = {}
 
 
-def TargetAdd(target, dummy=0, opts=[], input=[], dep=[], ipath=None, winrc=None):
+def TargetAdd(target, dummy=0, opts=[], input=[], dep=[], ipath=None, winrc=None, pyabi=None):
     if (dummy != 0):
     if (dummy != 0):
         exit("Syntax error in TargetAdd "+target)
         exit("Syntax error in TargetAdd "+target)
     if ipath is None: ipath = opts
     if ipath is None: ipath = opts
@@ -3351,11 +3442,10 @@ def TargetAdd(target, dummy=0, opts=[], input=[], dep=[], ipath=None, winrc=None
     if (type(input) == str): input = [input]
     if (type(input) == str): input = [input]
     if (type(dep) == str): dep = [dep]
     if (type(dep) == str): dep = [dep]
 
 
-    if os.path.splitext(target)[1] == '.pyd' and PkgSkip("PYTHON"):
-        # It makes no sense to build Python modules with python disabled.
-        return
+    if target.endswith(".pyd") and not pyabi:
+        raise RuntimeError("Use PyTargetAdd to build .pyd targets")
 
 
-    full = FindLocation(target, [OUTPUTDIR + "/include"])
+    full = FindLocation(target, [OUTPUTDIR + "/include"], pyabi=pyabi)
 
 
     if (full not in TARGET_TABLE):
     if (full not in TARGET_TABLE):
         t = Target()
         t = Target()
@@ -3374,7 +3464,7 @@ def TargetAdd(target, dummy=0, opts=[], input=[], dep=[], ipath=None, winrc=None
 
 
     ipath = [OUTPUTDIR + "/tmp"] + GetListOption(ipath, "DIR:") + [OUTPUTDIR+"/include"]
     ipath = [OUTPUTDIR + "/tmp"] + GetListOption(ipath, "DIR:") + [OUTPUTDIR+"/include"]
     for x in input:
     for x in input:
-        fullinput = FindLocation(x, ipath)
+        fullinput = FindLocation(x, ipath, pyabi=pyabi)
         t.inputs.append(fullinput)
         t.inputs.append(fullinput)
         # Don't re-link a library or binary if just its dependency dlls have been altered.
         # Don't re-link a library or binary if just its dependency dlls have been altered.
         # This should work out fine in most cases, and often reduces recompilation time.
         # This should work out fine in most cases, and often reduces recompilation time.
@@ -3413,7 +3503,7 @@ def TargetAdd(target, dummy=0, opts=[], input=[], dep=[], ipath=None, winrc=None
                 t.deps[fulln] = 1
                 t.deps[fulln] = 1
 
 
     for x in dep:
     for x in dep:
-        fulldep = FindLocation(x, ipath)
+        fulldep = FindLocation(x, ipath, pyabi=pyabi)
         t.deps[fulldep] = 1
         t.deps[fulldep] = 1
 
 
     if winrc and GetTarget() == 'windows':
     if winrc and GetTarget() == 'windows':
@@ -3434,3 +3524,32 @@ def TargetAdd(target, dummy=0, opts=[], input=[], dep=[], ipath=None, winrc=None
 
 
     if target.endswith(".pz") and not CrossCompiling():
     if target.endswith(".pz") and not CrossCompiling():
         t.deps[FindLocation("pzip.exe", [])] = 1
         t.deps[FindLocation("pzip.exe", [])] = 1
+
+    if target.endswith(".in"):
+        # Also add a target to compile the _igate.cxx file into an _igate.obj.
+        outbase = os.path.basename(target)[:-3]
+        woutc = OUTPUTDIR + "/tmp/" + outbase + "_igate.cxx"
+        CxxDependencyCache[woutc] = []
+        PyTargetAdd(outbase + "_igate.obj", opts=opts+['PYTHON','BIGOBJ'], input=woutc, dep=target)
+
+
+def PyTargetAdd(target, opts=[], **kwargs):
+    if PkgSkip("PYTHON"):
+        return
+
+    if 'PYTHON' not in opts:
+        opts = opts + ['PYTHON']
+
+    abi = GetPythonABI()
+
+    MakeDirectory(OUTPUTDIR + "/tmp/" + abi)
+
+    # Mark this target as being a Python-specific target.
+    orig = CalcLocation(target, [OUTPUTDIR + "/include"])
+    PYABI_SPECIFIC.add(orig)
+
+    if orig.startswith(OUTPUTDIR + "/tmp/") and os.path.exists(orig):
+        print("Removing file %s" % (orig))
+        os.unlink(orig)
+
+    TargetAdd(target, opts=opts, pyabi=abi, **kwargs)

+ 30 - 17
makepanda/makewheel.py

@@ -560,26 +560,39 @@ def makewheel(version, output_dir, platform=None):
 __version__ = '{0}'
 __version__ = '{0}'
 """.format(version))
 """.format(version))
 
 
+    # Copy the extension modules from the panda3d directory.
+    ext_suffix = GetExtensionSuffix()
+
+    for file in os.listdir(panda3d_dir):
+        if file == '__init__.py':
+            pass
+        elif file.endswith('.py') or (file.endswith(ext_suffix) and '.' not in file[:-len(ext_suffix)]):
+            source_path = os.path.join(panda3d_dir, file)
+
+            if file.endswith('.pyd') and platform.startswith('cygwin'):
+                # Rename it to .dll for cygwin Python to be able to load it.
+                target_path = 'panda3d/' + os.path.splitext(file)[0] + '.dll'
+            else:
+                target_path = 'panda3d/' + file
+
+            whl.write_file(target_path, source_path)
+
+    # And copy the extension modules from the Python installation into the
+    # deploy_libs directory, for use by deploy-ng.
     ext_suffix = '.pyd' if sys.platform in ('win32', 'cygwin') else '.so'
     ext_suffix = '.pyd' if sys.platform in ('win32', 'cygwin') else '.so'
+    ext_mod_dir = get_python_ext_module_dir()
 
 
-    ext_mod_dirs = [
-        (panda3d_dir, 'panda3d/'),
-        (get_python_ext_module_dir(), 'deploy_libs/'),
-    ]
-    for srcdir, targetdir in ext_mod_dirs:
-        for file in os.listdir(srcdir):
-            if file == '__init__.py':
-                pass
-            elif file.endswith(ext_suffix) or file.endswith('.py'):
-                source_path = os.path.join(srcdir, file)
-
-                if file.endswith('.pyd') and platform.startswith('cygwin'):
-                    # Rename it to .dll for cygwin Python to be able to load it.
-                    target_path = targetdir + os.path.splitext(file)[0] + '.dll'
-                else:
-                    target_path = targetdir + file
+    for file in os.listdir(ext_mod_dir):
+        if file.endswith(ext_suffix):
+            source_path = os.path.join(ext_mod_dir, file)
+
+            if file.endswith('.pyd') and platform.startswith('cygwin'):
+                # Rename it to .dll for cygwin Python to be able to load it.
+                target_path = 'deploy_libs/' + os.path.splitext(file)[0] + '.dll'
+            else:
+                target_path = 'deploy_libs/' + file
 
 
-                whl.write_file(target_path, source_path)
+            whl.write_file(target_path, source_path)
 
 
     # Add plug-ins.
     # Add plug-ins.
     for lib in PLUGIN_LIBS:
     for lib in PLUGIN_LIBS:

+ 1 - 1
panda/src/audiotraits/fmodAudioSound.cxx

@@ -651,7 +651,7 @@ get_3d_max_distance() const {
  * a balance [pan] function what is the point?
  * a balance [pan] function what is the point?
  */
  */
 PN_stdfloat FmodAudioSound::
 PN_stdfloat FmodAudioSound::
-get_speaker_mix(AudioManager::SpeakerId speaker) {
+get_speaker_mix(int speaker) {
   ReMutexHolder holder(FmodAudioManager::_lock);
   ReMutexHolder holder(FmodAudioManager::_lock);
   if (_channel == 0) {
   if (_channel == 0) {
     return 0.0;
     return 0.0;

+ 1 - 1
panda/src/audiotraits/fmodAudioSound.h

@@ -126,7 +126,7 @@ public:
 
 
   AudioSound::SoundStatus status() const;
   AudioSound::SoundStatus status() const;
 
 
-  virtual PN_stdfloat get_speaker_mix(AudioManager::SpeakerId speaker);
+  virtual PN_stdfloat get_speaker_mix(int speaker);
   virtual void set_speaker_mix(PN_stdfloat frontleft, PN_stdfloat frontright, PN_stdfloat center, PN_stdfloat sub, PN_stdfloat backleft, PN_stdfloat backright, PN_stdfloat sideleft, PN_stdfloat  sideright);
   virtual void set_speaker_mix(PN_stdfloat frontleft, PN_stdfloat frontright, PN_stdfloat center, PN_stdfloat sub, PN_stdfloat backleft, PN_stdfloat backright, PN_stdfloat sideleft, PN_stdfloat  sideright);
 
 
   void set_active(bool active=true);
   void set_active(bool active=true);

+ 1 - 8
panda/src/event/asyncFuture_ext.cxx

@@ -168,14 +168,7 @@ static PyObject *gen_next(PyObject *self) {
  */
  */
 PyObject *Extension<AsyncFuture>::
 PyObject *Extension<AsyncFuture>::
 __await__(PyObject *self) {
 __await__(PyObject *self) {
-  Dtool_GeneratorWrapper *gen;
-  gen = (Dtool_GeneratorWrapper *)PyType_GenericAlloc(&Dtool_GeneratorWrapper_Type, 0);
-  if (gen != nullptr) {
-    Py_INCREF(self);
-    gen->_base._self = self;
-    gen->_iternext_func = &gen_next;
-  }
-  return (PyObject *)gen;
+  return Dtool_NewGenerator(self, &gen_next);
 }
 }
 
 
 /**
 /**

+ 72 - 0
panda/src/glstuff/glShaderContext_src.cxx

@@ -1145,6 +1145,78 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       }
       }
       return;
       return;
     }
     }
+    if (size > 4 && noprefix.substr(0, 4) == "Fog.") {
+      Shader::ShaderMatSpec bind;
+      bind._id = arg_id;
+      bind._func = Shader::SMF_first;
+      bind._arg[0] = nullptr;
+      bind._dep[0] = Shader::SSD_general | Shader::SSD_fog;
+      bind._part[1] = Shader::SMO_identity;
+      bind._arg[1] = nullptr;
+      bind._dep[1] = Shader::SSD_NONE;
+
+      if (noprefix == "Fog.color") {
+        bind._part[0] = Shader::SMO_attr_fogcolor;
+
+        if (param_type == GL_FLOAT_VEC3) {
+          bind._piece = Shader::SMP_row3x3;
+        } else if (param_type == GL_FLOAT_VEC4) {
+          bind._piece = Shader::SMP_row3;
+        } else {
+          GLCAT.error()
+            << "p3d_Fog.color should be vec3 or vec4\n";
+          return;
+        }
+
+      } else if (noprefix == "Fog.density") {
+        bind._part[0] = Shader::SMO_attr_fog;
+
+        if (param_type == GL_FLOAT) {
+          bind._piece = Shader::SMP_row3x1;
+        } else {
+          GLCAT.error()
+            << "p3d_Fog.density should be float\n";
+          return;
+        }
+
+      } else if (noprefix == "Fog.start") {
+        bind._part[0] = Shader::SMO_attr_fog;
+
+        if (param_type == GL_FLOAT) {
+          bind._piece = Shader::SMP_cell13;
+        } else {
+          GLCAT.error()
+            << "p3d_Fog.start should be float\n";
+          return;
+        }
+
+      } else if (noprefix == "Fog.end") {
+        bind._part[0] = Shader::SMO_attr_fog;
+
+        if (param_type == GL_FLOAT) {
+          bind._piece = Shader::SMP_cell14;
+        } else {
+          GLCAT.error()
+            << "p3d_Fog.end should be float\n";
+          return;
+        }
+
+      } else if (noprefix == "Fog.scale") {
+        bind._part[0] = Shader::SMO_attr_fog;
+
+        if (param_type == GL_FLOAT) {
+          bind._piece = Shader::SMP_cell15;
+        } else {
+          GLCAT.error()
+            << "p3d_Fog.scale should be float\n";
+          return;
+        }
+      }
+
+      _shader->_mat_spec.push_back(bind);
+      _shader->_mat_deps |= bind._dep[0];
+      return;
+    }
     if (noprefix == "LightModel.ambient") {
     if (noprefix == "LightModel.ambient") {
       Shader::ShaderMatSpec bind;
       Shader::ShaderMatSpec bind;
       bind._id = arg_id;
       bind._id = arg_id;

+ 1 - 5
panda/src/gobj/internalName.h

@@ -96,11 +96,7 @@ PUBLISHED:
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
   // These versions are exposed to Python, which have additional logic to map
   // These versions are exposed to Python, which have additional logic to map
   // from Python interned strings.
   // from Python interned strings.
-#if PY_MAJOR_VERSION >= 3
-  EXTENSION(static PT(InternalName) make(PyUnicodeObject *str));
-#else
-  EXTENSION(static PT(InternalName) make(PyStringObject *str));
-#endif
+  EXTENSION(static PT(InternalName) make(PyObject *str));
 #endif
 #endif
 
 
 public:
 public:

+ 12 - 2
panda/src/gobj/internalName_ext.cxx

@@ -24,7 +24,12 @@ using std::string;
  */
  */
 #if PY_MAJOR_VERSION >= 3
 #if PY_MAJOR_VERSION >= 3
 PT(InternalName) Extension<InternalName>::
 PT(InternalName) Extension<InternalName>::
-make(PyUnicodeObject *str) {
+make(PyObject *str) {
+  if (!PyUnicode_Check(str)) {
+    Dtool_Raise_ArgTypeError(str, 0, "InternalName.make", "str");
+    return nullptr;
+  }
+
   if (!PyUnicode_CHECK_INTERNED(str)) {
   if (!PyUnicode_CHECK_INTERNED(str)) {
     // Not an interned string; don't bother.
     // Not an interned string; don't bother.
     Py_ssize_t len = 0;
     Py_ssize_t len = 0;
@@ -50,7 +55,12 @@ make(PyUnicodeObject *str) {
 
 
 #else
 #else
 PT(InternalName) Extension<InternalName>::
 PT(InternalName) Extension<InternalName>::
-make(PyStringObject *str) {
+make(PyObject *str) {
+  if (!PyString_Check(str)) {
+    Dtool_Raise_ArgTypeError(str, 0, "InternalName.make", "str");
+    return nullptr;
+  }
+
   if (!PyString_CHECK_INTERNED(str)) {
   if (!PyString_CHECK_INTERNED(str)) {
     // Not an interned string; don't bother.
     // Not an interned string; don't bother.
     string name(PyString_AS_STRING(str), PyString_GET_SIZE(str));
     string name(PyString_AS_STRING(str), PyString_GET_SIZE(str));

+ 1 - 5
panda/src/gobj/internalName_ext.h

@@ -29,11 +29,7 @@
 template<>
 template<>
 class Extension<InternalName> : public ExtensionBase<InternalName> {
 class Extension<InternalName> : public ExtensionBase<InternalName> {
 public:
 public:
-#if PY_MAJOR_VERSION >= 3
-  static PT(InternalName) make(PyUnicodeObject *str);
-#else
-  static PT(InternalName) make(PyStringObject *str);
-#endif
+  static PT(InternalName) make(PyObject *str);
 };
 };
 
 
 #endif  // HAVE_PYTHON
 #endif  // HAVE_PYTHON

+ 1 - 3
panda/src/ode/odeBody.I

@@ -89,12 +89,10 @@ set_data(void *data) {
   dBodySetData(_id, data);
   dBodySetData(_id, data);
 }
 }
 
 
-#ifndef HAVE_PYTHON
-INLINE void* OdeBody::
+INLINE void *OdeBody::
 get_data() const {
 get_data() const {
   return dBodyGetData(_id);
   return dBodyGetData(_id);
 }
 }
-#endif
 
 
 INLINE void OdeBody::
 INLINE void OdeBody::
 set_position(dReal x, dReal y, dReal z) {
 set_position(dReal x, dReal y, dReal z) {

+ 4 - 23
panda/src/ode/odeBody.cxx

@@ -15,10 +15,6 @@
 #include "odeBody.h"
 #include "odeBody.h"
 #include "odeJoint.h"
 #include "odeJoint.h"
 
 
-#ifdef HAVE_PYTHON
-#include "py_panda.h"
-#endif
-
 TypeHandle OdeBody::_type_handle;
 TypeHandle OdeBody::_type_handle;
 
 
 OdeBody::
 OdeBody::
@@ -38,29 +34,14 @@ OdeBody::
 
 
 void OdeBody::
 void OdeBody::
 destroy() {
 destroy() {
-#ifdef HAVE_PYTHON
-  Py_XDECREF((PyObject*) dBodyGetData(_id));
-#endif
+  if (_destroy_callback != nullptr) {
+    _destroy_callback(*this);
+    _destroy_callback = nullptr;
+  }
   nassertv(_id);
   nassertv(_id);
   dBodyDestroy(_id);
   dBodyDestroy(_id);
 }
 }
 
 
-#ifdef HAVE_PYTHON
-void OdeBody::
-set_data(PyObject *data) {
-  Py_XDECREF((PyObject*) dBodyGetData(_id));
-  Py_XINCREF(data);
-  dBodySetData(_id, data);
-}
-
-PyObject* OdeBody::
-get_data() const {
-  PyObject* data = (PyObject*) dBodyGetData(_id);
-  Py_XINCREF(data);
-  return data;
-}
-#endif
-
 OdeJoint OdeBody::
 OdeJoint OdeBody::
 get_joint(int index) const {
 get_joint(int index) const {
   nassertr(_id != nullptr, OdeJoint(nullptr));
   nassertr(_id != nullptr, OdeJoint(nullptr));

+ 8 - 7
panda/src/ode/odeBody.h

@@ -51,9 +51,7 @@ PUBLISHED:
   INLINE void set_auto_disable_flag(int do_auto_disable);
   INLINE void set_auto_disable_flag(int do_auto_disable);
   INLINE void set_auto_disable_defaults();
   INLINE void set_auto_disable_defaults();
   INLINE void set_data(void *data);
   INLINE void set_data(void *data);
-#ifdef HAVE_PYTHON
-  void set_data(PyObject *data);
-#endif
+  EXTENSION(void set_data(PyObject *data));
 
 
   INLINE void set_position(dReal x, dReal y, dReal z);
   INLINE void set_position(dReal x, dReal y, dReal z);
   INLINE void set_position(const LVecBase3f &pos);
   INLINE void set_position(const LVecBase3f &pos);
@@ -71,11 +69,10 @@ PUBLISHED:
   INLINE int   get_auto_disable_steps() const;
   INLINE int   get_auto_disable_steps() const;
   INLINE dReal get_auto_disable_time() const;
   INLINE dReal get_auto_disable_time() const;
   INLINE int   get_auto_disable_flag() const;
   INLINE int   get_auto_disable_flag() const;
-#ifdef HAVE_PYTHON
-  PyObject* get_data() const;
-#else
-  INLINE void* get_data() const;
+#ifndef CPPPARSER
+  INLINE void *get_data() const;
 #endif
 #endif
+  EXTENSION(PyObject *get_data() const);
 
 
   INLINE LVecBase3f  get_position() const;
   INLINE LVecBase3f  get_position() const;
   INLINE LMatrix3f  get_rotation() const;
   INLINE LMatrix3f  get_rotation() const;
@@ -150,6 +147,10 @@ PUBLISHED:
 private:
 private:
   dBodyID _id;
   dBodyID _id;
 
 
+public:
+  typedef void (*DestroyCallback)(OdeBody &body);
+  DestroyCallback _destroy_callback = nullptr;
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 13 - 0
panda/src/ode/odeBody_ext.I

@@ -13,6 +13,19 @@
 
 
 #include "odeJoint_ext.h"
 #include "odeJoint_ext.h"
 
 
+/**
+ * Returns the custom data associated with the OdeBody.
+ */
+INLINE PyObject *Extension<OdeBody>::
+get_data() const {
+  PyObject *data = (PyObject *)_this->get_data();
+  if (data == nullptr) {
+    data = Py_None;
+  }
+  Py_INCREF(data);
+  return data;
+}
+
 /**
 /**
  * Equivalent to get_joint().convert()
  * Equivalent to get_joint().convert()
  */
  */

+ 37 - 0
panda/src/ode/odeBody_ext.cxx

@@ -0,0 +1,37 @@
+/**
+ * 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."
+ *
+ * @file odeBody_ext.cxx
+ * @author rdb
+ * @date 2018-11-06
+ */
+
+#include "odeBody_ext.h"
+
+static void destroy_callback(OdeBody &body) {
+  Py_XDECREF((PyObject *)body.get_data());
+}
+
+/**
+ * Sets custom data to be associated with the OdeBody.
+ */
+void Extension<OdeBody>::
+set_data(PyObject *data) {
+  void *old_data = _this->get_data();
+
+  if (data != nullptr && data != Py_None) {
+    Py_INCREF(data);
+    _this->set_data((void *)data);
+    _this->_destroy_callback = &destroy_callback;
+  } else {
+    _this->set_data(nullptr);
+    _this->_destroy_callback = nullptr;
+  }
+
+  Py_XDECREF((PyObject *)old_data);
+}

+ 3 - 0
panda/src/ode/odeBody_ext.h

@@ -30,6 +30,9 @@
 template<>
 template<>
 class Extension<OdeBody> : public ExtensionBase<OdeBody> {
 class Extension<OdeBody> : public ExtensionBase<OdeBody> {
 public:
 public:
+  void set_data(PyObject *);
+  INLINE PyObject *get_data() const;
+
   INLINE PyObject *get_converted_joint(int i) const;
   INLINE PyObject *get_converted_joint(int i) const;
 };
 };
 
 

+ 1 - 0
panda/src/ode/p3ode_ext_composite.cxx

@@ -1,3 +1,4 @@
+#include "odeBody_ext.cxx"
 #include "odeGeom_ext.cxx"
 #include "odeGeom_ext.cxx"
 #include "odeJoint_ext.cxx"
 #include "odeJoint_ext.cxx"
 #include "odeSpace_ext.cxx"
 #include "odeSpace_ext.cxx"

Some files were not shown because too many files changed in this diff