Quellcode durchsuchen

Use dynamic type lookup for interrogate to eliminate inter-module dependencies
It is now no longer necessary to link to core.pyd
Also includes a slight coercion optimization for trivial types

rdb vor 10 Jahren
Ursprung
Commit
11ed8a4d8d
57 geänderte Dateien mit 909 neuen und 438 gelöschten Zeilen
  1. 4 1
      doc/man/interrogate_module.1
  2. 11 0
      dtool/src/cppparser/cppArrayType.cxx
  3. 1 0
      dtool/src/cppparser/cppArrayType.h
  4. 11 0
      dtool/src/cppparser/cppConstType.cxx
  5. 1 0
      dtool/src/cppparser/cppConstType.h
  6. 11 0
      dtool/src/cppparser/cppExtensionType.cxx
  7. 1 0
      dtool/src/cppparser/cppExtensionType.h
  8. 11 0
      dtool/src/cppparser/cppFunctionType.cxx
  9. 11 8
      dtool/src/cppparser/cppFunctionType.h
  10. 26 2
      dtool/src/cppparser/cppInstance.cxx
  11. 10 1
      dtool/src/cppparser/cppInstanceIdentifier.cxx
  12. 11 0
      dtool/src/cppparser/cppPointerType.cxx
  13. 1 0
      dtool/src/cppparser/cppPointerType.h
  14. 11 0
      dtool/src/cppparser/cppReferenceType.cxx
  15. 1 3
      dtool/src/cppparser/cppReferenceType.h
  16. 11 0
      dtool/src/cppparser/cppSimpleType.cxx
  17. 1 0
      dtool/src/cppparser/cppSimpleType.h
  18. 91 0
      dtool/src/cppparser/cppStructType.cxx
  19. 1 0
      dtool/src/cppparser/cppStructType.h
  20. 11 0
      dtool/src/cppparser/cppType.cxx
  21. 1 0
      dtool/src/cppparser/cppType.h
  22. 11 0
      dtool/src/cppparser/cppTypedefType.cxx
  23. 1 0
      dtool/src/cppparser/cppTypedefType.h
  24. 0 22
      dtool/src/dtoolbase/typeHandle.I
  25. 4 2
      dtool/src/dtoolbase/typeHandle.h
  26. 5 12
      dtool/src/interrogate/functionRemap.cxx
  27. 323 168
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  28. 1 1
      dtool/src/interrogate/interfaceMakerPythonNative.h
  29. 31 23
      dtool/src/interrogate/interrogateBuilder.cxx
  30. 53 2
      dtool/src/interrogate/interrogate_module.cxx
  31. 56 1
      dtool/src/interrogate/typeManager.cxx
  32. 1 1
      dtool/src/interrogate/typeManager.h
  33. 12 9
      dtool/src/interrogatedb/dtool_super_base.cxx
  34. 0 20
      dtool/src/interrogatedb/interrogateType.cxx
  35. 0 10
      dtool/src/interrogatedb/interrogateType.h
  36. 79 52
      dtool/src/interrogatedb/py_panda.cxx
  37. 24 27
      dtool/src/interrogatedb/py_panda.h
  38. 3 0
      dtool/src/parser-inc/iostream
  39. 18 35
      makepanda/makepanda.py
  40. 1 1
      panda/src/bullet/bulletRigidBodyNode.h
  41. 1 1
      panda/src/egg/eggGroupNode.h
  42. 3 3
      panda/src/express/memoryUsagePointers_ext.cxx
  43. 13 0
      panda/src/express/namable.I
  44. 5 1
      panda/src/express/namable.h
  45. 1 1
      panda/src/gobj/geom.h
  46. 2 2
      panda/src/gobj/geomVertexArrayData.h
  47. 5 5
      panda/src/gobj/geomVertexData.h
  48. 1 1
      panda/src/gobj/texture.h
  49. 1 1
      panda/src/gobj/textureStage.h
  50. 2 6
      panda/src/ode/odeGeom_ext.I
  51. 2 6
      panda/src/ode/odeSpace_ext.I
  52. 1 1
      panda/src/pgraph/camera.h
  53. 2 2
      panda/src/pgraph/nodePath.h
  54. 1 1
      panda/src/pgraph/pandaNode.h
  55. 4 4
      panda/src/pnmimage/pnmImage.h
  56. 3 1
      panda/src/pnmimage/pnmimage_base.h
  57. 1 1
      panda/src/pstatclient/pStatThread.h

+ 4 - 1
doc/man/interrogate_module.1

@@ -1,4 +1,4 @@
-.TH INTERROGATE_MODULE 1 "26 December 2014" "" Panda3D
+.TH INTERROGATE_MODULE 1 "02 June 2015" "" Panda3D
 .SH NAME
 interrogate_module \- generate module-level code for interrogate
 .SH SYNOPSIS
@@ -64,6 +64,9 @@ may be specified. If all are omitted, the default is \fB\-c\fP.
 Generate code within each wrapper function to adjust the global
 variable "in_interpreter" to indicated whether code is running
 within the Panda C++ environment or within the high-level language.
+.TP
+.BI "\-import " module_name
+Used to import an external dependency module.
 .SH "SEE ALSO"
 .BR interrogate (1),
 .BR test_interrogate (1)

+ 11 - 0
dtool/src/cppparser/cppArrayType.cxx

@@ -76,6 +76,17 @@ is_tbd() const {
   return _element_type->is_tbd();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPArrayType::is_trivial
+//       Access: Public, Virtual
+//  Description: Returns true if the type is considered a Plain Old
+//               Data (POD) type.
+////////////////////////////////////////////////////////////////////
+bool CPPArrayType::
+is_trivial() const {
+  return _element_type->is_trivial();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPArrayType::is_equivalent
 //       Access: Public, Virtual

+ 1 - 0
dtool/src/cppparser/cppArrayType.h

@@ -40,6 +40,7 @@ public:
   virtual CPPType *resolve_type(CPPScope *current_scope,
                                 CPPScope *global_scope);
   virtual bool is_tbd() const;
+  virtual bool is_trivial() const;
   virtual bool is_equivalent(const CPPType &other) const;
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 11 - 0
dtool/src/cppparser/cppConstType.cxx

@@ -101,6 +101,17 @@ is_tbd() const {
   return _wrapped_around->is_tbd();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPConstType::is_trivial
+//       Access: Public, Virtual
+//  Description: Returns true if the type is considered a Plain Old
+//               Data (POD) type.
+////////////////////////////////////////////////////////////////////
+bool CPPConstType::
+is_trivial() const {
+  return _wrapped_around->is_trivial();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPConstType::is_equivalent
 //       Access: Public, Virtual

+ 1 - 0
dtool/src/cppparser/cppConstType.h

@@ -38,6 +38,7 @@ public:
                                 CPPScope *global_scope);
 
   virtual bool is_tbd() const;
+  virtual bool is_trivial() const;
   virtual bool is_equivalent(const CPPType &other) const;
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 11 - 0
dtool/src/cppparser/cppExtensionType.cxx

@@ -102,6 +102,17 @@ is_tbd() const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExtensionType::is_trivial
+//       Access: Public, Virtual
+//  Description: Returns true if the type is considered a Plain Old
+//               Data (POD) type.
+////////////////////////////////////////////////////////////////////
+bool CPPExtensionType::
+is_trivial() const {
+  return (_type == T_enum);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPExtensionType::substitute_decl
 //       Access: Public, Virtual

+ 1 - 0
dtool/src/cppparser/cppExtensionType.h

@@ -47,6 +47,7 @@ public:
 
   virtual bool is_incomplete() const;
   virtual bool is_tbd() const;
+  virtual bool is_trivial() const;
 
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
                                           CPPScope *current_scope,

+ 11 - 0
dtool/src/cppparser/cppFunctionType.cxx

@@ -159,6 +159,17 @@ is_tbd() const {
   return _parameters->is_tbd();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPFunctionType::is_trivial
+//       Access: Public, Virtual
+//  Description: Returns true if the type is considered a Plain Old
+//               Data (POD) type.
+////////////////////////////////////////////////////////////////////
+bool CPPFunctionType::
+is_trivial() const {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPFunctionType::output
 //       Access: Public, Virtual

+ 11 - 8
dtool/src/cppparser/cppFunctionType.h

@@ -29,14 +29,16 @@ class CPPIdentifier;
 class CPPFunctionType : public CPPType {
 public:
   enum Flags {
-    F_const_method      = 0x01,
-    F_operator_typecast = 0x02,
-    F_constructor       = 0x04,
-    F_destructor        = 0x08,
-    F_method_pointer    = 0x10,
-    F_unary_op          = 0x20,
-    F_operator          = 0x40,
-    F_noexcept          = 0x80,
+    F_const_method      = 0x001,
+    F_operator_typecast = 0x002,
+    F_constructor       = 0x004,
+    F_destructor        = 0x008,
+    F_method_pointer    = 0x010,
+    F_unary_op          = 0x020,
+    F_operator          = 0x040,
+    F_noexcept          = 0x080,
+    F_copy_constructor  = 0x200,
+    F_move_constructor  = 0x400,
   };
 
   CPPFunctionType(CPPType *return_type, CPPParameterList *parameters,
@@ -57,6 +59,7 @@ public:
                                 CPPScope *global_scope);
 
   virtual bool is_tbd() const;
+  virtual bool is_trivial() const;
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,
                       bool complete) const;

+ 26 - 2
dtool/src/cppparser/cppInstance.cxx

@@ -347,9 +347,33 @@ check_for_constructor(CPPScope *current_scope, CPPScope *global_scope) {
         CPPType *void_type = CPPType::new_type
           (new CPPSimpleType(CPPSimpleType::T_void));
 
+        int flags = func->_flags | CPPFunctionType::F_constructor;
+
+        // Check if it might be a copy or move constructor.
+        CPPParameterList *params = func->_parameters;
+        if (params->_parameters.size() == 1 && !params->_includes_ellipsis) {
+          CPPType *param_type = params->_parameters[0]->_type;
+          CPPReferenceType *ref_type = param_type->as_reference_type();
+
+          if (ref_type != NULL) {
+            param_type = ref_type->_pointing_at;
+
+            if (param_type->get_subtype() == CPPDeclaration::ST_const) {
+              param_type = param_type->as_const_type()->_wrapped_around;
+            }
+
+            if (class_name == param_type->get_simple_name()) {
+              if (ref_type->_value_category == CPPReferenceType::VC_rvalue) {
+                flags |= CPPFunctionType::F_move_constructor;
+              } else {
+                flags |= CPPFunctionType::F_copy_constructor;
+              }
+            }
+          }
+        }
+
         _type = CPPType::new_type
-          (new CPPFunctionType(void_type, func->_parameters,
-                               func->_flags | CPPFunctionType::F_constructor));
+          (new CPPFunctionType(void_type, func->_parameters, flags));
 
       } else if (method_name == "~" + class_name) {
         CPPType *void_type = CPPType::new_type

+ 10 - 1
dtool/src/cppparser/cppInstanceIdentifier.cxx

@@ -166,7 +166,16 @@ add_scoped_pointer_modifier(CPPIdentifier *scoping) {
 ////////////////////////////////////////////////////////////////////
 void CPPInstanceIdentifier::
 add_array_modifier(CPPExpression *expr) {
-  _modifiers.push_back(Modifier::array_type(expr));
+  // Special case for operator new[] and delete[].  We're not really
+  // adding an array modifier to them, but appending [] to the
+  // identifier.  This is to work around a parser ambiguity.
+  if (_ident != NULL && (_ident->get_simple_name() == "operator delete" ||
+                         _ident->get_simple_name() == "operator new")) {
+
+    _ident->_names.back().append_name("[]");
+  } else {
+    _modifiers.push_back(Modifier::array_type(expr));
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 11 - 0
dtool/src/cppparser/cppPointerType.cxx

@@ -103,6 +103,17 @@ is_tbd() const {
   return _pointing_at->is_tbd();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPPointerType::is_trivial
+//       Access: Public, Virtual
+//  Description: Returns true if the type is considered a Plain Old
+//               Data (POD) type.
+////////////////////////////////////////////////////////////////////
+bool CPPPointerType::
+is_trivial() const {
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPPointerType::is_equivalent
 //       Access: Public, Virtual

+ 1 - 0
dtool/src/cppparser/cppPointerType.h

@@ -38,6 +38,7 @@ public:
                                 CPPScope *global_scope);
 
   virtual bool is_tbd() const;
+  virtual bool is_trivial() const;
   virtual bool is_equivalent(const CPPType &other) const;
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 11 - 0
dtool/src/cppparser/cppReferenceType.cxx

@@ -102,6 +102,17 @@ is_tbd() const {
   return _pointing_at->is_tbd();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPReferenceType::is_trivial
+//       Access: Public, Virtual
+//  Description: Returns true if the type is considered a Plain Old
+//               Data (POD) type.
+////////////////////////////////////////////////////////////////////
+bool CPPReferenceType::
+is_trivial() const {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPReferenceType::is_equivalent
 //       Access: Public, Virtual

+ 1 - 3
dtool/src/cppparser/cppReferenceType.h

@@ -35,9 +35,6 @@ public:
   CPPType *_pointing_at;
   ValueCategory _value_category;
 
-  inline bool is_lvalue() const;
-  inline bool is_rvalue() const;
-
   virtual bool is_fully_specified() const;
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
                                           CPPScope *current_scope,
@@ -47,6 +44,7 @@ public:
                                 CPPScope *global_scope);
 
   virtual bool is_tbd() const;
+  virtual bool is_trivial() const;
   virtual bool is_equivalent(const CPPType &other) const;
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 11 - 0
dtool/src/cppparser/cppSimpleType.cxx

@@ -40,6 +40,17 @@ is_tbd() const {
   return (_type == T_unknown);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPSimpleType::is_trivial
+//       Access: Public, Virtual
+//  Description: Returns true if the type is considered a Plain Old
+//               Data (POD) type.
+////////////////////////////////////////////////////////////////////
+bool CPPSimpleType::
+is_trivial() const {
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPSimpleType::is_parameter_expr
 //       Access: Public, Virtual

+ 1 - 0
dtool/src/cppparser/cppSimpleType.h

@@ -66,6 +66,7 @@ public:
   int _flags;
 
   virtual bool is_tbd() const;
+  virtual bool is_trivial() const;
   virtual bool is_parameter_expr() const;
 
   virtual string get_preferred_name() const;

+ 91 - 0
dtool/src/cppparser/cppStructType.cxx

@@ -131,6 +131,97 @@ is_abstract() const {
   return !funcs.empty();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPStructType::is_trivial
+//       Access: Public, Virtual
+//  Description: Returns true if the type is considered a Plain Old
+//               Data (POD) type.
+////////////////////////////////////////////////////////////////////
+bool CPPStructType::
+is_trivial() const {
+  // Make sure all base classes are trivial.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL && !base->is_trivial()) {
+      return false;
+    }
+  }
+
+  assert(_scope != NULL);
+
+  // Make sure all members are trivial.
+  CPPScope::Variables::const_iterator vi;
+  for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) {
+    CPPInstance *instance = (*vi).second;
+    assert(instance != NULL);
+
+    if (instance->_storage_class & CPPInstance::SC_static) {
+      // Static members don't count.
+      continue;
+    }
+
+    if (instance->_initializer != NULL) {
+      // A member with an initializer means the default constructor would
+      // assign a value.  This means the type can't be trivial.
+      return false;
+    }
+
+    // Finally, check if the data member itself is non-trivial.
+    assert(instance->_type != NULL);
+    if (!instance->_type->is_trivial()) {
+      return false;
+    }
+  }
+
+  // Now look for functions that are virtual or con/destructors.
+  bool is_default_constructible = true;
+  CPPScope::Functions::const_iterator fi;
+  for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) {
+    CPPFunctionGroup *fgroup = (*fi).second;
+
+    CPPFunctionGroup::Instances::const_iterator ii;
+    for (ii = fgroup->_instances.begin(); ii != fgroup->_instances.end(); ++ii) {
+      CPPInstance *inst = (*ii);
+
+      if (inst->_storage_class & CPPInstance::SC_virtual) {
+        // Virtual functions are banned right off the bat.
+        return false;
+      }
+
+      assert(inst->_type != (CPPType *)NULL);
+      CPPFunctionType *ftype = inst->_type->as_function_type();
+      assert(ftype != (CPPFunctionType *)NULL);
+
+      if (ftype->_flags & (CPPFunctionType::F_destructor |
+                           CPPFunctionType::F_move_constructor |
+                           CPPFunctionType::F_copy_constructor)) {
+        // User-provided destructors and copy/move constructors are not trivial.
+        return false;
+      }
+
+      if ((ftype->_flags & CPPFunctionType::F_constructor) != 0) {
+        if (ftype->_parameters->_parameters.size() == 0 &&
+            !ftype->_parameters->_includes_ellipsis) {
+          // Same for the default constructor.
+          return false;
+        }
+        // The presence of a non-default constructor makes the class not
+        // default-constructible.
+        is_default_constructible = false;
+      }
+
+      if (fgroup->_name == "operator =") {
+        // Or assignment operators.
+        return false;
+      }
+    }
+  }
+
+  // Finally, the class must be default-constructible.
+  return is_default_constructible;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPStructType::check_virtual
 //       Access: Public

+ 1 - 0
dtool/src/cppparser/cppStructType.h

@@ -47,6 +47,7 @@ public:
   bool check_virtual();
   virtual bool is_fully_specified() const;
   virtual bool is_incomplete() const;
+  virtual bool is_trivial() const;
 
   CPPInstance *get_destructor() const;
 

+ 11 - 0
dtool/src/cppparser/cppType.cxx

@@ -68,6 +68,17 @@ is_tbd() const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPType::is_trivial
+//       Access: Public, Virtual
+//  Description: Returns true if the type is considered a Plain Old
+//               Data (POD) type.
+////////////////////////////////////////////////////////////////////
+bool CPPType::
+is_trivial() const {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPType::is_parameter_expr
 //       Access: Public, Virtual

+ 1 - 0
dtool/src/cppparser/cppType.h

@@ -48,6 +48,7 @@ public:
                                 CPPScope *global_scope);
 
   virtual bool is_tbd() const;
+  virtual bool is_trivial() const;
   virtual bool is_parameter_expr() const;
 
   bool has_typedef_name() const;

+ 11 - 0
dtool/src/cppparser/cppTypedefType.cxx

@@ -178,6 +178,17 @@ is_tbd() const {
   return _type->is_tbd();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::is_trivial
+//       Access: Public, Virtual
+//  Description: Returns true if the type is considered a Plain Old
+//               Data (POD) type.
+////////////////////////////////////////////////////////////////////
+bool CPPTypedefType::
+is_trivial() const {
+  return _type->is_trivial();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPTypedefType::is_fully_specified
 //       Access: Public, Virtual

+ 1 - 0
dtool/src/cppparser/cppTypedefType.h

@@ -42,6 +42,7 @@ public:
 
   virtual bool is_incomplete() const;
   virtual bool is_tbd() const;
+  virtual bool is_trivial() const;
 
   virtual bool is_fully_specified() const;
 

+ 0 - 22
dtool/src/dtoolbase/typeHandle.I

@@ -13,28 +13,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: TypeHandle::Constructor
-//       Access: Published
-//  Description: The default constructor must do nothing, because we
-//               can't guarantee ordering of static initializers.  If
-//               the constructor tried to initialize its value, it
-//               might happen after the value had already been set
-//               previously by another static initializer!
-////////////////////////////////////////////////////////////////////
-INLINE TypeHandle::
-TypeHandle() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeHandle::Copy Constructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE TypeHandle::
-TypeHandle(const TypeHandle &copy) : _index(copy._index) {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: TypeHandle::Equality Operator
 //       Access: Published

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

@@ -94,8 +94,10 @@ PUBLISHED:
               // enum value.
   };
 
-  INLINE TypeHandle();
-  INLINE TypeHandle(const TypeHandle &copy);
+  // The default constructor must do nothing, because we can't
+  // guarantee ordering of static initializers.  If the constructor
+  // tried to initialize its value, it  might happen after the value
+  // had already been set previously by another static initializer!
 
   EXTENSION(static TypeHandle make(PyTypeObject *classobj));
 

+ 5 - 12
dtool/src/interrogate/functionRemap.cxx

@@ -30,8 +30,6 @@
 #include "interrogateType.h"
 #include "pnotify.h"
 
-extern bool inside_python_native;
-
 ////////////////////////////////////////////////////////////////////
 //     Function: FunctionRemap::Constructor
 //       Access: Public
@@ -120,11 +118,7 @@ call_function(ostream &out, int indent_level, bool convert_result,
       InterfaceMaker::indent(out, indent_level)
         << "unref_delete(" << container << ");\n";
     } else {
-      if (inside_python_native) {
-        InterfaceMaker::indent(out, indent_level) << "Dtool_Py_Delete(self);\n";
-      } else {
-        InterfaceMaker::indent(out, indent_level) << "delete " << container << ";\n";
-      }
+      InterfaceMaker::indent(out, indent_level) << "delete " << container << ";\n";
     }
 
   } else if (_type == T_typecast_method) {
@@ -866,13 +860,12 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     break;
 
   case T_constructor:
-    if (!_has_this && _parameters.size() == 1 &&
-        TypeManager::unwrap(_parameters[0]._remap->get_orig_type()) ==
-        TypeManager::unwrap(_return_type->get_orig_type())) {
-      // If this is the only parameter, and it's the same as the
-      // "this" type, this is a copy constructor.
+    if (_ftype->_flags & CPPFunctionType::F_copy_constructor) {
+      // It's a copy constructor.
       _flags |= F_copy_constructor;
 
+    } else if (_ftype->_flags & CPPFunctionType::F_move_constructor) {
+
     } else if (!_has_this && _parameters.size() > 0 &&
                (_cppfunc->_storage_class & CPPInstance::SC_explicit) == 0) {
       // A non-explicit non-copy constructor might be eligible for coercion.

+ 323 - 168
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -40,7 +40,6 @@
 #include <set>
 #include <map>
 
-extern bool     inside_python_native;
 extern          InterrogateType dummy_type;
 extern std::string EXPORT_IMPORT_PREFIX;
 
@@ -724,7 +723,7 @@ write_python_instance(ostream &out, int indent_level, const string &return_expr,
   out << boolalpha;
 
   if (!isExportThisRun(itype._cpptype)) {
-    _external_imports.insert(itype._cpptype);
+    _external_imports.insert(TypeManager::resolve_type(itype._cpptype));
   }
 
   string class_name = itype.get_scoped_name();
@@ -743,7 +742,7 @@ write_python_instance(ostream &out, int indent_level, const string &return_expr,
       << "} else {\n";
     indent(out, indent_level)
       << "  return DTool_CreatePyInstanceTyped((void *)" << return_expr
-      << ", " << CLASS_PREFIX << make_safe_name(class_name) << ", "
+      << ", *Dtool_Ptr_" << make_safe_name(class_name) << ", "
       << owns_memory << ", " << is_const << ", "
       << return_expr << "->as_typed_object()->get_type_index());\n";
     indent(out, indent_level)
@@ -753,7 +752,7 @@ write_python_instance(ostream &out, int indent_level, const string &return_expr,
     indent(out, indent_level)
       << "return "
       << "DTool_CreatePyInstance((void *)" << return_expr << ", "
-      << CLASS_PREFIX << make_safe_name(class_name) << ", "
+      << "*Dtool_Ptr_" << make_safe_name(class_name) << ", "
       << owns_memory << ", " << is_const << ");\n";
   }
 }
@@ -787,8 +786,6 @@ InterfaceMakerPythonNative::
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonNative::
 write_prototypes(ostream &out_code, ostream *out_h) {
-  inside_python_native = true;
-
   Functions::iterator fi;
 
   if (out_h != NULL) {
@@ -817,7 +814,7 @@ write_prototypes(ostream &out_code, ostream *out_h) {
           write_prototypes_class(out_code, out_h, object);
         } else {
           //write_prototypes_class_external(out_code, object);
-          _external_imports.insert(object->_itype._cpptype);
+          //_external_imports.insert(object->_itype._cpptype);
         }
       }
     }
@@ -832,28 +829,62 @@ write_prototypes(ostream &out_code, ostream *out_h) {
     string class_name = type->get_local_name(&parser);
     string safe_name = make_safe_name(class_name);
 
-    out_code << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << safe_name << ";\n";
-    out_code << "IMPORT_THIS void Dtool_PyModuleClassInit_" << safe_name << "(PyObject *module);\n";
+    out_code << "// " << class_name << "\n";
+
+    //out_code << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << safe_name << ";\n";
+    out_code << "static struct Dtool_PyTypedObject *Dtool_Ptr_" << safe_name << ";\n";
+    //out_code << "#define Dtool_Ptr_" << safe_name << " &Dtool_" << safe_name << "\n";
+    //out_code << "IMPORT_THIS void Dtool_PyModuleClassInit_" << safe_name << "(PyObject *module);\n";
 
+    // This is some really ugly code, because we have to store a pointer with a
+    // function of a signature that differs from class to class.  If someone can
+    // think of an elegant way to do this without sacrificing perf, let me know.
     int has_coerce = has_coerce_constructor(type->as_struct_type());
-    if (TypeManager::is_reference_count(type)) {
-      if (has_coerce > 0) {
-        out_code << "IMPORT_THIS bool Dtool_Coerce_" << safe_name << "(PyObject *args, CPT(" << class_name << ") &coerced);\n";
+    if (has_coerce > 0) {
+      if (TypeManager::is_reference_count(type)) {
+        out_code
+          << "inline static bool Dtool_ConstCoerce_" << safe_name << "(PyObject *args, CPT(" << class_name << ") &coerced) {\n"
+          << "  nassertr(Dtool_Ptr_" << safe_name << " != NULL, false);\n"
+          << "  nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_ConstCoerce != NULL, false);\n"
+          << "  return ((bool (*)(PyObject *, CPT(" << class_name << ") &))Dtool_Ptr_" << safe_name << "->_Dtool_ConstCoerce)(args, coerced);\n"
+          << "}\n";
+
         if (has_coerce > 1) {
-          out_code << "IMPORT_THIS bool Dtool_Coerce_" << safe_name << "(PyObject *args, PT(" << class_name << ") &coerced);\n";
+          out_code
+            << "inline static bool Dtool_Coerce_" << safe_name << "(PyObject *args, PT(" << class_name << ") &coerced) {\n"
+            << "  nassertr(Dtool_Ptr_" << safe_name << " != NULL, false);\n"
+            << "  nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_Coerce != NULL, false);\n"
+            << "  return ((bool (*)(PyObject *, PT(" << class_name << ") &))Dtool_Ptr_" << safe_name << "->_Dtool_Coerce)(args, coerced);\n"
+            << "}\n";
         }
-      }
-    } else {
-      if (has_coerce > 0) {
-        out_code << "IMPORT_THIS bool Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " const *&coerced, bool &manage);\n";
+
+      } else if (TypeManager::is_trivial(type)) {
+        out_code
+          << "inline static " << class_name << " *Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " &coerced) {\n"
+          << "  nassertr(Dtool_Ptr_" << safe_name << " != NULL, NULL);\n"
+          << "  nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_Coerce != NULL, NULL);\n"
+          << "  return ((" << class_name << " *(*)(PyObject *, " << class_name << " &))Dtool_Ptr_" << safe_name << "->_Dtool_Coerce)(args, coerced);\n"
+          << "}\n";
+
+      } else {
+        out_code
+          << "inline static bool Dtool_ConstCoerce_" << safe_name << "(PyObject *args, " << class_name << " const *&coerced, bool &manage) {\n"
+          << "  nassertr(Dtool_Ptr_" << safe_name << " != NULL, false);\n"
+          << "  nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_ConstCoerce != NULL, false);\n"
+          << "  return ((bool (*)(PyObject *, " << class_name << " const *&, bool&))Dtool_Ptr_" << safe_name << "->_Dtool_ConstCoerce)(args, coerced, manage);\n"
+          << "}\n";
+
         if (has_coerce > 1) {
-          out_code << "IMPORT_THIS bool Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " *&coerced, bool &manage);\n";
+          out_code
+            << "inline static bool Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " *&coerced, bool &manage) {\n"
+            << "  nassertr(Dtool_Ptr_" << safe_name << " != NULL, false);\n"
+            << "  nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_Coerce != NULL, false);\n"
+            << "  return ((bool (*)(PyObject *, " << class_name << " *&, bool&))Dtool_Ptr_" << safe_name << "->_Dtool_Coerce)(args, coerced, manage);\n"
+            << "}\n";
         }
       }
     }
   }
-
-  inside_python_native = false;
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////////
@@ -919,8 +950,6 @@ write_prototypes_class(ostream &out_code, ostream *out_h, Object *obj) {
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonNative::
 write_functions(ostream &out) {
-  inside_python_native = true;
-
   out << "//********************************************************************\n";
   out << "//*** Functions for .. Global\n" ;
   out << "//********************************************************************\n";
@@ -957,8 +986,6 @@ write_functions(ostream &out) {
       }
     }
   }
-
-  inside_python_native = true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1015,7 +1042,7 @@ write_class_details(ostream &out, Object *obj) {
   // Write the constructors.
   if (obj->_constructors.size() == 0) {
     // There is no constructor - write one that simply outputs an error.
-    out << "int Dtool_Init_" + ClassName + "(PyObject *, PyObject *, PyObject *) {\n"
+    out << "static int Dtool_Init_" + ClassName + "(PyObject *, PyObject *, PyObject *) {\n"
         << "#ifdef NDEBUG\n"
         << "  Dtool_Raise_TypeError(\"cannot init constant class\");\n"
         << "#else\n"
@@ -1027,7 +1054,7 @@ write_class_details(ostream &out, Object *obj) {
   } else {
     for (fi = obj->_constructors.begin(); fi != obj->_constructors.end(); ++fi) {
       Function *func = (*fi);
-      std::string fname = "int Dtool_Init_" + ClassName + "(PyObject *self, PyObject *args, PyObject *kwds)";
+      std::string fname = "static int Dtool_Init_" + ClassName + "(PyObject *self, PyObject *args, PyObject *kwds)";
 
       string expected_params;
       write_function_for_name(out, obj, func->_remaps, fname, expected_params, true, AT_keyword_args, RF_int);
@@ -1040,7 +1067,7 @@ write_class_details(ostream &out, Object *obj) {
   int has_coerce = has_coerce_constructor(cpptype->as_struct_type());
   if (has_coerce > 0) {
     write_coerce_constructor(out, obj, true);
-    if (has_coerce > 1) {
+    if (has_coerce > 1 && !TypeManager::is_trivial(obj->_itype._cpptype)) {
       write_coerce_constructor(out, obj, false);
     }
   }
@@ -1059,28 +1086,28 @@ write_class_details(ostream &out, Object *obj) {
   for (di = details.begin(); di != details.end(); di++) {
     //InterrogateType ptype =idb->get_type(di->first);
     if (di->second._is_legal_py_class && !isExportThisRun(di->second._structType)) {
-      _external_imports.insert(di->second._structType);
+      _external_imports.insert(TypeManager::resolve_type(di->second._structType));
     }
     //out << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << make_safe_name(di->second._to_class_name) << ";\n";
   }
 
   // Write support methods to cast from and to pointers of this type.
   {
-    out << "inline void *Dtool_UpcastInterface_" << ClassName << "(PyObject *self, Dtool_PyTypedObject *requested_type) {\n";
+    out << "static void *Dtool_UpcastInterface_" << ClassName << "(PyObject *self, Dtool_PyTypedObject *requested_type) {\n";
     out << "  Dtool_PyTypedObject *SelfType = ((Dtool_PyInstDef *)self)->_My_Type;\n";
-    out << "  if (SelfType != &Dtool_" << ClassName << ") {\n";
+    out << "  if (SelfType != Dtool_Ptr_" << ClassName << ") {\n";
     out << "    printf(\"" << ClassName << " ** Bad Source Type-- Requesting Conversion from %s to %s\\n\", Py_TYPE(self)->tp_name, requested_type->_PyType.tp_name); fflush(NULL);\n";;
     out << "    return NULL;\n";
     out << "  }\n";
     out << "\n";
     out << "  " << cClassName << " *local_this = (" << cClassName << " *)((Dtool_PyInstDef *)self)->_ptr_to_object;\n";
-    out << "  if (requested_type == &Dtool_" << ClassName << ") {\n";
+    out << "  if (requested_type == Dtool_Ptr_" << ClassName << ") {\n";
     out << "    return local_this;\n";
     out << "  }\n";
 
     for (di = details.begin(); di != details.end(); di++) {
       if (di->second._is_legal_py_class) {
-        out << "  if (requested_type == &Dtool_" << make_safe_name(di->second._to_class_name) << ") {\n";
+        out << "  if (requested_type == Dtool_Ptr_" << make_safe_name(di->second._to_class_name) << ") {\n";
         out << "    return " << di->second._up_cast_string << " local_this;\n";
         out << "  }\n";
       }
@@ -1089,16 +1116,16 @@ write_class_details(ostream &out, Object *obj) {
     out << "  return NULL;\n";
     out << "}\n\n";
 
-    out << "inline void *Dtool_DowncastInterface_" << ClassName << "(void *from_this, Dtool_PyTypedObject *from_type) {\n";
+    out << "static void *Dtool_DowncastInterface_" << ClassName << "(void *from_this, Dtool_PyTypedObject *from_type) {\n";
     out << "  if (from_this == NULL || from_type == NULL) {\n";
     out << "    return NULL;\n";
     out << "  }\n";
-    out << "  if (from_type == &Dtool_" << ClassName << ") {\n";
+    out << "  if (from_type == Dtool_Ptr_" << ClassName << ") {\n";
     out << "    return from_this;\n";
     out << "  }\n";
     for (di = details.begin(); di != details.end(); di++) {
       if (di->second._can_downcast && di->second._is_legal_py_class) {
-        out << "  if (from_type == &Dtool_" << make_safe_name(di->second._to_class_name) << ") {\n";
+        out << "  if (from_type == Dtool_Ptr_" << make_safe_name(di->second._to_class_name) << ") {\n";
         out << "    " << di->second._to_class_name << "* other_this = (" << di->second._to_class_name << "*)from_this;\n" ;
         out << "    return (" << cClassName << "*)other_this;\n";
         out << "  }\n";
@@ -1144,21 +1171,25 @@ write_class_declarations(ostream &out, ostream *out_h, Object *obj) {
   }
   out << "(" << _def->module_name << ", " << class_name << ", " << class_name << "_localtype, " << classNameFromCppName(preferred_name, false) << ");\n";
 
-  out << "EXPORT_THIS void Dtool_PyModuleClassInit_" << class_name << "(PyObject *module);\n";
+  out << "static struct Dtool_PyTypedObject *const Dtool_Ptr_" << class_name << " = &Dtool_" << class_name << ";\n";
+  out << "static void Dtool_PyModuleClassInit_" << class_name << "(PyObject *module);\n";
 
   int has_coerce = has_coerce_constructor(type->as_struct_type());
-  if (TypeManager::is_reference_count(type)) {
-    if (has_coerce > 0) {
-      out << "EXPORT_THIS bool Dtool_Coerce_" << class_name << "(PyObject *args, CPT(" << c_class_name << ") &coerced);\n";
+  if (has_coerce > 0) {
+    if (TypeManager::is_reference_count(type)) {
+      assert(!type->is_trivial());
+      out << "bool Dtool_ConstCoerce_" << class_name << "(PyObject *args, CPT(" << c_class_name << ") &coerced);\n";
       if (has_coerce > 1) {
-        out << "EXPORT_THIS bool Dtool_Coerce_" << class_name << "(PyObject *args, PT(" << c_class_name << ") &coerced);\n";
+        out << "bool Dtool_Coerce_" << class_name << "(PyObject *args, PT(" << c_class_name << ") &coerced);\n";
       }
-    }
-  } else {
-    if (has_coerce > 0) {
-      out << "EXPORT_THIS bool Dtool_Coerce_" << class_name << "(PyObject *args, " << c_class_name << " const *&coerced, bool &manage);\n";
+
+    } else if (TypeManager::is_trivial(type)) {
+      out << "" << c_class_name << " *Dtool_Coerce_" << class_name << "(PyObject *args, " << c_class_name << " &coerced);\n";
+
+    } else {
+      out << "bool Dtool_ConstCoerce_" << class_name << "(PyObject *args, " << c_class_name << " const *&coerced, bool &manage);\n";
       if (has_coerce > 1) {
-        out << "EXPORT_THIS bool Dtool_Coerce_" << class_name << "(PyObject *args, " << c_class_name << " *&coerced, bool &manage);\n";
+        out << "bool Dtool_Coerce_" << class_name << "(PyObject *args, " << c_class_name << " *&coerced, bool &manage);\n";
       }
     }
   }
@@ -1202,7 +1233,7 @@ write_sub_module(ostream &out, Object *obj) {
         << " " << *(obj->_itype._cpptype) << "\n";
 
     if (!isExportThisRun(wrapped_itype._cpptype)) {
-      _external_imports.insert(wrapped_itype._cpptype);
+      _external_imports.insert(TypeManager::resolve_type(wrapped_itype._cpptype));
     }
   }
 
@@ -1210,9 +1241,9 @@ write_sub_module(ostream &out, Object *obj) {
   std::string export_class_name2 = classNameFromCppName(obj->_itype.get_name(), true);
 
 //  out << "  Py_INCREF(&Dtool_" << class_name << ".As_PyTypeObject());\n";
-  out << "  PyModule_AddObject(module, \"" << export_class_name << "\", (PyObject *)&Dtool_" << class_name << ".As_PyTypeObject());\n";
+  out << "  PyModule_AddObject(module, \"" << export_class_name << "\", (PyObject *)&Dtool_" << class_name << ");\n";
   if (export_class_name != export_class_name2) {
-    out << "  PyModule_AddObject(module, \"" << export_class_name2 << "\", (PyObject *)&Dtool_" << class_name << ".As_PyTypeObject());\n";
+    out << "  PyModule_AddObject(module, \"" << export_class_name2 << "\", (PyObject *)&Dtool_" << class_name << ");\n";
   }
 }
 
@@ -1225,19 +1256,62 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
   out << "//*** Module Object Linker ..\n";
   out << "//********************************************************************\n";
 
-  out << "static void BuildInstants(PyObject *module) {\n";
-  out << "  (void) module; // Unused\n";
-
   Objects::iterator oi;
+
+  out << "void Dtool_" << def->library_name << "_RegisterTypes() {\n";
+
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     Object *object = (*oi).second;
-    if (object->_itype.is_enum() && !object->_itype.is_nested()) {
-      int enum_count = object->_itype.number_of_enum_values();
-      if (enum_count > 0) {
-          out << "//********************************************************************\n";
-          out << "//*** Module Enums  .." << object->_itype.get_scoped_name() << "\n";
-          out << "//********************************************************************\n";
+    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 = HasAGetClassTypeFunction(object->_itype._cpptype);
+
+        if (is_typed) {
+          out << "  Dtool_" << class_name << "._type = "
+              << object->_itype._cpptype->get_local_name(&parser)
+              << "::get_class_type();\n"
+              << "  RegisterRuntimeTypedClass(Dtool_" << class_name << ");\n";
+
+        } else {
+          out << "  RegisterNamedClass(\"" << object->_itype.get_scoped_name()
+              << "\", Dtool_" << class_name << ");\n";
+
+          if (IsPandaTypedObject(object->_itype._cpptype->as_struct_type())) {
+            nout << object->_itype.get_scoped_name() << " derives from TypedObject, "
+                 << "but does not define a get_class_type() function.\n";
+          }
+        }
       }
+    }
+  }
+  out << "}\n\n";
+
+  out << "void Dtool_" << def->library_name << "_ResolveExternals() {\n";
+  out << "  // Resolve externally imported types.\n";
+
+  for (std::set<CPPType *>::iterator ii = _external_imports.begin(); ii != _external_imports.end(); ++ii) {
+    string class_name = (*ii)->get_local_name(&parser);
+    string safe_name = make_safe_name(class_name);
+
+    if (HasAGetClassTypeFunction(*ii)) {
+      out << "  Dtool_Ptr_" << safe_name << " = LookupRuntimeTypedClass(" << class_name << "::get_class_type());\n";
+    } else {
+      out << "  Dtool_Ptr_" << safe_name << " = LookupNamedClass(\"" << class_name << "\");\n";
+    }
+  }
+  out << "}\n\n";
+
+  out << "void Dtool_" << def->library_name << "_BuildInstants(PyObject *module) {\n";
+  out << "  (void) module;\n";
+
+  for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
+    Object *object = (*oi).second;
+    if (object->_itype.is_enum() && !object->_itype.is_nested() &&
+        isExportThisRun(object->_itype._cpptype)) {
+      int enum_count = object->_itype.number_of_enum_values();
       for (int xx = 0; xx < enum_count; xx++) {
         string name1 = classNameFromCppName(object->_itype.get_enum_value_name(xx), false);
         string name2 = classNameFromCppName(object->_itype.get_enum_value_name(xx), true);
@@ -1334,10 +1408,10 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
       // Note: we shouldn't add METH_STATIC here, since both METH_STATIC
       // and METH_CLASS are illegal for module-level functions.
 
-      out << "  { \"" << name1 << "\", (PyCFunction) &"
+      out << "  {\"" << name1 << "\", (PyCFunction) &"
           << func->_name << ", " << flags << ", (const char *)" << func->_name << "_comment},\n";
       if (name1 != name2) {
-        out << "  { \"" << name2 << "\", (PyCFunction) &"
+        out << "  {\"" << name2 << "\", (PyCFunction) &"
             << func->_name << ", " << flags << ", (const char *)" << func->_name << "_comment},\n";
       }
     }
@@ -1351,7 +1425,7 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
 
   out << "  {NULL, NULL, 0, NULL}\n" << "};\n\n";
 
-  out << "EXPORT_THIS struct LibraryDef " << def->library_name << "_moddef = {python_simple_funcs, BuildInstants};\n";
+  out << "struct LibraryDef " << def->library_name << "_moddef = {python_simple_funcs};\n";
   if (out_h != NULL) {
     *out_h << "extern struct LibraryDef " << def->library_name << "_moddef;\n";
   }
@@ -1440,6 +1514,11 @@ write_module_class(ostream &out, Object *obj) {
   std::string cClassName =  obj->_itype.get_true_name();
   std::string export_class_name = classNameFromCppName(obj->_itype.get_name(), false);
 
+  bool is_runtime_typed = IsPandaTypedObject(obj->_itype._cpptype->as_struct_type());
+  if (!is_runtime_typed && HasAGetClassTypeFunction(obj->_itype._cpptype)) {
+    is_runtime_typed = true;
+  }
+
   Functions::iterator fi;
   out << "//********************************************************************\n";
   out << "//*** Py Init Code For .. " << ClassName << " | " << export_class_name << "\n" ;
@@ -1555,10 +1634,10 @@ write_module_class(ostream &out, Object *obj) {
       }
 
       // This method has non-slotted remaps, so write it out into the function table.
-      out << "  { \"" << name1 << "\", (PyCFunction) &"
+      out << "  {\"" << name1 << "\", (PyCFunction) &"
           << func->_name << ", " << flags << ", (char *) " << func->_name << "_comment},\n";
       if (name1 != name2) {
-        out << "  { \"" << name2 << "\", (PyCFunction) &"
+        out << "  {\"" << name2 << "\", (PyCFunction) &"
             << func->_name << ", " << flags << ", (char *) " << func->_name << "_comment},\n";
       }
     }
@@ -1566,37 +1645,43 @@ write_module_class(ostream &out, Object *obj) {
 
   if (obj->_protocol_types & Object::PT_make_copy) {
     if (!got_copy) {
-      out << "  { \"__copy__\", (PyCFunction) &copy_from_make_copy, METH_NOARGS, NULL},\n";
+      out << "  {\"__copy__\", (PyCFunction) &copy_from_make_copy, METH_NOARGS, NULL},\n";
       got_copy = true;
     }
   } else if (obj->_protocol_types & Object::PT_copy_constructor) {
     if (!got_copy) {
-      out << "  { \"__copy__\", (PyCFunction) &copy_from_copy_constructor, METH_NOARGS, NULL},\n";
+      out << "  {\"__copy__\", (PyCFunction) &copy_from_copy_constructor, METH_NOARGS, NULL},\n";
       got_copy = true;
     }
   }
 
   if (got_copy && !got_deepcopy) {
-    out << "  { \"__deepcopy__\", (PyCFunction) &map_deepcopy_to_copy, METH_VARARGS, NULL},\n";
+    out << "  {\"__deepcopy__\", (PyCFunction) &map_deepcopy_to_copy, METH_VARARGS, NULL},\n";
   }
 
   MakeSeqs::iterator msi;
   for (msi = obj->_make_seqs.begin(); msi != obj->_make_seqs.end(); ++msi) {
-    string flags = "METH_NOARGS";
-    if (obj->is_static_method((*msi)->_element_name)) {
-      flags += " | METH_CLASS";
-    }
-    string name1 = methodNameFromCppName((*msi)->_seq_name, export_class_name, false);
-    string name2 = methodNameFromCppName((*msi)->_seq_name, export_class_name, true);
-    out << "  { \"" << name1
-        << "\", (PyCFunction) &" << (*msi)->_name << ", " << flags << ", NULL},\n";
-    if (name1 != name2) {
-      out << "  { \"" << name2
+    const string &seq_name = (*msi)->_seq_name;
+
+    if ((seq_name.size() > 4 && seq_name.substr(0, 4) == "get_") ||
+        (seq_name.size() > 7 && seq_name.substr(0, 7) == "modify_")) {
+
+      string flags = "METH_NOARGS";
+      if (obj->is_static_method((*msi)->_element_name)) {
+        flags += " | METH_CLASS";
+      }
+      string name1 = methodNameFromCppName((*msi)->_seq_name, export_class_name, false);
+      string name2 = methodNameFromCppName((*msi)->_seq_name, export_class_name, true);
+      out << "  {\"" << name1
           << "\", (PyCFunction) &" << (*msi)->_name << ", " << flags << ", NULL},\n";
+      if (name1 != name2) {
+        out << "  { \"" << name2
+            << "\", (PyCFunction) &" << (*msi)->_name << ", " << flags << ", NULL},\n";
+      }
     }
   }
 
-  out << "  { NULL, NULL, 0, NULL }\n"
+  out << "  {NULL, NULL, 0, NULL}\n"
       << "};\n\n";
 
   int num_derivations = obj->_itype.number_of_derivations();
@@ -1607,7 +1692,7 @@ write_module_class(ostream &out, Object *obj) {
       const InterrogateType &d_itype = idb->get_type(d_type_Index);
       if (is_cpp_type_legal(d_itype._cpptype)) {
         if (!isExportThisRun(d_itype._cpptype)) {
-          _external_imports.insert(d_itype._cpptype);
+          _external_imports.insert(TypeManager::resolve_type(d_itype._cpptype));
 
           //out << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << make_safe_name(d_itype.get_scoped_name().c_str()) << ";\n";
         }
@@ -2649,7 +2734,7 @@ write_module_class(ostream &out, Object *obj) {
   }
 
   // Output the actual PyTypeObject definition.
-  out << "EXPORT_THIS Dtool_PyTypedObject Dtool_" << ClassName << " = {\n";
+  out << "struct Dtool_PyTypedObject Dtool_" << ClassName << " = {\n";
   out << "  {\n";
   out << "    PyVarObject_HEAD_INIT(NULL, 0)\n";
   // const char *tp_name;
@@ -2848,12 +2933,36 @@ write_module_class(ostream &out, Object *obj) {
   out << "    0, // tp_version_tag\n";
   out << "#endif\n";
   out << "  },\n";
+
+  // It's tempting to initialize the type handle here, but this causes static
+  // init ordering issues; this may run before init_type is called.
+  out << "  TypeHandle::none(),\n";
+  out << "  Dtool_PyModuleClassInit_" << ClassName << ",\n";
   out << "  Dtool_UpcastInterface_" << ClassName << ",\n";
   out << "  Dtool_DowncastInterface_" << ClassName << ",\n";
-  out << "  TypeHandle::none(),\n";
+
+  int has_coerce = has_coerce_constructor(obj->_itype._cpptype->as_struct_type());
+  if (has_coerce > 0) {
+    if (TypeManager::is_reference_count(obj->_itype._cpptype) ||
+        !TypeManager::is_trivial(obj->_itype._cpptype)) {
+      out << "  (CoerceFunction)Dtool_ConstCoerce_" << ClassName << ",\n";
+      if (has_coerce > 1) {
+        out << "  (CoerceFunction)Dtool_Coerce_" << ClassName << ",\n";
+      } else {
+        out << "  (CoerceFunction)0,\n";
+      }
+    } else {
+      out << "  (CoerceFunction)0,\n";
+      out << "  (CoerceFunction)Dtool_Coerce_" << ClassName << ",\n";
+    }
+  } else {
+    out << "  (CoerceFunction)0,\n";
+    out << "  (CoerceFunction)0,\n";
+  }
+
   out << "};\n\n";
 
-  out << "void Dtool_PyModuleClassInit_" << ClassName << "(PyObject *module) {\n";
+  out << "static void Dtool_PyModuleClassInit_" << ClassName << "(PyObject *module) {\n";
   out << "  (void) module; // Unused\n";
   out << "  static bool initdone = false;\n";
   out << "  if (!initdone) {\n";
@@ -2864,11 +2973,14 @@ write_module_class(ostream &out, Object *obj) {
     out << "    // Dependent objects\n";
     string baseargs;
     for (vector<string>::iterator bi = bases.begin(); bi != bases.end(); ++bi) {
-      baseargs += ", &Dtool_" + *bi + ".As_PyTypeObject()";
-      out << "    Dtool_PyModuleClassInit_" << make_safe_name(*bi) << "(NULL);\n";
+      baseargs += ", (PyTypeObject *)Dtool_Ptr_" + *bi;
+      string safe_name = make_safe_name(*bi);
+
+      out << "    assert(Dtool_Ptr_" << safe_name << " != NULL);\n"
+          << "    Dtool_Ptr_" << safe_name << "->_Dtool_ModuleClassInit(NULL);\n";
     }
 
-    out << "    Dtool_" << ClassName << ".As_PyTypeObject().tp_bases = PyTuple_Pack(" << bases.size() << baseargs << ");\n";
+    out << "    Dtool_" << ClassName << "._PyType.tp_bases = PyTuple_Pack(" << bases.size() << baseargs << ");\n";
   }
 
   int num_nested = obj->_itype.number_of_nested_types();
@@ -2901,7 +3013,7 @@ write_module_class(ostream &out, Object *obj) {
   } else {
     out << "    PyObject *dict = PyDict_New();\n";
   }
-  out << "    Dtool_" << ClassName << ".As_PyTypeObject().tp_dict = dict;\n";
+  out << "    Dtool_" << ClassName << "._PyType.tp_dict = dict;\n";
   out << "    PyDict_SetItemString(dict, \"DtoolClassDict\", dict);\n";
 
   // Now go through the nested types again to actually add the dict items.
@@ -2922,9 +3034,9 @@ write_module_class(ostream &out, Object *obj) {
       out << "    Dtool_PyModuleClassInit_" << ClassName1 << "(NULL);\n";
       string name1 = classNameFromCppName(ClassName2, false);
       string name2 = classNameFromCppName(ClassName2, true);
-      out << "    PyDict_SetItemString(dict, \"" << name1 << "\", (PyObject *)&Dtool_" << ClassName1 << ".As_PyTypeObject());\n";
+      out << "    PyDict_SetItemString(dict, \"" << name1 << "\", (PyObject *)&Dtool_" << ClassName1 << ");\n";
       if (name1 != name2) {
-        out << "    PyDict_SetItemString(dict, \"" << name2 << "\", (PyObject *)&Dtool_" << ClassName1 << ".As_PyTypeObject());\n";
+        out << "    PyDict_SetItemString(dict, \"" << name2 << "\", (PyObject *)&Dtool_" << ClassName1 << ");\n";
       }
 
     } else if (nested_obj->_itype.is_typedef()) {
@@ -2943,7 +3055,7 @@ write_module_class(ostream &out, Object *obj) {
       string ClassName2 = make_safe_name(interrogate_type_name(wrapped));
 
       string name1 = classNameFromCppName(ClassName2, false);
-      out << "    PyDict_SetItemString(dict, \"" << name1 << "\", (PyObject *)&Dtool_" << ClassName1 << ".As_PyTypeObject());\n";
+      out << "    PyDict_SetItemString(dict, \"" << name1 << "\", (PyObject *)&Dtool_" << ClassName1 << ");\n";
       // No need to support mangled names for nested typedefs; we only added support recently.
 
     } else if (nested_obj->_itype.is_enum()) {
@@ -2969,28 +3081,12 @@ write_module_class(ostream &out, Object *obj) {
     }
   }
 
-  out << "    if (PyType_Ready(&Dtool_" << ClassName << ".As_PyTypeObject()) < 0) {\n";
-  out << "      Dtool_Raise_TypeError(\"PyType_Ready(" << ClassName << ")\");\n";
-  out << "      return;\n";
-  out << "    }\n";
-
-  out << "    Py_INCREF(&Dtool_" << ClassName << ".As_PyTypeObject());\n";
-
-  // Why make the class a member of itself?
-  //out << "        PyDict_SetItemString(Dtool_" <<ClassName << ".As_PyTypeObject().tp_dict,\"" <<export_class_name<< "\",&Dtool_" <<ClassName << ".As_PyObject());\n";
-
-  bool is_runtime_typed = IsPandaTypedObject(obj->_itype._cpptype->as_struct_type());
-  if (HasAGetClassTypeFunction(obj->_itype)) {
-    is_runtime_typed = true;
-  }
-
-  if (is_runtime_typed) {
-    out << "    RegisterRuntimeClass(&Dtool_" << ClassName << ", " << cClassName << "::get_class_type().get_index());\n";
-  } else {
-    out << "    RegisterRuntimeClass(&Dtool_" << ClassName << ", -1);\n";
-  }
-
-  out << "  }\n";
+  out << "    if (PyType_Ready((PyTypeObject *)&Dtool_" << ClassName << ") < 0) {\n"
+         "      Dtool_Raise_TypeError(\"PyType_Ready(" << ClassName << ")\");\n"
+         "      return;\n"
+         "    }\n"
+         "    Py_INCREF((PyTypeObject *)&Dtool_" << ClassName << ");\n"
+         "  }\n";
 
   // Also write out the explicit alternate names.
   //int num_alt_names = obj->_itype.get_num_alt_names();
@@ -3625,12 +3721,14 @@ write_coerce_constructor(ostream &out, Object *obj, bool is_const) {
   std::string ClassName = make_safe_name(obj->_itype.get_scoped_name());
   std::string cClassName = obj->_itype.get_true_name();
 
+  int return_flags = RF_coerced;
+
   if (TypeManager::is_reference_count(obj->_itype._cpptype)) {
     // The coercion works slightly different for reference counted types, since
     // we can handle those a bit more nicely by taking advantage of the refcount
     // instead of having to use a boolean to indicate that it should be managed.
     if (is_const) {
-      out << "bool Dtool_Coerce_" << ClassName << "(PyObject *args, CPT(" << cClassName << ") &coerced) {\n";
+      out << "bool Dtool_ConstCoerce_" << ClassName << "(PyObject *args, CPT(" << cClassName << ") &coerced) {\n";
     } else {
       out << "bool Dtool_Coerce_" << ClassName << "(PyObject *args, PT(" << cClassName << ") &coerced) {\n";
     }
@@ -3650,9 +3748,26 @@ write_coerce_constructor(ostream &out, Object *obj, bool is_const) {
       out << "    coerced->ref();\n";
       out << "    return true;\n";
     }
+    return_flags |= RF_err_false;
+
+  } else if (TypeManager::is_trivial(obj->_itype._cpptype)) {
+    out << cClassName << " *Dtool_Coerce_" << ClassName << "(PyObject *args, " << cClassName << " &coerced) {\n";
+
+    out << "  " << cClassName << " *local_this;\n";
+    out << "  DTOOL_Call_ExtractThisPointerForType(args, &Dtool_" << ClassName << ", (void**)&local_this);\n";
+    out << "  if (local_this != NULL) {\n";
+    out << "    if (((Dtool_PyInstDef *)args)->_is_const) {\n";
+    out << "      // This is a const object.  Make a copy.\n";
+    out << "      coerced = *(const " << cClassName << " *)local_this;\n";
+    out << "      return &coerced;\n";
+    out << "    }\n";
+    out << "    return local_this;\n";
+
+    return_flags |= RF_err_null;
+
   } else {
     if (is_const) {
-      out << "bool Dtool_Coerce_" << ClassName << "(PyObject *args, " << cClassName << " const *&coerced, bool &manage) {\n";
+      out << "bool Dtool_ConstCoerce_" << ClassName << "(PyObject *args, " << cClassName << " const *&coerced, bool &manage) {\n";
     } else {
       out << "bool Dtool_Coerce_" << ClassName << "(PyObject *args, " << cClassName << " *&coerced, bool &manage) {\n";
     }
@@ -3667,12 +3782,14 @@ write_coerce_constructor(ostream &out, Object *obj, bool is_const) {
     } else {
       out << "    return true;\n";
     }
+
+    return_flags |= RF_err_false;
   }
 
   out << "  }\n\n";
 
   if (map_sets.empty()) {
-    error_return(out, 2, RF_coerced | RF_err_false);
+    error_return(out, 2, return_flags);
     out << "}\n\n";
     return;
   }
@@ -3687,12 +3804,12 @@ write_coerce_constructor(ostream &out, Object *obj, bool is_const) {
     out << "    PyObject *arg = args;\n";
 
     write_function_forset(out, mii->second, mii->first, mii->first, expected_params, 4, false, false,
-                          AT_single_arg, RF_coerced | RF_err_false, true, false);
+                          AT_single_arg, return_flags, true, false);
 
     if (map_sets.size() == 1) {
       out << "  }\n";
       //out << "  PyErr_Clear();\n";
-      error_return(out, 2, RF_coerced | RF_err_false);
+      error_return(out, 2, return_flags);
       out << "}\n\n";
       return;
     }
@@ -3730,7 +3847,7 @@ write_coerce_constructor(ostream &out, Object *obj, bool is_const) {
       indent(out, 6) << "case " << max_args << ": {\n";
 
       write_function_forset(out, mii->second, min_args, max_args, expected_params, 8, false, false,
-                            AT_varargs, RF_coerced | RF_err_false, true, false);
+                            AT_varargs, return_flags, true, false);
 
       indent(out, 8) << "break;\n";
       indent(out, 6) << "}\n";
@@ -3760,13 +3877,13 @@ write_coerce_constructor(ostream &out, Object *obj, bool is_const) {
     }
 
     write_function_forset(out, mii->second, min_args, max_args, expected_params, 6, false, false,
-                          AT_varargs, RF_coerced | RF_err_false, true, false);
+                          AT_varargs, return_flags, true, false);
     indent(out, 4) << "}\n";
   }
 
   out << "  }\n\n";
   //out << "  PyErr_Clear();\n";
-  error_return(out, 2, RF_coerced | RF_err_false);
+  error_return(out, 2, return_flags);
   out << "}\n\n";
 }
 
@@ -5163,7 +5280,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
 
       // need to a forward scope for this class..
       if (!isExportThisRun(obj_type)) {
-        _external_imports.insert(obj_type);
+        _external_imports.insert(TypeManager::resolve_type(obj_type));
       }
 
       string this_class_name;
@@ -5183,19 +5300,50 @@ write_function_instance(ostream &out, FunctionRemap *remap,
           // We use a PointerTo to handle the management here.  It's cleaner
           // that way.
           if (TypeManager::is_const_pointer_to_anything(type)) {
-            extra_convert << 'C';
-          }
-          extra_convert
-            << "PT(" << class_name << ") " << param_name << "_this"
-            << default_expr << ";\n";
+            extra_convert
+              << "CPT(" << class_name << ") " << param_name << "_this"
+              << default_expr << ";\n";
 
-          coerce_call = "Dtool_Coerce_" + make_safe_name(class_name) +
-            "(" + param_name + ", " + param_name + "_this)";
+            coerce_call = "Dtool_ConstCoerce_" + make_safe_name(class_name) +
+              "(" + param_name + ", " + param_name + "_this)";
+          } else {
+            extra_convert
+              << "PT(" << class_name << ") " << param_name << "_this"
+              << default_expr << ";\n";
+
+            coerce_call = "Dtool_Coerce_" + make_safe_name(class_name) +
+              "(" + param_name + ", " + param_name + "_this)";
+          }
 
           // Use move constructor when available for functions that take
           // an actual PointerTo.  This eliminates an unref()/ref() pair.
           pexpr_string = "MOVE(" + param_name + "_this)";
 
+        } else if (TypeManager::is_trivial(obj_type)) {
+          // This is a trivial type, such as TypeHandle or LVecBase4.
+          obj_type->output_instance(extra_convert, param_name + "_local", &parser);
+          extra_convert << ";\n";
+
+          type->output_instance(extra_convert, param_name + "_this", &parser);
+
+          if (is_optional) {
+            extra_convert
+              << default_expr << ";\n"
+              << "if (" << param_name << " != NULL) {\n"
+              << "  " << param_name << "_this";
+          }
+
+          extra_convert << " = Dtool_Coerce_" + make_safe_name(class_name) +
+            "(" + param_name + ", " + param_name + "_local);\n";
+
+          if (is_optional) {
+            extra_convert << "}\n";
+          }
+
+          coerce_call = "(" + param_name + "_this != NULL)";
+
+          pexpr_string = param_name + "_this";
+
         } else  {
           // This is a bit less elegant: we use a bool to store whether
           // we're supposed to clean up the reference afterward.
@@ -5204,8 +5352,13 @@ write_function_instance(ostream &out, FunctionRemap *remap,
             << default_expr << ";\n"
             << "bool " << param_name << "_manage = false;\n";
 
-          coerce_call = "Dtool_Coerce_" + make_safe_name(class_name) +
-            "(" + param_name + ", " + param_name + "_this, " + param_name + "_manage)";
+          if (TypeManager::is_const_pointer_or_ref(orig_type)) {
+            coerce_call = "Dtool_ConstCoerce_" + make_safe_name(class_name) +
+              "(" + param_name + ", " + param_name + "_this, " + param_name + "_manage)";
+          } else {
+            coerce_call = "Dtool_Coerce_" + make_safe_name(class_name) +
+              "(" + param_name + ", " + param_name + "_this, " + param_name + "_manage)";
+          }
 
           extra_cleanup
             << "if (" << param_name << "_manage) {\n"
@@ -5266,13 +5419,13 @@ write_function_instance(ostream &out, FunctionRemap *remap,
           }
           extra_convert
             << "DTOOL_Call_ExtractThisPointerForType(" << param_name
-            << ", &Dtool_" << make_safe_name(class_name)
+            << ", Dtool_Ptr_" << make_safe_name(class_name)
             << ", (void **)&" << param_name << "_this);\n";
         } else {
           extra_convert << boolalpha
             << " = (" << class_name << " *)"
             << "DTOOL_Call_GetPointerThisClass(" << param_name
-            << ", &Dtool_" << make_safe_name(class_name)
+            << ", Dtool_Ptr_" << make_safe_name(class_name)
             << ", " << pn << ", \""
             << method_prefix << methodNameFromCppName(remap, this_class_name, false)
             << "\", " << const_ok << ", " << report_errors << ");\n";
@@ -5462,6 +5615,20 @@ write_function_instance(ostream &out, FunctionRemap *remap,
     manage_return = remap->_return_value_needs_management;
     return_expr = "return_value";
 
+  } else if ((return_flags & RF_coerced) != 0 && TypeManager::is_trivial(remap->_cpptype)) {
+    // Another special case is the coerce constructor for a trivial type.
+    // We don't want to invoke "operator new" unnecessarily.
+    if (is_constructor && remap->_extension) {
+      // Extension constructors are a special case, as usual.
+      indent(out, indent_level)
+        << remap->get_call_str("&coerced", pexprs) << ";\n";
+
+    } else {
+      indent(out, indent_level)
+        << "coerced = " << remap->get_call_str(container, pexprs) << ";\n";
+    }
+    return_expr = "&coerced";
+
   } else {
     // The general case; an ordinary constructor or function.
     return_expr = remap->call_function(out, indent_level, true, container, pexprs);
@@ -5626,7 +5793,10 @@ write_function_instance(ostream &out, FunctionRemap *remap,
     // the C++ code was executing, and report this failure back to Python.
     // Don't do this for coercion constructors since they are called by
     // other wrapper functions which already check this on their own.
-    if (watch_asserts && (return_flags & RF_coerced) == 0) {
+    // Generated getters obviously can't raise asserts.
+    if (watch_asserts && (return_flags & RF_coerced) == 0 &&
+        remap->_type != FunctionRemap::T_getter &&
+        remap->_type != FunctionRemap::T_setter) {
       out << "#ifndef NDEBUG\n";
       indent(out, indent_level)
         << "Notify *notify = Notify::ptr();\n";
@@ -5663,7 +5833,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)), false);
       const InterrogateType &itype = idb->get_type(type_index);
       indent(out, indent_level)
-        << "return DTool_PyInit_Finalize(self, " << return_expr << ", &" << CLASS_PREFIX << make_safe_name(itype.get_scoped_name()) << ", true, false);\n";
+        << "return DTool_PyInit_Finalize(self, (void *)" << return_expr << ", &" << CLASS_PREFIX << make_safe_name(itype.get_scoped_name()) << ", true, false);\n";
 
     } else if (TypeManager::is_integer(orig_type)) {
       if (return_flags & RF_compare) {
@@ -5678,7 +5848,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       indent(out, indent_level) << "return 0;\n";
 
     } else {
-      cerr << "Warning: function has return type " << *orig_type
+      nout << "Warning: function has return type " << *orig_type
            << ", expected int or void:\n" << expected_params << "\n";
       indent(out, indent_level) << "// Don't know what to do with return type "
                                 << *orig_type << ".\n";
@@ -5728,16 +5898,20 @@ write_function_instance(ostream &out, FunctionRemap *remap,
 
     if (return_expr == "coerced") {
       // We already did this earlier...
+      indent(out, indent_level) << "return true;\n";
 
     } else if (TypeManager::is_reference_count(remap->_cpptype)) {
       indent(out, indent_level) << "coerced = MOVE(" << return_expr << ");\n";
+      indent(out, indent_level) << "return true;\n";
+
+    } else if (TypeManager::is_trivial(remap->_cpptype)) {
+      indent(out, indent_level) << "return &coerced;\n";
 
     } else {
       indent(out, indent_level) << "coerced = " << return_expr << ";\n";
       indent(out, indent_level) << "manage = true;\n";
+      indent(out, indent_level) << "return true;\n";
     }
-
-    indent(out, indent_level) << "return true;\n";
   }
 
   // Close the extra braces opened earlier.
@@ -5827,7 +6001,8 @@ error_raise_return(ostream &out, int indent_level, int return_flags,
       out << ");\n";
     }
 
-  } else if ((return_flags & RF_err_null) != 0) {
+  } else if ((return_flags & RF_err_null) != 0 &&
+             (return_flags & RF_pyobject) != 0) {
     // PyErr_Format always returns NULL.  Passing it on directly allows
     // the compiler to make a tiny optimization, so why not.
     indent(out, indent_level) << "return PyErr_Format(PyExc_" << exc_type << ",\n";
@@ -6265,7 +6440,6 @@ record_object(TypeIndex type_index) {
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonNative::
 generate_wrappers() {
-  inside_python_native = true;
   InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
 
   // We use a while loop rather than a simple for loop, because we
@@ -6314,7 +6488,6 @@ generate_wrappers() {
       record_function(dummy_type, func_index);
     }
   }
-  inside_python_native = false;
 }
 
 //////////////////////////////////////////////
@@ -6490,9 +6663,9 @@ has_coerce_constructor(CPPStructType *type) {
       }
 
       if (ftype->_flags & CPPFunctionType::F_constructor) {
-        if (params.size() == 1 &&
-            TypeManager::unwrap(params[0]->_type) == type) {
-          // Skip a copy constructor.
+        if (ftype->_flags & (CPPFunctionType::F_copy_constructor |
+                             CPPFunctionType::F_move_constructor)) {
+          // Skip a copy and move constructor.
           continue;
         } else {
           return 2;
@@ -6626,37 +6799,19 @@ DoesInheritFromIsClass(const CPPStructType *inclass, const std::string &name) {
 // does the class have a supportable GetClassType which returns a TypeHandle.
 //////////////////////////////////////////////////////////////////////////////////////////
 bool InterfaceMakerPythonNative::
-HasAGetClassTypeFunction(const InterrogateType &itype_class) {
-  InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
+HasAGetClassTypeFunction(CPPType *type) {
+  while (type->get_subtype() == CPPDeclaration::ST_typedef) {
+    type = type->as_typedef_type()->_type;
+  }
 
-  int num_methods = itype_class.number_of_methods();
-  int mi;
+  CPPStructType *struct_type = type->as_struct_type();
+  if (struct_type == NULL) {
+    return false;
+  }
 
-  for (mi = 0; mi < num_methods; mi++) {
-    FunctionIndex func_index = itype_class.get_method(mi);
-    const InterrogateFunction &ifunc = idb->get_function(func_index);
-    if (ifunc.get_name() == "get_class_type") {
-      if (ifunc._instances != (InterrogateFunction::Instances *)NULL) {
-        InterrogateFunction::Instances::const_iterator ii;
-        for (ii = ifunc._instances->begin();ii != ifunc._instances->end();++ii) {
-          CPPInstance *cppinst = (*ii).second;
-          CPPFunctionType *cppfunc = cppinst->_type->as_function_type();
+  CPPScope *scope = struct_type->get_scope();
 
-          if (cppfunc != NULL && cppfunc->_return_type != NULL &&
-              cppfunc->_parameters != NULL) {
-            CPPType *ret_type = TypeManager::unwrap(cppfunc->_return_type);
-            if (TypeManager::is_struct(ret_type) &&
-                ret_type->get_simple_name() == "TypeHandle") {
-              if (cppfunc->_parameters->_parameters.size() == 0) {
-                return true;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-  return false;
+  return scope->_functions.find("get_class_type") != scope->_functions.end();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
dtool/src/interrogate/interfaceMakerPythonNative.h

@@ -199,7 +199,7 @@ public:
   bool DoesInheritFromIsClass(const CPPStructType * inclass, const std::string &name);
   bool IsPandaTypedObject(CPPStructType * inclass) { return DoesInheritFromIsClass(inclass,"TypedObject"); };
   void write_python_instance(ostream &out, int indent_level, const std::string &return_expr, bool owns_memory, const InterrogateType &itype, bool is_const);
-  bool HasAGetClassTypeFunction(const InterrogateType &itype_class);
+  bool HasAGetClassTypeFunction(CPPType *type);
   int NeedsAStrFunction(const InterrogateType &itype_class);
   int NeedsAReprFunction(const InterrogateType &itype_class);
   bool NeedsARichCompareFunction(const InterrogateType &itype_class);

+ 31 - 23
dtool/src/interrogate/interrogateBuilder.cxx

@@ -53,7 +53,6 @@
 
 InterrogateBuilder builder;
 std::string EXPORT_IMPORT_PREFIX;
-bool inside_python_native = false;
 
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateBuilder::add_source_file
@@ -1912,27 +1911,29 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type) {
   CPPType *return_type = NULL;
 
   CPPFunctionGroup *fgroup = make_property->_getter;
-  CPPFunctionGroup::Instances::const_iterator fi;
-  for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
-    CPPInstance *function = (*fi);
-    CPPFunctionType *ftype =
-      function->_type->as_function_type();
-    if (ftype != NULL && ftype->_parameters->_parameters.size() == 0) {
-      getter = function;
-      return_type = ftype->_return_type;
-
-      // The return type of the non-const method probably better represents
-      // the type of the property we are creating.
-      if ((ftype->_flags & CPPFunctionType::F_const_method) == 0) {
-        break;
+  if (fgroup != NULL) {
+    CPPFunctionGroup::Instances::const_iterator fi;
+    for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
+      CPPInstance *function = (*fi);
+      CPPFunctionType *ftype =
+        function->_type->as_function_type();
+      if (ftype != NULL && ftype->_parameters->_parameters.size() == 0) {
+        getter = function;
+        return_type = ftype->_return_type;
+
+        // The return type of the non-const method probably better represents
+        // the type of the property we are creating.
+        if ((ftype->_flags & CPPFunctionType::F_const_method) == 0) {
+          break;
+        }
       }
     }
-  }
 
-  if (getter == NULL || return_type == NULL) {
-    cerr << "No instance of getter '"
-         << make_property->_getter->_name << "' is suitable!\n";
-    return 0;
+    if (getter == NULL || return_type == NULL) {
+      cerr << "No instance of getter '"
+           << fgroup->_name << "' is suitable!\n";
+      return 0;
+    }
   }
 
   InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
@@ -1944,11 +1945,17 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type) {
   iproperty._name = make_property->get_simple_name();
   iproperty._scoped_name = descope(make_property->get_local_name(&parser));
 
-  iproperty._type = get_type(return_type, false);
+  if (return_type != NULL) {
+    iproperty._type = get_type(return_type, false);
+  } else {
+    iproperty._type = 0;
+  }
 
-  iproperty._flags |= InterrogateElement::F_has_getter;
-  iproperty._getter = get_function(getter, "", struct_type,
-                                   struct_type->get_scope(), 0);
+  if (getter != NULL) {
+    iproperty._flags |= InterrogateElement::F_has_getter;
+    iproperty._getter = get_function(getter, "", struct_type,
+                                     struct_type->get_scope(), 0);
+  }
 
   // See if there happens to be a comment before the MAKE_PROPERTY macro.
   if (make_property->_leading_comment != (CPPCommentBlock *)NULL) {
@@ -1958,6 +1965,7 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type) {
   // Now look for setters.
   fgroup = make_property->_setter;
   if (fgroup != NULL) {
+    CPPFunctionGroup::Instances::const_iterator fi;
     for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
       CPPInstance *function = (*fi);
       iproperty._flags |= InterrogateElement::F_has_setter;

+ 53 - 2
dtool/src/interrogate/interrogate_module.cxx

@@ -25,6 +25,7 @@
 #include "panda_getopt_long.h"
 #include "preprocess_argv.h"
 #include "pset.h"
+#include "vector_string.h"
 
 Filename output_code_filename;
 string module_name;
@@ -33,6 +34,7 @@ bool build_c_wrappers = false;
 bool build_python_wrappers = false;
 bool build_python_native_wrappers = false;
 bool track_interpreter = false;
+vector_string imports;
 
 // Short command-line options.
 static const char *short_options = "";
@@ -46,6 +48,7 @@ enum CommandOptions {
   CO_python,
   CO_python_native,
   CO_track_interpreter,
+  CO_import,
 };
 
 static struct option long_options[] = {
@@ -56,6 +59,7 @@ static struct option long_options[] = {
   { "python", no_argument, NULL, CO_python },
   { "python-native", no_argument, NULL, CO_python_native },
   { "track-interpreter", no_argument, NULL, CO_track_interpreter },
+  { "import", required_argument, NULL, CO_import },
   { NULL }
 };
 
@@ -113,6 +117,9 @@ int write_python_table_native(ostream &out) {
   for(ii = libraries.begin(); ii != libraries.end(); ii++) {
     printf("Referencing Library %s\n", (*ii).c_str());
     out << "extern LibraryDef " << *ii << "_moddef;\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 << "\n"
@@ -138,6 +145,19 @@ int write_python_table_native(ostream &out) {
     out << "  in_interpreter = 1;\n";
   }
 
+  vector_string::const_iterator si;
+  for (si = imports.begin(); si != imports.end(); ++si) {
+    out << "  PyImport_Import(PyUnicode_FromString(\"" << *si << "\"));\n";
+  }
+
+  for (ii = libraries.begin(); ii != libraries.end(); ii++) {
+    out << "  Dtool_" << *ii << "_RegisterTypes();\n";
+  }
+  for (ii = libraries.begin(); ii != libraries.end(); ii++) {
+    out << "  Dtool_" << *ii << "_ResolveExternals();\n";
+  }
+  out << "\n";
+
   out << "  LibraryDef *defs[] = {";
   for(ii = libraries.begin(); ii != libraries.end(); ii++) {
     out << "&" << *ii << "_moddef, ";
@@ -145,7 +165,15 @@ int write_python_table_native(ostream &out) {
 
   out << "NULL};\n"
       << "\n"
-      << "  return Dtool_PyModuleInitHelper(defs, &py_" << library_name << "_module);\n"
+      << "  PyObject *module = Dtool_PyModuleInitHelper(defs, &py_" << library_name << "_module);\n"
+      << "  if (module != NULL) {\n";
+
+  for (ii = libraries.begin(); ii != libraries.end(); ii++) {
+    out << "    Dtool_" << *ii << "_BuildInstants(module);\n";
+  }
+
+  out << "  }\n"
+      << "  return module;\n"
       << "}\n"
       << "\n"
       << "#else  // Python 2 case\n"
@@ -162,6 +190,18 @@ int write_python_table_native(ostream &out) {
     out << "  in_interpreter = 1;\n";
   }
 
+  for (si = imports.begin(); si != imports.end(); ++si) {
+    out << "  PyImport_Import(PyUnicode_FromString(\"" << *si << "\"));\n";
+  }
+
+  for (ii = libraries.begin(); ii != libraries.end(); ii++) {
+    out << "  Dtool_" << *ii << "_RegisterTypes();\n";
+  }
+  for (ii = libraries.begin(); ii != libraries.end(); ii++) {
+    out << "  Dtool_" << *ii << "_ResolveExternals();\n";
+  }
+  out << "\n";
+
   out << "  LibraryDef *defs[] = {";
   for(ii = libraries.begin(); ii != libraries.end(); ii++) {
     out << "&" << *ii << "_moddef, ";
@@ -169,7 +209,14 @@ int write_python_table_native(ostream &out) {
 
   out << "NULL};\n"
       << "\n"
-      << "  Dtool_PyModuleInitHelper(defs, \"" << library_name << "\");\n"
+      << "  PyObject *module = Dtool_PyModuleInitHelper(defs, \"" << library_name << "\");\n"
+      << "  if (module != NULL) {\n";
+
+  for (ii = libraries.begin(); ii != libraries.end(); ii++) {
+    out << "    Dtool_" << *ii << "_BuildInstants(module);\n";
+  }
+
+  out << "  }\n"
       << "}\n"
       << "#endif\n"
       << "\n";
@@ -335,6 +382,10 @@ int main(int argc, char *argv[]) {
       track_interpreter = true;
       break;
 
+    case CO_import:
+      imports.push_back(optarg);
+      break;
+
     default:
       exit(1);
     }

+ 56 - 1
dtool/src/interrogate/typeManager.cxx

@@ -2570,4 +2570,59 @@ is_local(CPPType *source_type) {
 
  return false;
  */
-};
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_trivial
+//       Access: Public, Static
+//  Description: Returns true if the type is trivial (or trivial
+//               enough for our purposes).
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_trivial(CPPType *source_type) {
+  switch (source_type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_trivial(source_type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_reference:
+    return false;
+
+  case CPPDeclaration::ST_pointer:
+    return true;
+
+  case CPPDeclaration::ST_simple:
+    return true;
+
+  case CPPDeclaration::ST_typedef:
+    return is_trivial(source_type->as_typedef_type()->_type);
+
+  default:
+    if (source_type->is_trivial()) {
+      return true;
+    } else {
+      // This is a bit of a hack.  is_trivial() returns false for types that
+      // have an empty constructor (since we can't use =default yet).
+      // For the other classes, it's just convenient to consider them trivial
+      // even if they aren't, since they are simple enough.
+      string name = source_type->get_simple_name();
+      return (name == "ButtonHandle" || name == "DatagramIterator" ||
+              name == "BitMask" || name == "Filename" || name == "pixel" ||
+              name == "NodePath" || name == "LoaderOptions" ||
+              name == "PointerToArray" || name == "ConstPointerToArray" ||
+              name == "PStatThread" ||
+              (name.size() >= 6 && name.substr(0, 6) == "LPlane") ||
+              (name.size() > 6 && name.substr(0, 6) == "LPoint") ||
+              (name.size() > 7 && name.substr(0, 7) == "LVector") ||
+              (name.size() > 7 && name.substr(0, 7) == "LMatrix") ||
+              (name.size() > 8 && name.substr(0, 8) == "LVecBase") ||
+              (name.size() >= 9 && name.substr(0, 9) == "LParabola") ||
+              (name.size() >= 9 && name.substr(0, 9) == "LRotation") ||
+              (name.size() >= 11 && name.substr(0, 11) == "LQuaternion") ||
+              (name.size() >= 12 && name.substr(0, 12) == "LOrientation") ||
+              (name.size() > 16 && name.substr(0, 16) == "UnalignedLMatrix") ||
+              (name.size() > 17 && name.substr(0, 17) == "UnalignedLVecBase"));
+    }
+  }
+
+  return false;
+}

+ 1 - 1
dtool/src/interrogate/typeManager.h

@@ -146,7 +146,7 @@ public:
 
   static bool is_exported(CPPType *type);
   static bool is_local(CPPType *type);
-
+  static bool is_trivial(CPPType *type);
 };
 
 #endif

+ 12 - 9
dtool/src/interrogatedb/dtool_super_base.cxx

@@ -21,7 +21,7 @@ class EmptyClass {
 Define_Module_Class_Private(dtoolconfig, DTOOL_SUPER_BASE, EmptyClass, DTOOL_SUPER_BASE111);
 
 static PyObject *GetSuperBase(PyObject *self) {
-  Py_INCREF(&(Dtool_DTOOL_SUPER_BASE.As_PyTypeObject())); // order is important .. this is used for static functions
+  Py_INCREF((PyTypeObject *)&Dtool_DTOOL_SUPER_BASE); // order is important .. this is used for static functions
   return (PyObject *) &Dtool_DTOOL_SUPER_BASE;
 };
 
@@ -35,21 +35,21 @@ EXPCL_DTOOLCONFIG void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module
   if (!initdone) {
 
     initdone = true;
-    Dtool_DTOOL_SUPER_BASE.As_PyTypeObject().tp_dict = PyDict_New();
-    PyDict_SetItemString(Dtool_DTOOL_SUPER_BASE.As_PyTypeObject().tp_dict, "DtoolClassDict", Dtool_DTOOL_SUPER_BASE.As_PyTypeObject().tp_dict);
+    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(&Dtool_DTOOL_SUPER_BASE.As_PyTypeObject()) < 0) {
+    if (PyType_Ready((PyTypeObject *)&Dtool_DTOOL_SUPER_BASE) < 0) {
       PyErr_SetString(PyExc_TypeError, "PyType_Ready(Dtool_DTOOL_SUPER_BASE)");
       return;
     }
-    Py_INCREF(&Dtool_DTOOL_SUPER_BASE.As_PyTypeObject());
+    Py_INCREF((PyTypeObject *)&Dtool_DTOOL_SUPER_BASE);
 
-    PyDict_SetItemString(Dtool_DTOOL_SUPER_BASE.As_PyTypeObject().tp_dict, "DtoolGetSuperBase", PyCFunction_New(&Dtool_Methods_DTOOL_SUPER_BASE[0], &Dtool_DTOOL_SUPER_BASE.As_PyObject()));
+    PyDict_SetItemString(Dtool_DTOOL_SUPER_BASE._PyType.tp_dict, "DtoolGetSuperBase", PyCFunction_New(&Dtool_Methods_DTOOL_SUPER_BASE[0], (PyObject *)&Dtool_DTOOL_SUPER_BASE));
   }
 
   if (module != NULL) {
-    Py_INCREF(&Dtool_DTOOL_SUPER_BASE.As_PyTypeObject());
-    PyModule_AddObject(module, "DTOOL_SUPER_BASE", (PyObject *)&Dtool_DTOOL_SUPER_BASE.As_PyTypeObject());
+    Py_INCREF((PyTypeObject *)&Dtool_DTOOL_SUPER_BASE);
+    PyModule_AddObject(module, "DTOOL_SUPER_BASE", (PyObject *)&Dtool_DTOOL_SUPER_BASE);
   }
 }
 
@@ -123,9 +123,12 @@ EXPORT_THIS Dtool_PyTypedObject Dtool_DTOOL_SUPER_BASE = {
     0,
     0,
   },
+  TypeHandle::none(),
+  Dtool_PyModuleClassInit_DTOOL_SUPER_BASE,
   Dtool_UpcastInterface_DTOOL_SUPER_BASE,
   Dtool_DowncastInterface_DTOOL_SUPER_BASE,
-  TypeHandle::none(),
+  NULL,
+  NULL,
 };
 
 #endif  // HAVE_PYTHON

+ 0 - 20
dtool/src/interrogatedb/interrogateType.cxx

@@ -269,23 +269,3 @@ remap_indices(const IndexRemapper &remap) {
   }
 
 }
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: GetRunTimeDictionary
-////////////////////////////////////////////////////////////////////
-EXPCL_DTOOLCONFIG RunTimeTypeDictionary & GetRunTimeDictionary()
-{
-    static RunTimeTypeDictionary dict;
-    return dict;
-};
-
-////////////////////////////////////////////////////////////////////
-//     Function: GetRunTimeTypeList
-////////////////////////////////////////////////////////////////////
-EXPCL_DTOOLCONFIG RunTimeTypeList & GetRunTimeTypeList()
-{
-    static RunTimeTypeList list;
-    return list;
-};
-

+ 0 - 10
dtool/src/interrogatedb/interrogateType.h

@@ -231,14 +231,4 @@ INLINE istream &operator >> (istream &in, InterrogateType::EnumValue &d);
 
 #include "interrogateType.I"
 
-#include <set>
-#include <map>
-struct Dtool_PyTypedObject;
-typedef std::map< int , Dtool_PyTypedObject *>   RunTimeTypeDictionary;
-typedef std::set<int >                           RunTimeTypeList;
-
-EXPCL_DTOOLCONFIG  RunTimeTypeDictionary & GetRunTimeDictionary();
-EXPCL_DTOOLCONFIG  RunTimeTypeList & GetRunTimeTypeList();
-
-
 #endif

+ 79 - 52
dtool/src/interrogatedb/py_panda.cxx

@@ -26,6 +26,10 @@ PyMemberDef standard_type_members[] = {
   {NULL}  /* Sentinel */
 };
 
+static RuntimeTypeMap runtime_type_map;
+static RuntimeTypeSet runtime_type_set;
+static NamedTypeMap named_type_map;
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DtoolCanThisBeAPandaInstance
 //  Description: Given a valid (non-NULL) PyObject, does a simple
@@ -360,7 +364,7 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
         /////////////////////////////////////////////
         // ask class to allocate an instance..
         /////////////////////////////////////////////
-        Dtool_PyInstDef *self = (Dtool_PyInstDef *) target_class->As_PyTypeObject().tp_new(&target_class->As_PyTypeObject(), NULL, NULL);
+        Dtool_PyInstDef *self = (Dtool_PyInstDef *) target_class->_PyType.tp_new(&target_class->_PyType, NULL, NULL);
         if (self != NULL) {
           self->_ptr_to_object = new_local_this;
           self->_memory_rules = memory_rules;
@@ -377,7 +381,7 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
   // if we get this far .. just wrap the thing in the known type ??
   //    better than aborting...I guess....
   /////////////////////////////////////////////////////
-  Dtool_PyInstDef *self = (Dtool_PyInstDef *) known_class_type.As_PyTypeObject().tp_new(&known_class_type.As_PyTypeObject(), NULL, NULL);
+  Dtool_PyInstDef *self = (Dtool_PyInstDef *) known_class_type._PyType.tp_new(&known_class_type._PyType, NULL, NULL);
   if (self != NULL) {
     self->_ptr_to_object = local_this_in;
     self->_memory_rules = memory_rules;
@@ -401,7 +405,7 @@ PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_class
   }
 
   Dtool_PyTypedObject *classdef = &in_classdef;
-  Dtool_PyInstDef *self = (Dtool_PyInstDef *) classdef->As_PyTypeObject().tp_new(&classdef->As_PyTypeObject(), NULL, NULL);
+  Dtool_PyInstDef *self = (Dtool_PyInstDef *) classdef->_PyType.tp_new(&classdef->_PyType, NULL, NULL);
   if (self != NULL) {
     self->_ptr_to_object = local_this;
     self->_memory_rules = memory_rules;
@@ -446,42 +450,97 @@ void Dtool_Accum_MethDefs(PyMethodDef in[], MethodDefmap &themap) {
 //
 ///////////////////////////////////////////////////////////////////////////////
 void
-RegisterRuntimeClass(Dtool_PyTypedObject *otype, int class_id) {
-  if (class_id == 0) {
+RegisterNamedClass(const string &name, Dtool_PyTypedObject &otype) {
+  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
+      << "Class " << otype._PyType.tp_name
       << " has a zero TypeHandle value; check that init_type() is called.\n";
 
-  } else if (class_id > 0) {
-    RunTimeTypeDictionary &dict = GetRunTimeDictionary();
-    pair<RunTimeTypeDictionary::iterator, bool> result =
-      dict.insert(RunTimeTypeDictionary::value_type(class_id, otype));
+  } 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 {
+    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 class_id.
+      // 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
+        << "Classes " << otype._PyType.tp_name
         << " and " << other_type->_PyType.tp_name
-        << " share the same TypeHandle value (" << class_id
+        << " share the same TypeHandle value (" << type_index
         << "); check class definitions.\n";
 
     } else {
-      GetRunTimeTypeList().insert(class_id);
-      otype->_type = TypeRegistry::ptr()->find_type_by_id(class_id);
+      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 NULL;
+  } 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 NULL;
+  } else {
+    return it->second;
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 Dtool_PyTypedObject *Dtool_RuntimeTypeDtoolType(int type) {
-  RunTimeTypeDictionary::iterator di = GetRunTimeDictionary().find(type);
-  if (di != GetRunTimeDictionary().end()) {
+  RuntimeTypeMap::iterator di = runtime_type_map.find(type);
+  if (di != runtime_type_map.end()) {
     return di->second;
   } else {
-    int type2 = get_best_parent_from_Set(type, GetRunTimeTypeList());
-    di = GetRunTimeDictionary().find(type2);
-    if (di != GetRunTimeDictionary().end()) {
+    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;
     }
   }
@@ -526,11 +585,6 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
 #endif
   }
 
-  // the constant inits... enums, classes ...
-  for (int y = 0; defs[y] != NULL; y++) {
-    defs[y]->_constants(module);
-  }
-
   PyModule_AddIntConstant(module, "Dtool_PyNativeInterface", 1);
   return module;
 }
@@ -710,33 +764,6 @@ PyObject *DTOOL_PyObject_RichCompare(PyObject *v1, PyObject *v2, int op) {
   return PyBool_FromLong(result);
 }
 
-PyObject *make_list_for_item(PyObject *self, const char *num_name,
-                             const char *element_name) {
-  PyObject *num_result = PyObject_CallMethod(self, (char *)num_name, (char *)"()");
-  if (num_result == NULL) {
-    return NULL;
-  }
-
-  Py_ssize_t num_elements;
-#if PY_MAJOR_VERSION >= 3
-  num_elements = PyLong_AsSsize_t(num_result);
-#else
-  num_elements = PyInt_AsSsize_t(num_result);
-#endif
-  Py_DECREF(num_result);
-
-  PyObject *list = PyList_New(num_elements);
-  for (int i = 0; i < num_elements; ++i) {
-    PyObject *element = PyObject_CallMethod(self, (char *)element_name, (char *)"(i)", i);
-    if (element == NULL) {
-      Py_DECREF(list);
-      return NULL;
-    }
-    PyList_SET_ITEM(list, i, element);
-  }
-  return list;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: copy_from_make_copy
 //  Description: This is a support function for a synthesized

+ 24 - 27
dtool/src/interrogatedb/py_panda.h

@@ -143,17 +143,17 @@ using namespace std;
 ///////////////////////////////////////////////////////////////////////////////////
 
 struct Dtool_PyTypedObject;
-typedef std::map<int, Dtool_PyTypedObject *>   RunTimeTypeDictionary;
-typedef std::set<int>                           RunTimeTypeList;
-
-EXPCL_DTOOLCONFIG RunTimeTypeDictionary &GetRunTimeDictionary();
-EXPCL_DTOOLCONFIG RunTimeTypeList &GetRunTimeTypeList();
+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..
 #define PY_PANDA_SIGNATURE 0xbeaf
 typedef void *(*UpcastFunction)(PyObject *,Dtool_PyTypedObject *);
 typedef void *(*DowncastFunction)(void *, Dtool_PyTypedObject *);
+typedef void *(*CoerceFunction)(PyObject *, void *);
+typedef void (*ModuleClassInitFunction)(PyObject *module);
 
 //inline          Dtool_PyTypedObject *  Dtool_RuntimeTypeDtoolType(int type);
 //inline void     Dtool_Deallocate_General(PyObject * self);
@@ -196,16 +196,16 @@ struct Dtool_PyTypedObject {
   // Standard Python Features..
   PyTypeObject _PyType;
 
-  // My Class Level Features..
-  UpcastFunction _Dtool_UpcastInterface;    // The Upcast Function By Slot
-  DowncastFunction _Dtool_DowncastInterface; // The Downcast Function By Slot
-
   // May be TypeHandle::none() to indicate a non-TypedObject class.
   TypeHandle _type;
 
-  // some convenience functions..
-  inline PyTypeObject &As_PyTypeObject() { return _PyType; };
-  inline PyObject &As_PyObject() { return (PyObject &)_PyType; };
+  ModuleClassInitFunction _Dtool_ModuleClassInit;
+
+  UpcastFunction _Dtool_UpcastInterface;    // The Upcast Function By Slot
+  DowncastFunction _Dtool_DowncastInterface; // The Downcast Function By Slot
+
+  CoerceFunction _Dtool_ConstCoerce;
+  CoerceFunction _Dtool_Coerce;
 };
 
 // This is now simply a forward declaration.  The actual definition is created
@@ -217,7 +217,7 @@ struct Dtool_PyTypedObject {
 //  More Macro(s) to Implement class functions.. Usually used if C++ needs type information
 ////////////////////////////////////////////////////////////////////////
 #define Define_Dtool_new(CLASS_NAME,CNAME)\
-PyObject *Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds) {\
+static PyObject *Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds) {\
   (void) args; (void) kwds;\
   PyObject *self = type->tp_alloc(type, 0);\
   ((Dtool_PyInstDef *)self)->_signature = PY_PANDA_SIGNATURE;\
@@ -291,7 +291,11 @@ EXPCL_DTOOLCONFIG bool DtoolCanThisBeAPandaInstance(PyObject *self);
 //
 ///////////////////////////////////////////////////////////////////////////////
 
-EXPCL_DTOOLCONFIG void RegisterRuntimeClass(Dtool_PyTypedObject *otype, int class_id);
+EXPCL_DTOOLCONFIG void RegisterNamedClass(const string &name, Dtool_PyTypedObject &otype);
+EXPCL_DTOOLCONFIG void RegisterRuntimeTypedClass(Dtool_PyTypedObject &otype);
+
+EXPCL_DTOOLCONFIG Dtool_PyTypedObject *LookupNamedClass(const string &name);
+EXPCL_DTOOLCONFIG Dtool_PyTypedObject *LookupRuntimeTypedClass(TypeHandle handle);
 
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
@@ -305,7 +309,7 @@ EXPCL_DTOOLCONFIG Dtool_PyTypedObject *Dtool_RuntimeTypeDtoolType(int type);
 //      with these as the generated code depends on how this is set
 //      up..
 ////////////////////////////////////////////////////////////////////////
-EXPCL_DTOOLCONFIG void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject * classdef, void ** answer);
+EXPCL_DTOOLCONFIG void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject *classdef, void **answer);
 
 EXPCL_DTOOLCONFIG void *DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, int param, const string &function_name, bool const_ok, bool report_errors);
 
@@ -407,11 +411,9 @@ template<class T> INLINE PyObject *DTool_CreatePyInstanceTyped(T *obj, bool memo
 //struct Dtool_PyTypedObject Dtool_##CLASS_NAME;
 
 #define Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
-extern EXPORT_THIS   Dtool_PyTypedObject Dtool_##CLASS_NAME;\
-int         Dtool_Init_##CLASS_NAME(PyObject *self, PyObject *args, PyObject *kwds);\
-PyObject *  Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds);\
-void  *     Dtool_UpcastInterface_##CLASS_NAME(PyObject *self, Dtool_PyTypedObject *requested_type);\
-void  *     Dtool_DowncastInterface_##CLASS_NAME(void *self, Dtool_PyTypedObject *requested_type);
+extern struct Dtool_PyTypedObject Dtool_##CLASS_NAME;\
+static int Dtool_Init_##CLASS_NAME(PyObject *self, PyObject *args, PyObject *kwds);\
+static PyObject *Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds);
 
 ///////////////////////////////////////////////////////////////////////////////
 #define Define_Module_Class(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
@@ -460,10 +462,7 @@ EXPCL_DTOOLCONFIG void Dtool_Accum_MethDefs(PyMethodDef in[], MethodDefmap &them
 /// fallowing structors and code.. along with the support of interigate_module
 ///////////////////////////////////////////////////////////////////////////////
 struct LibraryDef {
-  typedef void (*ConstantFunction)(PyObject *);
-
   PyMethodDef *_methods;
-  ConstantFunction _constants;
 };
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -505,10 +504,6 @@ EXPCL_DTOOLCONFIG int DTOOL_PyObject_Compare(PyObject *v1, PyObject *v2);
 
 EXPCL_DTOOLCONFIG PyObject *DTOOL_PyObject_RichCompare(PyObject *v1, PyObject *v2, int op);
 
-EXPCL_DTOOLCONFIG PyObject *
-make_list_for_item(PyObject *self, const char *num_name,
-                   const char *element_name);
-
 EXPCL_DTOOLCONFIG PyObject *
 copy_from_make_copy(PyObject *self);
 
@@ -527,6 +522,8 @@ PyLongOrInt_FromUnsignedLong(unsigned long value);
 EXPCL_DTOOLCONFIG extern struct Dtool_PyTypedObject Dtool_DTOOL_SUPER_BASE;
 EXPCL_DTOOLCONFIG extern void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module);
 
+#define Dtool_Ptr_DTOOL_SUPER_BASE (&Dtool_DTOOL_SUPER_BASE)
+
 #endif  // HAVE_PYTHON && !CPPPARSER
 
 #endif // PY_PANDA_H_

+ 3 - 0
dtool/src/parser-inc/iostream

@@ -43,6 +43,9 @@ __published:
   static const openmode in;
   static const openmode out;
   static const openmode trunc;
+protected:
+  // Force this to be a non-trivial type.
+  ios_base() {};
 };
 class ios : public ios_base {
 __published:

+ 18 - 35
makepanda/makepanda.py

@@ -1411,7 +1411,10 @@ def CompileImod(wobj, wsrc, opts):
         # Assume that interrogate_module is on the PATH somewhere.
         cmd = 'interrogate_module'
 
-    cmd += ' -oc ' + woutc + ' -module ' + module + ' -library ' + library + ' -python-native '
+    cmd += ' -oc ' + woutc + ' -module ' + module + ' -library ' + library + ' -python-native'
+    importmod = GetValueOption(opts, "IMPORT:")
+    if importmod:
+        cmd += ' -import ' + importmod
     for x in wsrc: cmd += ' ' + BracketNameWithQuotes(x)
     oscmd(cmd)
     CompileCxx(wobj,woutc,opts)
@@ -1592,20 +1595,13 @@ def CompileLink(dll, obj, opts):
                 cmd = cxx + ' -undefined dynamic_lookup'
                 if ("BUNDLE" in opts): cmd += ' -bundle '
                 else:
-                    if GetOrigExt(dll) == ".pyd":
-                        install_name = '@loader_path/../panda3d/' + os.path.basename(dll)
-                    else:
-                        install_name = os.path.basename(dll)
+                    install_name = os.path.basename(dll)
                     cmd += ' -dynamiclib -install_name ' + install_name
                     cmd += ' -compatibility_version ' + MAJOR_VERSION + ' -current_version ' + VERSION
                 cmd += ' -o ' + dll + ' -L' + GetOutputDir() + '/lib -L' + GetOutputDir() + '/tmp'
             else:
                 cmd = cxx + ' -shared'
                 if ("MODULE" not in opts): cmd += " -Wl,-soname=" + os.path.basename(dll)
-                if GetOrigExt(dll) == ".pyd" and not os.path.basename(dll).startswith('core'):
-                    # Tell the other libraries where to find core.so.
-                    # Not sure if this is the best way to do that, but it works.
-                    cmd += " -Wl,-rpath '-Wl,$ORIGIN'"
                 cmd += ' -o ' + dll + ' -L' + GetOutputDir() + '/lib -L' + GetOutputDir() + '/tmp'
 
         for x in obj:
@@ -3856,12 +3852,11 @@ if (PkgSkip("VISION") == 0) and (not RUNTIME):
 
   TargetAdd('vision_module.obj', input='libp3vision.in')
   TargetAdd('vision_module.obj', opts=OPTS)
-  TargetAdd('vision_module.obj', opts=['IMOD:panda3d.vision', 'ILIB:vision'])
+  TargetAdd('vision_module.obj', opts=['IMOD:panda3d.vision', 'ILIB:vision', 'IMPORT:panda3d.core'])
 
   TargetAdd('vision.pyd', input='vision_module.obj')
   TargetAdd('vision.pyd', input='libp3vision_igate.obj')
   TargetAdd('vision.pyd', input='libp3vision.dll')
-  TargetAdd('vision.pyd', input='core.pyd')
   TargetAdd('vision.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('vision.pyd', opts=['PYTHON'])
 
@@ -3887,13 +3882,12 @@ if (PkgSkip("ROCKET") == 0) and (not RUNTIME):
 
   TargetAdd('rocket_module.obj', input='libp3rocket.in')
   TargetAdd('rocket_module.obj', opts=OPTS)
-  TargetAdd('rocket_module.obj', opts=['IMOD:panda3d.rocket', 'ILIB:rocket'])
+  TargetAdd('rocket_module.obj', opts=['IMOD:panda3d.rocket', 'ILIB:rocket', 'IMPORT:panda3d.core'])
 
   TargetAdd('rocket.pyd', input='rocket_module.obj')
   TargetAdd('rocket.pyd', input='libp3rocket_igate.obj')
   TargetAdd('rocket.pyd', input='p3rocket_rocketRegion_ext.obj')
   TargetAdd('rocket.pyd', input='libp3rocket.dll')
-  TargetAdd('rocket.pyd', input='core.pyd')
   TargetAdd('rocket.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('rocket.pyd', opts=['PYTHON', 'ROCKET'])
 
@@ -3915,12 +3909,11 @@ if PkgSkip("AWESOMIUM") == 0 and not RUNTIME:
 
   TargetAdd('awesomium_module.obj', input='libp3awesomium.in')
   TargetAdd('awesomium_module.obj', opts=OPTS)
-  TargetAdd('awesomium_module.obj', opts=['IMOD:panda3d.awesomium', 'ILIB:awesomium'])
+  TargetAdd('awesomium_module.obj', opts=['IMOD:panda3d.awesomium', 'ILIB:awesomium', 'IMPORT:panda3d.core'])
 
   TargetAdd('awesomium.pyd', input='awesomium_module.obj')
   TargetAdd('awesomium.pyd', input='libp3awesomium_igate.obj')
   TargetAdd('awesomium.pyd', input='libp3awesomium.dll')
-  TargetAdd('awesomium.pyd', input='core.pyd')
   TargetAdd('awesomium.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('awesomium.pyd', opts=['PYTHON'])
 
@@ -3949,12 +3942,11 @@ if (PkgSkip('SKEL')==0) and (not RUNTIME):
   TargetAdd('libpandaskel.dll', opts=OPTS)
 
   TargetAdd('skel_module.obj', input='libp3skel.in')
-  TargetAdd('skel_module.obj', opts=['IMOD:panda3d.skel', 'ILIB:skel'])
+  TargetAdd('skel_module.obj', opts=['IMOD:panda3d.skel', 'ILIB:skel', 'IMPORT:panda3d.core'])
 
   TargetAdd('skel.pyd', input='skel_module.obj')
   TargetAdd('skel.pyd', input='libp3skel_igate.obj')
   TargetAdd('skel.pyd', input='libpandaskel.dll')
-  TargetAdd('skel.pyd', input='core.pyd')
   TargetAdd('skel.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('skel.pyd', opts=['PYTHON'])
 
@@ -3988,12 +3980,11 @@ if (PkgSkip('PANDAFX')==0) and (not RUNTIME):
   OPTS=['DIR:panda/metalibs/pandafx', 'DIR:panda/src/distort', 'NVIDIACG']
   TargetAdd('fx_module.obj', input='libp3distort.in')
   TargetAdd('fx_module.obj', opts=OPTS)
-  TargetAdd('fx_module.obj', opts=['IMOD:panda3d.fx', 'ILIB:fx'])
+  TargetAdd('fx_module.obj', opts=['IMOD:panda3d.fx', 'ILIB:fx', 'IMPORT:panda3d.core'])
 
   TargetAdd('fx.pyd', input='fx_module.obj')
   TargetAdd('fx.pyd', input='libp3distort_igate.obj')
   TargetAdd('fx.pyd', input='libpandafx.dll')
-  TargetAdd('fx.pyd', input='core.pyd')
   TargetAdd('fx.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('fx.pyd', opts=['PYTHON'])
 
@@ -4016,12 +4007,11 @@ if (PkgSkip("VRPN")==0 and not RUNTIME):
 
   TargetAdd('vrpn_module.obj', input='libp3vrpn.in')
   TargetAdd('vrpn_module.obj', opts=OPTS)
-  TargetAdd('vrpn_module.obj', opts=['IMOD:panda3d.vrpn', 'ILIB:vrpn'])
+  TargetAdd('vrpn_module.obj', opts=['IMOD:panda3d.vrpn', 'ILIB:vrpn', 'IMPORT:panda3d.core'])
 
   TargetAdd('vrpn.pyd', input='vrpn_module.obj')
   TargetAdd('vrpn.pyd', input='libp3vrpn_igate.obj')
   TargetAdd('vrpn.pyd', input='libp3vrpn.dll')
-  TargetAdd('vrpn.pyd', input='core.pyd')
   TargetAdd('vrpn.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('vrpn.pyd', opts=['PYTHON'])
 
@@ -4249,14 +4239,13 @@ if (not RUNTIME):
   TargetAdd('egg_module.obj', input='libp3egg2pg.in')
   TargetAdd('egg_module.obj', input='libp3egg.in')
   TargetAdd('egg_module.obj', opts=OPTS)
-  TargetAdd('egg_module.obj', opts=['IMOD:panda3d.egg', 'ILIB:egg'])
+  TargetAdd('egg_module.obj', opts=['IMOD:panda3d.egg', 'ILIB:egg', 'IMPORT:panda3d.core'])
 
   TargetAdd('egg.pyd', input='egg_module.obj')
   TargetAdd('egg.pyd', input='p3egg_eggGroupNode_ext.obj')
   TargetAdd('egg.pyd', input='libp3egg_igate.obj')
   TargetAdd('egg.pyd', input='libp3egg2pg_igate.obj')
   TargetAdd('egg.pyd', input='libpandaegg.dll')
-  TargetAdd('egg.pyd', input='core.pyd')
   TargetAdd('egg.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('egg.pyd', opts=['PYTHON'])
 
@@ -4416,13 +4405,12 @@ if (PkgSkip("ODE")==0 and not RUNTIME):
   OPTS=['DIR:panda/metalibs/pandaode', 'ODE']
   TargetAdd('ode_module.obj', input='libpandaode.in')
   TargetAdd('ode_module.obj', opts=OPTS)
-  TargetAdd('ode_module.obj', opts=['IMOD:panda3d.ode', 'ILIB:ode'])
+  TargetAdd('ode_module.obj', opts=['IMOD:panda3d.ode', 'ILIB:ode', 'IMPORT:panda3d.core'])
 
   TargetAdd('ode.pyd', input='ode_module.obj')
   TargetAdd('ode.pyd', input='libpandaode_igate.obj')
   TargetAdd('ode.pyd', input='p3ode_ext_composite.obj')
   TargetAdd('ode.pyd', input='libpandaode.dll')
-  TargetAdd('ode.pyd', input='core.pyd')
   TargetAdd('ode.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('ode.pyd', opts=['PYTHON', 'WINUSER', 'ODE'])
 
@@ -4454,12 +4442,11 @@ if (PkgSkip("BULLET")==0 and not RUNTIME):
   OPTS=['DIR:panda/metalibs/pandabullet', 'BULLET']
   TargetAdd('bullet_module.obj', input='libpandabullet.in')
   TargetAdd('bullet_module.obj', opts=OPTS)
-  TargetAdd('bullet_module.obj', opts=['IMOD:panda3d.bullet', 'ILIB:bullet'])
+  TargetAdd('bullet_module.obj', opts=['IMOD:panda3d.bullet', 'ILIB:bullet', 'IMPORT:panda3d.core'])
 
   TargetAdd('bullet.pyd', input='bullet_module.obj')
   TargetAdd('bullet.pyd', input='libpandabullet_igate.obj')
   TargetAdd('bullet.pyd', input='libpandabullet.dll')
-  TargetAdd('bullet.pyd', input='core.pyd')
   TargetAdd('bullet.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('bullet.pyd', opts=['PYTHON', 'WINUSER', 'BULLET'])
 
@@ -4493,12 +4480,11 @@ if (PkgSkip("PHYSX")==0):
   OPTS=['DIR:panda/metalibs/pandaphysx', 'PHYSX', 'NOARCH:PPC']
   TargetAdd('physx_module.obj', input='libpandaphysx.in')
   TargetAdd('physx_module.obj', opts=OPTS)
-  TargetAdd('physx_module.obj', opts=['IMOD:panda3d.physx', 'ILIB:physx'])
+  TargetAdd('physx_module.obj', opts=['IMOD:panda3d.physx', 'ILIB:physx', 'IMPORT:panda3d.core'])
 
   TargetAdd('physx.pyd', input='physx_module.obj')
   TargetAdd('physx.pyd', input='libpandaphysx_igate.obj')
   TargetAdd('physx.pyd', input='libpandaphysx.dll')
-  TargetAdd('physx.pyd', input='core.pyd')
   TargetAdd('physx.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('physx.pyd', opts=['PYTHON', 'WINUSER', 'PHYSX', 'NOARCH:PPC'])
 
@@ -4559,14 +4545,13 @@ if (PkgSkip("PANDAPHYSICS")==0) and (not RUNTIME):
   if (PkgSkip("PANDAPARTICLESYSTEM")==0):
     TargetAdd('physics_module.obj', input='libp3particlesystem.in')
   TargetAdd('physics_module.obj', opts=OPTS)
-  TargetAdd('physics_module.obj', opts=['IMOD:panda3d.physics', 'ILIB:physics'])
+  TargetAdd('physics_module.obj', opts=['IMOD:panda3d.physics', 'ILIB:physics', 'IMPORT:panda3d.core'])
 
   TargetAdd('physics.pyd', input='physics_module.obj')
   TargetAdd('physics.pyd', input='libp3physics_igate.obj')
   if (PkgSkip("PANDAPARTICLESYSTEM")==0):
     TargetAdd('physics.pyd', input='libp3particlesystem_igate.obj')
   TargetAdd('physics.pyd', input='libpandaphysics.dll')
-  TargetAdd('physics.pyd', input='core.pyd')
   TargetAdd('physics.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('physics.pyd', opts=['PYTHON'])
 
@@ -4816,7 +4801,7 @@ if (PkgSkip("DIRECT")==0):
   TargetAdd('direct_module.obj', input='libp3interval.in')
   TargetAdd('direct_module.obj', input='libp3distributed.in')
   TargetAdd('direct_module.obj', opts=OPTS)
-  TargetAdd('direct_module.obj', opts=['IMOD:panda3d.direct', 'ILIB:direct'])
+  TargetAdd('direct_module.obj', opts=['IMOD:panda3d.direct', 'ILIB:direct', 'IMPORT:panda3d.core'])
 
   TargetAdd('direct.pyd', input='libp3dcparser_igate.obj')
   TargetAdd('direct.pyd', input='libp3showbase_igate.obj')
@@ -4826,7 +4811,6 @@ if (PkgSkip("DIRECT")==0):
 
   TargetAdd('direct.pyd', input='direct_module.obj')
   TargetAdd('direct.pyd', input='libp3direct.dll')
-  TargetAdd('direct.pyd', input='core.pyd')
   TargetAdd('direct.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('direct.pyd', opts=['PYTHON', 'OPENSSL', 'WINUSER', 'WINGDI'])
 
@@ -6026,12 +6010,11 @@ if (PkgSkip("CONTRIB")==0 and not RUNTIME):
 
   TargetAdd('ai_module.obj', input='libpandaai.in')
   TargetAdd('ai_module.obj', opts=OPTS)
-  TargetAdd('ai_module.obj', opts=['IMOD:panda3d.ai', 'ILIB:ai'])
+  TargetAdd('ai_module.obj', opts=['IMOD:panda3d.ai', 'ILIB:ai', 'IMPORT:panda3d.core'])
 
   TargetAdd('ai.pyd', input='ai_module.obj')
   TargetAdd('ai.pyd', input='libpandaai_igate.obj')
   TargetAdd('ai.pyd', input='libpandaai.dll')
-  TargetAdd('ai.pyd', input='core.pyd')
   TargetAdd('ai.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('ai.pyd', opts=['PYTHON'])
 

+ 1 - 1
panda/src/bullet/bulletRigidBodyNode.h

@@ -33,7 +33,7 @@ class BulletShape;
 class EXPCL_PANDABULLET BulletRigidBodyNode : public BulletBodyNode {
 
 PUBLISHED:
-  BulletRigidBodyNode(const char *name="rigid");
+  explicit BulletRigidBodyNode(const char *name="rigid");
   INLINE ~BulletRigidBodyNode();
 
   // Mass & inertia

+ 1 - 1
panda/src/egg/eggGroupNode.h

@@ -26,6 +26,7 @@
 #include "luse.h"
 #include "globPattern.h"
 #include "plist.h"
+#include "bamCacheRecord.h"
 
 class EggTextureCollection;
 class EggMaterialCollection;
@@ -33,7 +34,6 @@ class EggPolygon;
 class EggVertex;
 class EggVertexPool;
 class DSearchPath;
-class BamCacheRecord;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : EggGroupNode

+ 3 - 3
panda/src/express/memoryUsagePointers_ext.cxx

@@ -17,9 +17,9 @@
 #if defined(HAVE_PYTHON) && defined(DO_MEMORY_USAGE)
 
 #ifndef CPPPARSER
-extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_TypedObject;
-extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_TypedReferenceCount;
-extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_ReferenceCount;
+extern Dtool_PyTypedObject Dtool_TypedObject;
+extern Dtool_PyTypedObject Dtool_TypedReferenceCount;
+extern Dtool_PyTypedObject Dtool_ReferenceCount;
 #endif  // CPPPARSER
 
 ////////////////////////////////////////////////////////////////////

+ 13 - 0
panda/src/express/namable.I

@@ -45,6 +45,19 @@ operator = (const Namable &other) {
   return *this;
 }
 
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: Namable::Copy Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE Namable &Namable::
+operator = (Namable &&other) NOEXCEPT {
+  _name = MOVE(other._name);
+  return *this;
+}
+#endif
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Namable::set_name
 //       Access: Public

+ 5 - 1
panda/src/express/namable.h

@@ -28,10 +28,14 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDAEXPRESS Namable : public MemoryBase {
 PUBLISHED:
-  INLINE Namable(const string &initial_name = "");
+  INLINE explicit Namable(const string &initial_name = "");
   INLINE Namable(const Namable &copy);
   INLINE Namable &operator = (const Namable &other);
 
+#ifdef USE_MOVE_SEMANTICS
+  INLINE Namable &operator = (Namable &&other) NOEXCEPT;
+#endif
+
   INLINE void set_name(const string &name);
   INLINE void clear_name();
   INLINE bool has_name() const;

+ 1 - 1
panda/src/gobj/geom.h

@@ -60,7 +60,7 @@ protected:
   virtual PT(CopyOnWriteObject) make_cow_copy();
 
 PUBLISHED:
-  Geom(const GeomVertexData *data);
+  explicit Geom(const GeomVertexData *data);
 
 protected:
   Geom(const Geom &copy);

+ 2 - 2
panda/src/gobj/geomVertexArrayData.h

@@ -68,8 +68,8 @@ protected:
   virtual PT(CopyOnWriteObject) make_cow_copy();
 
 PUBLISHED:
-  GeomVertexArrayData(const GeomVertexArrayFormat *array_format,
-                      UsageHint usage_hint);
+  explicit GeomVertexArrayData(const GeomVertexArrayFormat *array_format,
+                               UsageHint usage_hint);
   GeomVertexArrayData(const GeomVertexArrayData &copy);
   void operator = (const GeomVertexArrayData &copy);
   virtual ~GeomVertexArrayData();

+ 5 - 5
panda/src/gobj/geomVertexData.h

@@ -80,12 +80,12 @@ protected:
   virtual PT(CopyOnWriteObject) make_cow_copy();
 
 PUBLISHED:
-  GeomVertexData(const string &name,
-                 const GeomVertexFormat *format,
-                 UsageHint usage_hint);
+  explicit GeomVertexData(const string &name,
+                          const GeomVertexFormat *format,
+                          UsageHint usage_hint);
   GeomVertexData(const GeomVertexData &copy);
-  GeomVertexData(const GeomVertexData &copy,
-                 const GeomVertexFormat *format);
+  explicit GeomVertexData(const GeomVertexData &copy,
+                          const GeomVertexFormat *format);
   void operator = (const GeomVertexData &copy);
   virtual ~GeomVertexData();
   ALLOC_DELETED_CHAIN(GeomVertexData);

+ 1 - 1
panda/src/gobj/texture.h

@@ -43,6 +43,7 @@
 #include "pnmImage.h"
 #include "colorSpace.h"
 #include "geomEnums.h"
+#include "bamCacheRecord.h"
 
 class PNMImage;
 class PfmFile;
@@ -51,7 +52,6 @@ class FactoryParams;
 class PreparedGraphicsObjects;
 class CullTraverser;
 class CullTraverserData;
-class BamCacheRecord;
 class TexturePeeker;
 struct DDSHeader;
 

+ 1 - 1
panda/src/gobj/textureStage.h

@@ -37,7 +37,7 @@ class FactoryParams;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_GOBJ TextureStage : public TypedWritableReferenceCount {
 PUBLISHED:
-  TextureStage(const string &name);
+  explicit TextureStage(const string &name);
   INLINE TextureStage(TextureStage &copy);
   void operator = (const TextureStage &copy);
 

+ 2 - 6
panda/src/ode/odeGeom_ext.I

@@ -15,10 +15,6 @@
 #include "odeSpace_ext.h"
 #include "lpoint3.h"
 
-#ifndef CPPPARSER
-IMPORT_THIS struct Dtool_PyTypedObject Dtool_LPoint3f;
-#endif
-
 ////////////////////////////////////////////////////////////////////
 //     Function: OdeGeom::get_AA_bounds
 //       Access: Published
@@ -30,8 +26,8 @@ get_AA_bounds() const {
   LPoint3f *max_point = new LPoint3f;
   _this->get_AABB(*min_point, *max_point);
 
-  PyObject *min_inst = DTool_CreatePyInstance((void*) min_point, Dtool_LPoint3f, true, false);
-  PyObject *max_inst = DTool_CreatePyInstance((void*) max_point, Dtool_LPoint3f, true, false);
+  PyObject *min_inst = DTool_CreatePyInstance(min_point, true);
+  PyObject *max_inst = DTool_CreatePyInstance(max_point, true);
   return Py_BuildValue("NN", min_inst, max_inst);
 }
 

+ 2 - 6
panda/src/ode/odeSpace_ext.I

@@ -15,10 +15,6 @@
 /* okcircular */
 #include "odeGeom_ext.h"
 
-#ifndef CPPPARSER
-IMPORT_THIS struct Dtool_PyTypedObject Dtool_LPoint3f;
-#endif
-
 ////////////////////////////////////////////////////////////////////
 //     Function: OdeSpace::get_AA_bounds
 //       Access: Published
@@ -30,8 +26,8 @@ get_AA_bounds() const {
   LPoint3f *max_point = new LPoint3f;
   _this->get_AABB(*min_point, *max_point);
 
-  PyObject *min_inst = DTool_CreatePyInstance((void*) min_point, Dtool_LPoint3f, true, false);
-  PyObject *max_inst = DTool_CreatePyInstance((void*) max_point, Dtool_LPoint3f, true, false);
+  PyObject *min_inst = DTool_CreatePyInstance(min_point, true);
+  PyObject *max_inst = DTool_CreatePyInstance(max_point, true);
   return Py_BuildValue("NN", min_inst, max_inst);
 }
 

+ 1 - 1
panda/src/pgraph/camera.h

@@ -36,7 +36,7 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PGRAPH Camera : public LensNode {
 PUBLISHED:
-  Camera(const string &name, Lens *lens = new PerspectiveLens());
+  explicit Camera(const string &name, Lens *lens = new PerspectiveLens());
   Camera(const Camera &copy);
 
 public:

+ 2 - 2
panda/src/pgraph/nodePath.h

@@ -177,8 +177,8 @@ PUBLISHED:
   INLINE explicit NodePath(const string &top_node_name, Thread *current_thread = Thread::get_current_thread());
   INLINE explicit NodePath(PandaNode *node, Thread *current_thread = Thread::get_current_thread());
   INLINE static NodePath any_path(PandaNode *node, Thread *current_thread = Thread::get_current_thread());
-  NodePath(const NodePath &parent, PandaNode *child_node,
-           Thread *current_thread = Thread::get_current_thread());
+  explicit NodePath(const NodePath &parent, PandaNode *child_node,
+                    Thread *current_thread = Thread::get_current_thread());
 
   INLINE NodePath(const NodePath &copy);
   INLINE void operator = (const NodePath &copy);

+ 1 - 1
panda/src/pgraph/pandaNode.h

@@ -72,7 +72,7 @@ class GraphicsStateGuardianBase;
 class EXPCL_PANDA_PGRAPH PandaNode : public TypedWritableReferenceCount,
                                      public Namable, public LinkedListNode {
 PUBLISHED:
-  PandaNode(const string &name);
+  explicit PandaNode(const string &name);
   virtual ~PandaNode();
   //published so that characters can be combined.
   virtual PandaNode *combine_with(PandaNode *other);

+ 4 - 4
panda/src/pnmimage/pnmImage.h

@@ -68,10 +68,10 @@ class PNMFileType;
 class EXPCL_PANDA_PNMIMAGE PNMImage : public PNMImageHeader {
 PUBLISHED:
   INLINE PNMImage();
-  PNMImage(const Filename &filename, PNMFileType *type = NULL);
-  INLINE PNMImage(int x_size, int y_size, int num_channels = 3,
-                  xelval maxval = 255, PNMFileType *type = NULL,
-                  ColorSpace color_space = CS_linear);
+  explicit PNMImage(const Filename &filename, PNMFileType *type = NULL);
+  INLINE explicit PNMImage(int x_size, int y_size, int num_channels = 3,
+                           xelval maxval = 255, PNMFileType *type = NULL,
+                           ColorSpace color_space = CS_linear);
   INLINE PNMImage(const PNMImage &copy);
   INLINE void operator = (const PNMImage &copy);
 

+ 3 - 1
panda/src/pnmimage/pnmimage_base.h

@@ -42,8 +42,9 @@ typedef unsigned char gray;
 struct pixel {
 PUBLISHED:
   pixel() { }
+  pixel(gray fill) : r(fill), g(fill), b(fill) { }
   pixel(gray r, gray g, gray b) : r(r), g(g), b(b) { }
-  static int size() { return 3; }
+
   gray operator [](int i) const { nassertr(i >= 0 && i < 3, 0); return *(&r + i); }
   gray &operator [](int i) { nassertr(i >= 0 && i < 3, r); return *(&r + i); }
   pixel operator + (const pixel &other) const
@@ -60,6 +61,7 @@ PUBLISHED:
     { r *= mult; g *= mult; b *= mult; }
 
 #ifdef HAVE_PYTHON
+  static int size() { return 3; }
   void output(ostream &out) {
     out << "pixel(r=" << r << ", g=" << g << ", b=" << b << ")";
   }

+ 1 - 1
panda/src/pstatclient/pStatThread.h

@@ -29,7 +29,7 @@ class Thread;
 //               with Panda's Thread instance.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PSTATCLIENT PStatThread {
-private:
+public:
   INLINE PStatThread();
 
 PUBLISHED: