Browse Source

Big interrogate cleanup, new extension system, add __iter__ support, add buffer protocol support

rdb 12 years ago
parent
commit
cc3bae7e76
79 changed files with 2340 additions and 805 deletions
  1. 1 6
      dtool/src/dtoolbase/dtoolbase.h
  2. 10 26
      dtool/src/dtoolbase/dtoolbase_cc.h
  3. 52 40
      dtool/src/interrogate/functionRemap.cxx
  4. 4 1
      dtool/src/interrogate/functionRemap.h
  5. 8 4
      dtool/src/interrogate/interfaceMaker.cxx
  6. 1 0
      dtool/src/interrogate/interfaceMaker.h
  7. 0 1
      dtool/src/interrogate/interfaceMakerPython.cxx
  8. 370 155
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  9. 23 18
      dtool/src/interrogate/interfaceMakerPythonNative.h
  10. 17 19
      dtool/src/interrogate/interrogateBuilder.cxx
  11. 1 1
      dtool/src/interrogate/interrogateBuilder.h
  12. 1 1
      dtool/src/interrogate/parameterRemapConstToNonConst.h
  13. 101 0
      dtool/src/interrogate/typeManager.cxx
  14. 4 0
      dtool/src/interrogate/typeManager.h
  15. 2 2
      dtool/src/interrogatedb/Sources.pp
  16. 75 0
      dtool/src/interrogatedb/extension.h
  17. 3 1
      dtool/src/interrogatedb/py_panda.cxx
  18. 15 1
      dtool/src/interrogatedb/py_panda.h
  19. 1 0
      dtool/src/parser-inc/OVR.h
  20. 1 0
      dtool/src/parser-inc/Python.h
  21. 1 0
      panda/src/express/Sources.pp
  22. 238 14
      panda/src/express/pointerToArray.I
  23. 59 7
      panda/src/express/pointerToArray.h
  24. 0 67
      panda/src/express/virtualFileSystem.cxx
  25. 6 9
      panda/src/express/virtualFileSystem.h
  26. 82 0
      panda/src/express/virtualFileSystem_ext.cxx
  27. 41 0
      panda/src/express/virtualFileSystem_ext.h
  28. 1 0
      panda/src/gobj/Sources.pp
  29. 4 0
      panda/src/gobj/geomVertexArrayData.h
  30. 167 0
      panda/src/gobj/geomVertexArrayData_ext.cxx
  31. 42 0
      panda/src/gobj/geomVertexArrayData_ext.h
  32. 77 0
      panda/src/gobj/geomVertexArrayFormat.cxx
  33. 2 0
      panda/src/gobj/geomVertexArrayFormat.h
  34. 5 5
      panda/src/linmath/Sources.pp
  35. 19 19
      panda/src/linmath/lmatrix3_ext_src.I
  36. 41 0
      panda/src/linmath/lmatrix3_ext_src.h
  37. 2 2
      panda/src/linmath/lmatrix3_src.h
  38. 27 27
      panda/src/linmath/lmatrix4_ext_src.I
  39. 41 0
      panda/src/linmath/lmatrix4_ext_src.h
  40. 2 2
      panda/src/linmath/lmatrix4_src.h
  41. 12 6
      panda/src/linmath/lmatrix_ext.h
  42. 10 3
      panda/src/linmath/lpoint2_ext.h
  43. 36 20
      panda/src/linmath/lpoint2_ext_src.I
  44. 30 0
      panda/src/linmath/lpoint2_ext_src.h
  45. 2 2
      panda/src/linmath/lpoint2_src.h
  46. 10 3
      panda/src/linmath/lpoint3_ext.h
  47. 35 27
      panda/src/linmath/lpoint3_ext_src.I
  48. 30 0
      panda/src/linmath/lpoint3_ext_src.h
  49. 2 2
      panda/src/linmath/lpoint3_src.h
  50. 10 3
      panda/src/linmath/lpoint4_ext.h
  51. 38 39
      panda/src/linmath/lpoint4_ext_src.I
  52. 30 0
      panda/src/linmath/lpoint4_ext_src.h
  53. 2 2
      panda/src/linmath/lpoint4_src.h
  54. 8 3
      panda/src/linmath/lvecBase2_ext.h
  55. 41 39
      panda/src/linmath/lvecBase2_ext_src.I
  56. 32 0
      panda/src/linmath/lvecBase2_ext_src.h
  57. 3 3
      panda/src/linmath/lvecBase2_src.h
  58. 8 3
      panda/src/linmath/lvecBase3_ext.h
  59. 42 40
      panda/src/linmath/lvecBase3_ext_src.I
  60. 32 0
      panda/src/linmath/lvecBase3_ext_src.h
  61. 3 3
      panda/src/linmath/lvecBase3_src.h
  62. 8 3
      panda/src/linmath/lvecBase4_ext.h
  63. 49 48
      panda/src/linmath/lvecBase4_ext_src.I
  64. 44 0
      panda/src/linmath/lvecBase4_ext_src.h
  65. 3 3
      panda/src/linmath/lvecBase4_src.h
  66. 10 3
      panda/src/linmath/lvector2_ext.h
  67. 32 32
      panda/src/linmath/lvector2_ext_src.I
  68. 30 0
      panda/src/linmath/lvector2_ext_src.h
  69. 2 2
      panda/src/linmath/lvector2_src.h
  70. 10 3
      panda/src/linmath/lvector3_ext.h
  71. 33 34
      panda/src/linmath/lvector3_ext_src.I
  72. 30 0
      panda/src/linmath/lvector3_ext_src.h
  73. 2 2
      panda/src/linmath/lvector3_src.h
  74. 10 3
      panda/src/linmath/lvector4_ext.h
  75. 38 39
      panda/src/linmath/lvector4_ext_src.I
  76. 30 0
      panda/src/linmath/lvector4_ext_src.h
  77. 2 2
      panda/src/linmath/lvector4_src.h
  78. 5 5
      panda/src/rocket/rocketRegion_ext.cxx
  79. 39 0
      panda/src/rocket/rocketRegion_ext.h

+ 1 - 6
dtool/src/dtoolbase/dtoolbase.h

@@ -23,7 +23,7 @@
 #include "dtool_config.h"
 
 /* Make sure WIN32 and WIN32_VC are defined when using MSVC */
-#ifdef _WIN32
+#if defined(_WIN32) || defined(_WIN64)
 #ifndef WIN32
 #define WIN32
 #endif
@@ -411,11 +411,6 @@
 #define MAKE_SEQ(seq_name, num_name, element_name)
 #define EXTENSION(x)
 #define EXTEND
-/* If you change these, don't forget to also change it in interrogate itself. */
-#define _EXT_FUNC(func) _ext__ ## func
-#define EXT_FUNC(func) _EXT_FUNC(func) ()
-#define EXT_FUNC_ARGS(func, ...) _EXT_FUNC(func) (__VA_ARGS__)
-#define CALL_EXT_FUNC(func, ...) _EXT_METHOD(cl, m) (__VA_ARGS__)
 #endif
 
 #ifdef __cplusplus

+ 10 - 26
dtool/src/dtoolbase/dtoolbase_cc.h

@@ -220,32 +220,16 @@ private:
 
 #endif  // USE_TAU
 
-#ifdef CPPPARSER
-#define EXT_METHOD(cl, m) cl::m()
-#define EXT_METHOD_ARGS(cl, m, ...) cl::m(__VA_ARGS__)
-#define EXT_CONST_METHOD(cl, m) cl::m() const
-#define EXT_CONST_METHOD_ARGS(cl, m, ...) cl::m(__VA_ARGS__) const
-#define EXT_NESTED_METHOD(cl1, cl2, m) cl1::cl2::m()
-#define EXT_NESTED_METHOD_ARGS(cl1, cl2, m, ...) cl1::cl2::m(__VA_ARGS__)
-#define EXT_NESTED_CONST_METHOD(cl1, cl2, m) cl1::cl2::m() const
-#define EXT_NESTED_CONST_METHOD_ARGS(cl1, cl2, m, ...) cl1::cl2::m(__VA_ARGS__) const
-#define CALL_EXT_METHOD(cl, m, obj, ...) (obj)-> m(__VA_ARGS__)
-#else
-/* If you change these, don't forget to also change it in interrogate itself. */
-#define __EXT_METHOD(cl, m) _ext_ ## cl ## _ ## m
-#define _EXT_METHOD(cl, m) __EXT_METHOD(cl, m)
-#define __EXT_NEST(cl1, cl2) cl1 ## __ ## cl2
-#define _EXT_NEST(cl1, cl2) __EXT_NEST(cl1, cl2)
-#define EXT_METHOD(cl, m) _EXT_METHOD(cl, m) (cl * _ext_this)
-#define EXT_METHOD_ARGS(cl, m, ...) _EXT_METHOD(cl, m) (cl * _ext_this, __VA_ARGS__)
-#define EXT_CONST_METHOD(cl, m) _EXT_METHOD(cl, m) (const cl * _ext_this)
-#define EXT_CONST_METHOD_ARGS(cl, m, ...) _EXT_METHOD(cl, m) (const cl * _ext_this, __VA_ARGS__)
-#define EXT_NESTED_METHOD(cl1, cl2, m) _EXT_METHOD(_EXT_NEST(cl1, cl2), m) (cl1::cl2 * _ext_this)
-#define EXT_NESTED_METHOD_ARGS(cl1, cl2, m, ...) _EXT_METHOD(_EXT_NEST(cl1, cl2), m) (cl1::cl2 * _ext_this, __VA_ARGS__)
-#define EXT_NESTED_CONST_METHOD(cl1, cl2, m) _EXT_METHOD(_EXT_NEST(cl1, cl2), m) (const cl1::cl2 * _ext_this)
-#define EXT_NESTED_CONST_METHOD_ARGS(cl1, cl2, m, ...) _EXT_METHOD(_EXT_NEST(cl1, cl2), m) (const cl1::cl2 * _ext_this, __VA_ARGS__)
-#define CALL_EXT_METHOD(cl, m, ...) _EXT_METHOD(cl, m) (__VA_ARGS__)
-#endif
+// Macros from hell.
+#define EXT_METHOD(cl, m) Extension<cl>::m()
+#define EXT_METHOD_ARGS(cl, m, ...) Extension<cl>::m(__VA_ARGS__)
+#define EXT_CONST_METHOD(cl, m) Extension<cl>::m() const
+#define EXT_CONST_METHOD_ARGS(cl, m, ...) Extension<cl>::m(__VA_ARGS__) const
+#define EXT_NESTED_METHOD(cl1, cl2, m) Extension<cl1::cl2>::m()
+#define EXT_NESTED_METHOD_ARGS(cl1, cl2, m, ...) Extension<cl1::cl2>::m(__VA_ARGS__)
+#define EXT_NESTED_CONST_METHOD(cl1, cl2, m) Extension<cl1::cl2>::m() const
+#define EXT_NESTED_CONST_METHOD_ARGS(cl1, cl2, m, ...) Extension<cl1::cl2>::m(__VA_ARGS__) const
+#define CALL_EXT_METHOD(cl, m, obj, ...) invoke_extension(obj).m(__VA_ARGS__)
 
 #endif  //  __cplusplus
 #endif

+ 52 - 40
dtool/src/interrogate/functionRemap.cxx

@@ -244,8 +244,12 @@ string FunctionRemap::call_function(ostream &out, int indent_level, bool convert
 //               comment.
 ////////////////////////////////////////////////////////////////////
 void FunctionRemap::
-write_orig_prototype(ostream &out, int indent_level) const {
-  _cppfunc->output(out, indent_level, &parser, false, _num_default_parameters);
+write_orig_prototype(ostream &out, int indent_level, bool local) const {
+  if (local) {
+    _cppfunc->output(out, indent_level, NULL, false, _num_default_parameters);
+  } else {
+    _cppfunc->output(out, indent_level, &parser, false, _num_default_parameters);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -392,28 +396,13 @@ get_call_str(const string &container, const vector_string &pexprs) const {
     const char *separator = "";
 
     // If this function is marked as having an extension function,
-    // call that instead.  The naming convention of the extension
-    // function has to match the EXT_IMPL definition in dtoolbase.h.
-    if (_extension) {
-      if (_cpptype != NULL) {
-        // Fix nested classes by replacing :: with __
-        char* nested_name = strdup(_cpptype->get_local_name(&parser).c_str());
-        for (size_t i = 0; i < strlen(nested_name); ++i) {
-          if (nested_name[i] == ':') {
-            nested_name[i] = '_';
-          }
-        }
-        call << "_ext_"  << nested_name << "_"
-                         << _cppfunc->get_local_name() << "(";
-        delete[] nested_name;
-      } else {
-        call << "_ext__" << _cppfunc->get_local_name() << "(";
-      }
+    // call that instead.
+    if (_extension && !container.empty()) {
+      call << "invoke_extension(" << container << ").";
+
+      call << _cppfunc->get_local_name();
+      call << "(";
 
-      if (_has_this && !container.empty()) {
-        call << container;
-        separator = ", ";
-      }
     } else {
 
       if (_type == T_constructor) {
@@ -569,11 +558,13 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     if (param._remap == (ParameterRemap *)NULL) {
       // If we can't handle one of the parameter types, we can't call
       // the function.
+      //nout << "Can't handle parameter " << i << " of method " << *_cppfunc << "\n";
       return false;
     }
     param._remap->set_default_value(params[i]->_initializer);
 
     if (!param._remap->is_valid()) {
+      nout << "Invalid remap for parameter " << i << " of method " << *_cppfunc << "\n";
       return false;
     }
 
@@ -693,6 +684,31 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
         // It receives no parameters, and returns a pointer.
         _flags |= F_make_copy;
       }
+
+    } else if (fname == "__iter__" ) {
+      if (_has_this && _parameters.size() == 1 &&
+          TypeManager::is_pointer(_return_type->get_new_type())) {
+        // It receives no parameters, and returns a pointer.
+        _flags |= F_iter;
+      }
+
+    } else if (fname == "__getbuffer__" ) {
+      if (_has_this && _parameters.size() == 4 &&
+          TypeManager::is_integer(_return_type->get_new_type()) &&
+          TypeManager::is_pointer_to_PyObject(_parameters[1]._remap->get_orig_type()) &&
+          TypeManager::is_pointer_to_Py_buffer(_parameters[2]._remap->get_orig_type()) &&
+          TypeManager::is_integer(_parameters[3]._remap->get_orig_type())) {
+
+        _flags |= F_getbuffer;
+      }
+
+    } else if (fname == "__releasebuffer__" ) {
+      if (_has_this && _parameters.size() == 3 &&
+          TypeManager::is_pointer_to_PyObject(_parameters[1]._remap->get_orig_type()) &&
+          TypeManager::is_pointer_to_Py_buffer(_parameters[2]._remap->get_orig_type())) {
+
+        _flags |= F_releasebuffer;
+      }
     }
 
   } else if (_type == T_constructor) {
@@ -709,25 +725,21 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
   return true;
 }
 
-
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
-std::string make_safe_name(const std::string & name)
-{
-    return InterrogateBuilder::clean_identifier(name);
-
-    /*
-    static const char safe_chars2[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
-        std::string result = name;
-
-        size_t pos = result.find_first_not_of(safe_chars2);
-        while (pos != std::string::npos)
-        {
-                result[pos] = '_';
-                pos = result.find_first_not_of(safe_chars2);
-        }
+std::string make_safe_name(const std::string &name) {
+  return InterrogateBuilder::clean_identifier(name);
+  /*
+  static const char safe_chars2[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+  std::string result = name;
+
+  size_t pos = result.find_first_not_of(safe_chars2);
+  while (pos != std::string::npos) {
+    result[pos] = '_';
+    pos = result.find_first_not_of(safe_chars2);
+  }
 
-        return result;
-        */
+  return result;
+  */
 }

+ 4 - 1
dtool/src/interrogate/functionRemap.h

@@ -56,7 +56,7 @@ public:
                        bool convert_result, const string &container,
                        const vector_string &pexprs = vector_string()) const;
 
-  void write_orig_prototype(ostream &out, int indent_level) const;
+  void write_orig_prototype(ostream &out, int indent_level, bool local=false) const;
 
   FunctionWrapperIndex make_wrapper_entry(FunctionIndex function_index);
 
@@ -87,6 +87,9 @@ public:
     F_make_copy        = 0x0020,
     F_copy_constructor = 0x0040,
     F_explicit_self    = 0x0080,
+    F_iter             = 0x0100,
+    F_getbuffer        = 0x0200,
+    F_releasebuffer    = 0x0400,
   };
 
   typedef vector<Parameter> Parameters;

+ 8 - 4
dtool/src/interrogate/interfaceMaker.cxx

@@ -40,8 +40,7 @@
 #include "cppStructType.h"
 #include "pnotify.h"
 
- InterrogateType dummy_type;
-
+InterrogateType dummy_type;
  
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMaker::Function::Constructor
@@ -152,6 +151,10 @@ check_protocols() {
     _protocol_types |= PT_copy_constructor;
   }
 
+  if (flags & FunctionRemap::F_iter) {
+    _protocol_types |= PT_iter;
+  }
+
   // Now are there any make_seq requests within this class?
   CPPStructType *stype = _itype._cpptype->as_struct_type();
   if (stype != (CPPStructType *)NULL) {
@@ -361,10 +364,9 @@ write_functions(ostream &out) {
 //               support a module file.
 ////////////////////////////////////////////////////////////////////
 void InterfaceMaker::
-write_module(ostream &, ostream *out_h,InterrogateModuleDef *) {
+write_module(ostream &, ostream *out_h, InterrogateModuleDef *) {
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMaker::remap_parameter
 //       Access: Public, Virtual
@@ -379,6 +381,8 @@ write_module(ostream &, ostream *out_h,InterrogateModuleDef *) {
 ////////////////////////////////////////////////////////////////////
 ParameterRemap *InterfaceMaker::
 remap_parameter(CPPType *struct_type, CPPType *param_type) {
+  nassertr(param_type != NULL, NULL);
+
   if (convert_strings) {
     if (TypeManager::is_char_pointer(param_type)) {
       return new ParameterRemapCharStarToString(param_type);

+ 1 - 0
dtool/src/interrogate/interfaceMaker.h

@@ -115,6 +115,7 @@ public:
       PT_mapping          = 0x0002,
       PT_make_copy        = 0x0004,
       PT_copy_constructor = 0x0008,
+      PT_iter             = 0x0010,
     };
     int _protocol_types;
   };

+ 0 - 1
dtool/src/interrogate/interfaceMakerPython.cxx

@@ -15,7 +15,6 @@
 #include "interfaceMakerPython.h"
 #include "interrogate.h"
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMakerPython::Constructor
 //       Access: Public

File diff suppressed because it is too large
+ 370 - 155
dtool/src/interrogate/interfaceMakerPythonNative.cxx


+ 23 - 18
dtool/src/interrogate/interfaceMakerPythonNative.h

@@ -34,17 +34,17 @@ public:
   virtual ~InterfaceMakerPythonNative();
   
   
-  virtual void write_prototypes(ostream &out,ostream *out_h);
-  void write_prototypes_class(ostream &out,ostream *out_h, Object * obj) ;
-  void write_prototypes_class_external(ostream &out, Object * obj);
+  virtual void write_prototypes(ostream &out, ostream *out_h);
+  void write_prototypes_class(ostream &out, ostream *out_h, Object *obj) ;
+  void write_prototypes_class_external(ostream &out, Object *obj);
   
   virtual void write_functions(ostream &out);
   
-  virtual void write_module(ostream &out,ostream *out_h, InterrogateModuleDef *def);
-  virtual void write_module_support(ostream &out, ostream *out_h,InterrogateModuleDef *moduledefdef);
+  virtual void write_module(ostream &out, ostream *out_h, InterrogateModuleDef *def);
+  virtual void write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def);
   
   void write_module_class(ostream &out, Object *cls); 
-  virtual void write_sub_module(ostream &out,  Object *obj); 
+  virtual void write_sub_module(ostream &out, Object *obj); 
   
   virtual bool synthesize_this_parameter();
   
@@ -74,6 +74,8 @@ private:
     WT_sequence_size,
     WT_mapping_setitem,
     WT_inquiry,
+    WT_getbuffer,
+    WT_releasebuffer,
   };
 
   class SlottedFunctionDef {
@@ -102,22 +104,25 @@ private:
                              int indent_level, ostream &forwarddecl, bool inplace,
                              bool coercion_allowed, bool &coercion_attempted, 
                              const string &args_cleanup);
-  
-  void pack_return_value(ostream &out, int indent_level,
-                         FunctionRemap *remap, std::string return_expr, ostream &forwarddecl, bool in_place);
-  
+
+  void pack_return_value(ostream &out, int indent_level, FunctionRemap *remap,
+                         const std::string &return_expr, bool in_place);
+  void pack_python_value(ostream &out, int indent_level, FunctionRemap *remap,
+                         ParameterRemap *return_type, const std::string &return_expr,
+                         const std::string &assign_expr, bool in_place);
+
   void write_make_seq(ostream &out, Object *obj, const std::string &ClassName,
                       MakeSeq *make_seq);
-  
+
   void write_class_prototypes(ostream &out) ;
   void write_class_declarations(ostream &out, ostream *out_h, Object *obj);
   void write_class_details(ostream &out, Object *obj);
   
   void do_assert_init(ostream &out, int &indent_level, bool constructor, const string &args_cleanup) const;
 public:
-  bool isRemapLegal(FunctionRemap &remap);
-  bool isFunctionLegal( Function *func);
-  bool isCppTypeLegal(CPPType *ctype);
+  bool is_remap_legal(FunctionRemap &remap);
+  bool is_function_legal( Function *func);
+  bool is_cpp_type_legal(CPPType *ctype);
   bool isExportThisRun(CPPType *ctype);
   bool isExportThisRun(Function *func);
   bool isFunctionWithThis( Function *func);
@@ -131,11 +136,11 @@ public:
     bool            _can_downcast;
     bool            _is_legal_py_class;
   };
-  
-  void GetValideChildClasses( std::map< std::string ,CastDetails > &answer, CPPStructType * inclass,  const std::string &up_cast_seed = "", bool downcastposible = true);
-  bool DoesInheritFromIsClass( const CPPStructType * inclass, const std::string &name);
+
+  void get_valid_child_classes(std::map<std::string, CastDetails> &answer, CPPStructType *inclass, const std::string &upcast_seed = "", bool can_downcast = true);
+  bool DoesInheritFromIsClass(const CPPStructType * inclass, const std::string &name);
   bool IsPandaTypedObject(CPPStructType * inclass) { return DoesInheritFromIsClass(inclass,"TypedObject"); };
-  void WriteReturnInstance(ostream &out, int indent_level, std::string &return_expr, std::string &ows_memory_flag,const std::string &class_name, CPPType *ctype, bool inplace, const std::string &const_flag);
+  void write_python_instance(ostream &out, int indent_level, const std::string &return_expr, const std::string &assign_expr, std::string &owns_memory_flag, const std::string &class_name, CPPType *ctype, bool inplace, const std::string &const_flag);
   string HasAGetKeyFunction(const InterrogateType &itype_class);
   bool HasAGetClassTypeFunction(const InterrogateType &itype_class);
   int NeedsAStrFunction(const InterrogateType &itype_class);

+ 17 - 19
dtool/src/interrogate/interrogateBuilder.cxx

@@ -128,17 +128,16 @@ read_command_file(istream &in) {
 void InterrogateBuilder::
 do_command(const string &command, const string &params) {
 
-  if(command == "forcevisible")
-  {
-      CPPType *type = parser.parse_type(params);
-      if (type == (CPPType *)NULL) {
-          nout << "Unknown type: allowtype " << params << "\n";
-      } else {
-          type = type->resolve_type(&parser, &parser);
-          type->_vis = min_vis;
-      }
-  }
-  else if (command == "forcetype") {
+  if (command == "forcevisible") {
+    CPPType *type = parser.parse_type(params);
+    if (type == (CPPType *)NULL) {
+      nout << "Unknown type: allowtype " << params << "\n";
+    } else {
+      type = type->resolve_type(&parser, &parser);
+      type->_vis = min_vis;
+    }
+
+  } else if (command == "forcetype") {
     // forcetype explicitly exports the given type.
     CPPType *type = parser.parse_type(params);
     if (type == (CPPType *)NULL) {
@@ -364,7 +363,6 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
              << "#include \"dconfig.h\"\n";
   }
 
-
   ostringstream declaration_bodies;
 
   if (watch_asserts) {
@@ -377,7 +375,8 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
     if (library_name.size() > 1) {
       declaration_bodies << "#define PANDA_LIBRARY_NAME_" << library_name << "\n";
     }
-    declaration_bodies << "#include \"py_panda.h\"  \n";
+    declaration_bodies << "#include \"py_panda.h\"\n";
+    declaration_bodies << "#include \"extension.h\"\n";
   }
   declaration_bodies << "\n";
   
@@ -393,12 +392,6 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
       } else {
         declaration_bodies << "#include <" << filename << ">\n";
       }
-    // Check if it's a special extension file.
-    } else if (filename.length() > 6 && filename.substr(filename.length() - 6) == "_ext.I") {
-      declaration_bodies
-        << "#define this _ext_this\n"
-        << "#include \"" << filename << "\"\n"
-        << "#undef this\n";
     }
   }
   declaration_bodies << "\n";
@@ -1757,6 +1750,11 @@ get_function(CPPInstance *function, string description,
     ifunction->_flags |= InterrogateFunction::F_operator_typecast;
   }
 
+  if (function->_storage_class & CPPInstance::SC_virtual) {
+    // This is a virtual function.
+    ifunction->_flags |= InterrogateFunction::F_virtual;
+  }
+
   ifunction->_flags |= flags;
   ifunction->_instances->insert(InterrogateFunction::Instances::value_type(function_signature, function));
   ifunction->_expression = expression;

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

@@ -56,7 +56,7 @@ public:
   void read_command_file(istream &in);
   void do_command(const string &command, const string &params);
   void build();
-  void write_code(ostream &out_code,ostream *out_include, InterrogateModuleDef *def);
+  void write_code(ostream &out_code, ostream *out_include, InterrogateModuleDef *def);
   InterrogateModuleDef *make_module_def(int file_identifier);
 
   static string clean_identifier(const string &name);

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

@@ -23,7 +23,7 @@
 //       Class : ParameterRemapConstToNonConst
 // Description : A ParameterRemap class that handles remapping a
 //               simple const parameter (like const int) to an
-//               ordinary parameter (line int).  It doesn't apply to
+//               ordinary parameter (like int).  It doesn't apply to
 //               const references or const pointers, however.
 ////////////////////////////////////////////////////////////////////
 class ParameterRemapConstToNonConst : public ParameterRemap {

+ 101 - 0
dtool/src/interrogate/typeManager.cxx

@@ -23,6 +23,7 @@
 #include "cppPointerType.h"
 #include "cppSimpleType.h"
 #include "cppStructType.h"
+#include "cppTemplateScope.h"
 #include "cppTypeDeclaration.h"
 #include "pnotify.h"
 #include "cppTypedef.h"
@@ -1052,6 +1053,35 @@ is_const_ref_to_pointer_to_base(CPPType *type) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_pair
+//       Access: Public, Static
+//  Description: Returns true if the type is pair<>, or
+//               a reference to it.
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_pair(CPPType *type) {
+  // We only check the simple name of the type against pair,
+  // since we need to allow for the various template instantiations of
+  // this thing.
+  if (type->get_simple_name() == "pair") {
+    return true;
+  }
+
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_pair(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_reference:
+    return is_pair(type->as_reference_type()->_pointing_at);
+
+  default:
+    break;
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TypeManager::is_pointer_to_PyObject
 //       Access: Public, Static
@@ -1090,6 +1120,43 @@ is_PyObject(CPPType *type) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_pointer_to_Py_buffer
+//       Access: Public, Static
+//  Description: Returns true if the indicated type is Py_buffer *.
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_pointer_to_Py_buffer(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_pointer_to_Py_buffer(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_pointer:
+    return is_Py_buffer(type->as_pointer_type()->_pointing_at);
+
+  default:
+    return false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_Py_buffer
+//       Access: Public, Static
+//  Description: Returns true if the indicated type is Py_buffer.
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_Py_buffer(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_Py_buffer(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_extension:
+    return (type->get_local_name(&parser) == "Py_buffer");
+
+  default:
+    return false;
+  }
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: TypeManager::is_ostream
@@ -1390,6 +1457,40 @@ get_pointer_type(CPPStructType *pt_type) {
   return (CPPType *)NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::get_template_parameter_type
+//       Access: Public, Static
+//  Description: Returns the ith template parameter type.  For
+//               instance, if the type is pair<A, B>, then this
+//               function will return type A when passing 0 and
+//               type B when passing 1, and NULL otherwise.
+////////////////////////////////////////////////////////////////////
+CPPType *TypeManager::
+get_template_parameter_type(CPPType *source_type, int i) {
+  switch (source_type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return get_template_parameter_type(source_type->as_const_type()->_wrapped_around, i);
+
+  case CPPDeclaration::ST_reference:
+    return get_template_parameter_type(source_type->as_reference_type()->_pointing_at, i);
+  }
+
+  CPPStructType *type = source_type->as_struct_type();
+  if (type == NULL) {
+    return NULL;
+  }
+
+  // I'm not sure how reliable this is, but I don't know if there
+  // is a more proper way to access this.
+  CPPTemplateParameterList *templ = type->_ident->_names.back().get_templ();
+  if (templ == NULL || i >= templ->_parameters.size()) {
+    return NULL;
+  }
+
+  CPPDeclaration *decl = templ->_parameters[i];
+  return decl->as_type();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TypeManager::wrap_pointer
 //       Access: Public, Static

+ 4 - 0
dtool/src/interrogate/typeManager.h

@@ -76,6 +76,7 @@ public:
   static bool is_const_ref_to_basic_string_wchar(CPPType *type);
   static bool is_const_ptr_to_basic_string_wchar(CPPType *type);
   static bool is_wstring(CPPType *type);
+  static bool is_pair(CPPType *type);
   static bool is_bool(CPPType *type);
   static bool is_integer(CPPType *type);
   static bool is_unsigned_integer(CPPType *type);
@@ -90,6 +91,8 @@ public:
   static bool is_const_ref_to_pointer_to_base(CPPType *type);
   static bool is_pointer_to_PyObject(CPPType *type);
   static bool is_PyObject(CPPType *type);
+  static bool is_pointer_to_Py_buffer(CPPType *type);
+  static bool is_Py_buffer(CPPType *type);
   static bool involves_unpublished(CPPType *type);
   static bool involves_protected(CPPType *type);
 
@@ -103,6 +106,7 @@ public:
   static CPPType *unwrap(CPPType *type);
 
   static CPPType *get_pointer_type(CPPStructType *pt_type);
+  static CPPType *get_template_parameter_type(CPPType *type, int i = 0);
 
   static CPPType *wrap_pointer(CPPType *type);
   static CPPType *wrap_const_pointer(CPPType *type);

+ 2 - 2
dtool/src/interrogatedb/Sources.pp

@@ -17,7 +17,7 @@
     interrogateType.I interrogateType.h  \
     interrogate_datafile.I interrogate_datafile.h  \
     interrogate_interface.h interrogate_request.h \
-    py_panda.h \
+    extension.h py_panda.h \
     vector_int.h
 
  #define INCLUDED_SOURCES  \
@@ -37,7 +37,7 @@
   #define INSTALL_HEADERS \
     interrogate_interface.h interrogate_request.h vector_int.h \
     config_interrogatedb.h \
-    py_panda.h \
+    extension.h py_panda.h \
     vector_int.h
 
 #end lib_target

+ 75 - 0
dtool/src/interrogatedb/extension.h

@@ -0,0 +1,75 @@
+// Filename: extension.h
+// Created by:  rdb (11Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef EXTENSION_H
+#define EXTENSION_H
+
+#include "dtoolbase.h"
+
+struct _object;
+typedef struct _object PyObject;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ExtensionBase
+// Description : This is where all extensions should derive from.
+//               It defines the _self and _this members that can
+//               be used from the extension method.
+////////////////////////////////////////////////////////////////////
+template<class T>
+class EXPCL_DTOOLCONFIG ExtensionBase {
+public:
+  T * _this;
+  PyObject * _self;
+};
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension
+// Description : The default class template does not define any
+//               methods.  Classes that are extended should create
+//               a specialization of this class template.
+////////////////////////////////////////////////////////////////////
+template<class T>
+class EXPCL_DTOOLCONFIG Extension : public ExtensionBase<T> {
+};
+
+////////////////////////////////////////////////////////////////////
+//    Function : invoke_extension
+// Description : Creates a new extension object for the given
+//               pointer that can then be used to call extension
+//               methods, as follows:
+//               invoke_extension((MyClass) *ptr).method()
+////////////////////////////////////////////////////////////////////
+template<class T>
+inline Extension<T>
+invoke_extension(T *ptr, PyObject *self = NULL) {
+  Extension<T> ext;
+  ext._this = ptr;
+  ext._self = self;
+  return ext;
+}
+
+////////////////////////////////////////////////////////////////////
+//    Function : invoke_extension
+// Description : The const version of the above function.
+////////////////////////////////////////////////////////////////////
+template<class T>
+inline const Extension<T>
+invoke_extension(const T *ptr, PyObject *self = NULL) {
+  Extension<T> ext;
+  ext._this = (T *) ptr;
+  ext._self = self;
+  return ext;
+}
+
+#endif

+ 3 - 1
dtool/src/interrogatedb/py_panda.cxx

@@ -437,7 +437,7 @@ RegisterRuntimeClass(Dtool_PyTypedObject * otype, int class_id) {
 Dtool_PyTypedObject *Dtool_RuntimeTypeDtoolType(int type) {
   RunTimeTypeDictionary::iterator di = GetRunTimeDictionary().find(type);
   if (di != GetRunTimeDictionary().end()) {
-      return di->second;
+    return di->second;
   } else {
     int type2 = get_best_parent_from_Set(type, GetRunTimeTypeList());
     di = GetRunTimeDictionary().find(type2);
@@ -468,6 +468,7 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
   newdef[offset].ml_flags = 0;
 
 #if PY_MAJOR_VERSION >= 3
+  cerr << "About to create module " << modulename << "\n";
   struct PyModuleDef moduledef = {
     PyModuleDef_HEAD_INIT,
     modulename,
@@ -477,6 +478,7 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
     NULL, NULL, NULL, NULL
   };
   PyObject *module = PyModule_Create(&moduledef);
+  cerr << "Module created!\n";
 #else
   PyObject *module = Py_InitModule((char *)modulename, newdef); 
 #endif  

+ 15 - 1
dtool/src/interrogatedb/py_panda.h

@@ -221,7 +221,7 @@ struct Dtool_PyTypedObject {
         0,                                      /* tp_str */            \
         PyObject_GenericGetAttr,                /* tp_getattro */       \
         PyObject_GenericSetAttr,                /* tp_setattro */       \
-        0,                                      /* tp_as_buffer */      \
+        &Dtool_PyBufferProcs_##CLASS_NAME,      /* tp_as_buffer */      \
         (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES), /* tp_flags */ \
         0,                                      /* tp_doc */            \
         0,                                      /* tp_traverse */       \
@@ -310,6 +310,11 @@ struct Dtool_PyTypedObject {
       0,/*binaryfunc mp_subscript */                                    \
       0,/*objobjargproc mp_ass_subscript */                             \
     };                                                                  \
+  static PyMappingMethods Dtool_PyBufferProcs_##CLASS_NAME =            \
+    {                                                                   \
+      0,/*getbufferproc bf_getbuffer */                                 \
+      0,/*releasebufferproc bf_releasebuffer */                         \
+    };                                                                  \
   Define_Dtool_PyTypedObject(MODULE_NAME, CLASS_NAME, PUBLIC_NAME)
 
 #else // Python 2:
@@ -373,6 +378,15 @@ struct Dtool_PyTypedObject {
       0,/*binaryfunc mp_subscript */                                    \
       0,/*objobjargproc mp_ass_subscript */                             \
     };                                                                  \
+  static PyBufferProcs Dtool_PyBufferProcs_##CLASS_NAME =               \
+    {                                                                   \
+      0,/*readbufferproc bf_getreadbuffer */                            \
+      0,/*writebufferproc bf_getwritebuffer */                          \
+      0,/*segcountproc bf_getsegcount */                                \
+      0,/*charbufferproc bf_getcharbuffer */                            \
+      0,/*getbufferproc bf_getbuffer */                                 \
+      0,/*releasebufferproc bf_releasebuffer */                         \
+    };                                                                  \
   Define_Dtool_PyTypedObject(MODULE_NAME, CLASS_NAME, PUBLIC_NAME)
 #endif
 

+ 1 - 0
dtool/src/parser-inc/OVR.h

@@ -11,5 +11,6 @@ namespace OVR {
   class SensorInfo;
   class SensorFusion;
 
+  template<class T> class DeviceEnumerator;
   template<class T> class Ptr;
 };

+ 1 - 0
dtool/src/parser-inc/Python.h

@@ -23,5 +23,6 @@
 class PyObject;
 class PyThreadState;
 typedef int Py_ssize_t;
+struct Py_buffer;
 
 #endif  // PYTHON_H

+ 1 - 0
panda/src/express/Sources.pp

@@ -70,6 +70,7 @@
     virtualFileMountSystem.h virtualFileMountSystem.I \
     virtualFileSimple.h virtualFileSimple.I \
     virtualFileSystem.h virtualFileSystem.I \
+    virtualFileSystem_ext.h virtualFileSystem_ext.cxx \
     weakPointerCallback.I weakPointerCallback.h \
     weakPointerTo.I weakPointerTo.h \
     weakPointerToBase.I weakPointerToBase.h \

+ 238 - 14
panda/src/express/pointerToArray.I

@@ -83,11 +83,12 @@ PointerToArray(const PointerToArray<Element> &copy) :
 //       Access: Published
 //  Description: This special constructor accepts a Python list of
 //               elements, or a Python string (or a bytes object,
-//               in Python 3).
+//               in Python 3), or any object that supports the
+//               Python buffer protocol.
 ////////////////////////////////////////////////////////////////////
 template<class Element>
 PointerToArray<Element>::
-PointerToArray(PyObject *self, PyObject *sequence) :
+PointerToArray(PyObject *self, PyObject *source) :
   PointerToArrayBase<Element>((ReferenceCountedVector<Element> *)NULL),
   _type_handle(get_type_handle(Element))
 {
@@ -95,9 +96,33 @@ PointerToArray(PyObject *self, PyObject *sequence) :
   // self in the constructor--the caller can't initialize this for us.
   ((Dtool_PyInstDef *)self)->_ptr_to_object = this;
 
-  if (!PySequence_Check(sequence)) {
+  if (PyObject_CheckBuffer(source)) {
+    // User passed a buffer object.
+    Py_buffer view;
+    if (PyObject_GetBuffer(source, &view, PyBUF_CONTIG_RO) == -1) {
+      PyErr_SetString(PyExc_TypeError, "PointerToArray constructor requires a contiguous buffer");
+      return;
+    }
+
+    if (view.itemsize != 1 && view.itemsize != sizeof(Element)) {
+      PyErr_SetString(PyExc_TypeError, "buffer.itemsize does not match PointerToArray element size");
+      return;
+    }
+
+    int num_elements = view.len / sizeof(Element);
+    insert(begin(), num_elements, Element());
+
+    if (view.len > 0) {
+      memcpy(p(), view.buf, view.len);
+    }
+
+    PyBuffer_Release(&view);
+    return;
+  }
+
+  if (!PySequence_Check(source)) {
     // If passed with a non-sequence, this isn't the right constructor.
-    PyErr_SetString(PyExc_TypeError, "PointerToArray constructor requires a sequence");
+    PyErr_SetString(PyExc_TypeError, "PointerToArray constructor requires a sequence or buffer object");
     return;
   }
 
@@ -105,8 +130,8 @@ PointerToArray(PyObject *self, PyObject *sequence) :
   // character-at-a-time, just load the whole string as a data
   // buffer.
 #if PY_MAJOR_VERSION >= 3
-  if (PyBytes_Check(sequence)) {
-    int size = PyBytes_Size(sequence);
+  if (PyBytes_Check(source)) {
+    int size = PyBytes_Size(source);
     if (size % sizeof(Element) != 0) {
       ostringstream stream;
       stream << "Buffer not a multiple of " << sizeof(Element) << " bytes";
@@ -121,14 +146,14 @@ PointerToArray(PyObject *self, PyObject *sequence) :
     // Hope there aren't any constructors or destructors involved
     // here.
     if (size != 0) {
-      const char *data = PyBytes_AsString(sequence);
+      const char *data = PyBytes_AsString(source);
       memcpy(p(), data, size);
     }
     return;
   }
 #else
-  if (PyString_CheckExact(sequence)) {
-    int size = PyString_Size(sequence);
+  if (PyString_CheckExact(source)) {
+    int size = PyString_Size(source);
     if (size % sizeof(Element) != 0) {
       ostringstream stream;
       stream << "Buffer not a multiple of " << sizeof(Element) << " bytes";
@@ -143,7 +168,7 @@ PointerToArray(PyObject *self, PyObject *sequence) :
     // Hope there aren't any constructors or destructors involved
     // here.
     if (size != 0) {
-      const char *data = PyString_AsString(sequence);
+      const char *data = PyString_AsString(source);
       memcpy(p(), data, size);
     }
     return;
@@ -152,9 +177,9 @@ PointerToArray(PyObject *self, PyObject *sequence) :
 
   // Now construct the internal list by copying the elements
   // one-at-a-time from Python.
-  int size = PySequence_Size(sequence);
+  int size = PySequence_Size(source);
   for (int i = 0; i < size; ++i) {
-    PyObject *item = PySequence_GetItem(sequence, i);
+    PyObject *item = PySequence_GetItem(source, i);
     if (item == NULL) {
       return;
     }
@@ -715,6 +740,32 @@ get_ref_count() const {
   return ((this->_void_ptr) == NULL) ? 0 : ((To *)(this->_void_ptr))->get_ref_count();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToArray::ref
+//       Access: Public
+//  Description: Increments the reference count of the underlying vector.
+////////////////////////////////////////////////////////////////////
+template<class Element>
+INLINE void PointerToArray<Element>::
+ref() const {
+  if ((this->_void_ptr) == NULL) {
+    ((PointerToArray<Element> *)this)->reassign(new ReferenceCountedVector<Element>(_type_handle));
+  }
+  ((To *)(this->_void_ptr))->ref();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToArray::unref
+//       Access: Public
+//  Description: Decrements the reference count of the underlying vector.
+////////////////////////////////////////////////////////////////////
+template<class Element>
+INLINE bool PointerToArray<Element>::
+unref() const {
+  nassertr((this->_void_ptr) != NULL, true);
+  return ((To *)(this->_void_ptr))->unref();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PointerToArray::get_node_ref_count
 //       Access: Public
@@ -841,8 +892,8 @@ ConstPointerToArray(const ConstPointerToArray<Element> &copy) :
 ////////////////////////////////////////////////////////////////////
 template<class Element>
 INLINE ConstPointerToArray<Element>::
-ConstPointerToArray(PyObject *self, PyObject *sequence) :
-  PointerToArrayBase<Element>(PointerToArray<Element>(self, sequence)),
+ConstPointerToArray(PyObject *self, PyObject *source) :
+  PointerToArrayBase<Element>(PointerToArray<Element>(self, source)),
   _type_handle(get_type_handle(Element))
 {
 }
@@ -1164,6 +1215,32 @@ get_ref_count() const {
   return ((this->_void_ptr) == NULL) ? 0 : ((To *)(this->_void_ptr))->get_ref_count();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ConstPointerToArray::ref
+//       Access: Public
+//  Description: Increments the reference count of the underlying vector.
+////////////////////////////////////////////////////////////////////
+template<class Element>
+INLINE void ConstPointerToArray<Element>::
+ref() const {
+  if ((this->_void_ptr) == NULL) {
+    ((ConstPointerToArray<Element> *)this)->reassign(new ReferenceCountedVector<Element>(_type_handle));
+  }
+  ((To *)(this->_void_ptr))->ref();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConstPointerToArray::unref
+//       Access: Public
+//  Description: Decrements the reference count of the underlying vector.
+////////////////////////////////////////////////////////////////////
+template<class Element>
+INLINE bool ConstPointerToArray<Element>::
+unref() const {
+  nassertr((this->_void_ptr) != NULL, true);
+  return ((To *)(this->_void_ptr))->unref();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ConstPointerToArray::get_node_ref_count
 //       Access: Public
@@ -1252,4 +1329,151 @@ clear() {
   ((ConstPointerToArray<Element> *)this)->reassign((ReferenceCountedVector<Element> *)NULL);
 }
 
+#ifdef HAVE_PYTHON
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToArray::__getbuffer__
+//       Access: Published
+//  Description: This is used to implement the buffer protocol, in
+//               order to allow efficient access to the array data
+//               through a Python multiview object.
+////////////////////////////////////////////////////////////////////
+template<class Element>
+INLINE int PointerToArray<Element>::
+__getbuffer__(PyObject *self, Py_buffer *view, int flags) {
+
+  const char *format = get_format_code(Element);
+  cerr << "non-const __getbuffer__ with fmt " << format << "\n";
+  if (format == NULL) {
+    // Not supported.
+    return -1;
+  }
+
+  if (self != NULL) {
+    Py_INCREF(self);
+  }
+  view->obj = self;
+  view->buf = (void*) p();
+  view->len = size() * sizeof(Element);
+  view->readonly = 0;
+  view->itemsize = sizeof(Element);
+  view->format = NULL;
+  if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
+    view->format = (char*) format;
+  }
+  view->ndim = 1;
+  view->shape = NULL;
+  if ((flags & PyBUF_ND) == PyBUF_ND) {
+    // This leaks, which sucks, but __releasebuffer__ doesn't give us
+    // the same pointer, so we would need to store it elsewhere if we
+    // wanted to delete it there.  Eh, it's just an int, who cares.
+    view->shape = new Py_ssize_t(size());
+  }
+  view->strides = NULL;
+  if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+    view->strides = &(view->itemsize);
+  }
+  view->suboffsets = NULL;
+
+  // Store a reference to ourselves on the Py_buffer object
+  // as a reminder that we have increased our refcount.
+  ref();
+  view->internal = (void*) this;
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToArray::__releasebuffer__
+//       Access: Published
+//  Description: Releases the buffer allocated by __getbuffer__.
+////////////////////////////////////////////////////////////////////
+template<class Element>
+INLINE void PointerToArray<Element>::
+__releasebuffer__(PyObject *self, Py_buffer *view) const {
+  // Note: PyBuffer_Release automatically decrements view->obj.
+
+  if (view->internal != NULL) {
+    // Oh, right, let's not forget to unref this.
+    ((const PointerToArray<Element> *) view->internal)->unref();
+    view->internal = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConstPointerToArray::__getbuffer__
+//       Access: Published
+//  Description: This is used to implement the buffer protocol, in
+//               order to allow efficient access to the array data
+//               through a Python multiview object.
+////////////////////////////////////////////////////////////////////
+template<class Element>
+INLINE int ConstPointerToArray<Element>::
+__getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
+
+  if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) {
+    cerr << "writable buffer requested of const array\n";
+    PyErr_SetString(PyExc_BufferError,
+                    "Object is not writable.");
+    return -1;
+  }
+
+  const char *format = get_format_code(Element);
+  cerr << "const __getbuffer__ with fmt " << format << "\n";
+  if (format == NULL) {
+    // Not supported.
+    return -1;
+  }
+
+  if (self != NULL) {
+    Py_INCREF(self);
+  }
+  view->obj = self;
+  view->buf = (void*) p();
+  view->len = size() * sizeof(Element);
+  view->readonly = 1;
+  view->itemsize = sizeof(Element);
+  view->format = NULL;
+  if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
+    view->format = (char*) format;
+  }
+  view->ndim = 1;
+  view->shape = NULL;
+  if ((flags & PyBUF_ND) == PyBUF_ND) {
+    // This leaks, which sucks, but __releasebuffer__ doesn't give us
+    // the same pointer, so we would need to store it elsewhere if we
+    // wanted to delete it there.  Eh, it's just an int, who cares.
+    view->shape = new Py_ssize_t(size());
+  }
+  view->strides = NULL;
+  if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+    view->strides = &(view->itemsize);
+  }
+  view->suboffsets = NULL;
+
+  // Store a reference to ourselves on the Py_buffer object
+  // as a reminder that we have increased our refcount.
+  ref();
+  view->internal = (void*) this;
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConstPointerToArray::__releasebuffer__
+//       Access: Published
+//  Description: Releases the buffer allocated by __getbuffer__.
+////////////////////////////////////////////////////////////////////
+template<class Element>
+INLINE void ConstPointerToArray<Element>::
+__releasebuffer__(PyObject *self, Py_buffer *view) const {
+  // Note: PyBuffer_Release automatically decrements obj->view.
+
+  if (view->internal != NULL) {
+    // Oh, right, let's not forget to unref this.
+    ((const PointerToArray<Element> *) view->internal)->unref();
+    view->internal = NULL;
+  }
+}
+#endif  // HAVE_PYTHON
+
 #endif  // CPPPARSER

+ 59 - 7
panda/src/express/pointerToArray.h

@@ -113,7 +113,7 @@ PUBLISHED:
   INLINE PointerToArray(const PointerToArray<Element> &copy);
 
 #ifdef HAVE_PYTHON
-  PointerToArray(PyObject *self, PyObject *sequence);
+  PointerToArray(PyObject *self, PyObject *source);
 #endif
 
   INLINE size_type size() const;
@@ -130,6 +130,11 @@ PUBLISHED:
   INLINE int get_ref_count() const;
   INLINE int get_node_ref_count() const;
 
+#ifdef HAVE_PYTHON
+  int __getbuffer__(PyObject *self, Py_buffer *view, int flags);
+  void __releasebuffer__(PyObject *self, Py_buffer *view) const;
+#endif
+
 #else  // CPPPARSER
   // This is the actual, complete interface.
   typedef TYPENAME PointerToArrayBase<Element>::To To;
@@ -150,7 +155,7 @@ public:
   INLINE PointerToArray(const PointerToArray<Element> &copy);
 
 #ifdef HAVE_PYTHON
-  PointerToArray(PyObject *self, PyObject *sequence);
+  PointerToArray(PyObject *self, PyObject *source);
 #endif
 
 public:
@@ -223,11 +228,18 @@ public:
   INLINE void set_void_ptr(void* p);
 
   INLINE int get_ref_count() const;
+  INLINE void ref() const;
+  INLINE bool unref() const;
 
   INLINE int get_node_ref_count() const;
   INLINE void node_ref() const;
   INLINE bool node_unref() const;
 
+#ifdef HAVE_PYTHON
+  int __getbuffer__(PyObject *self, Py_buffer *view, int flags);
+  void __releasebuffer__(PyObject *self, Py_buffer *view) const;
+#endif
+
   // Reassignment is by pointer, not memberwise as with a vector.
   INLINE PointerToArray<Element> &
   operator = (ReferenceCountedVector<Element> *ptr);
@@ -268,7 +280,7 @@ PUBLISHED:
   INLINE ConstPointerToArray(const ConstPointerToArray<Element> &copy);
 
 #ifdef HAVE_PYTHON
-  INLINE ConstPointerToArray(PyObject *self, PyObject *sequence);
+  INLINE ConstPointerToArray(PyObject *self, PyObject *source);
 #endif
 
   typedef TYPENAME pvector<Element>::size_type size_type;
@@ -280,6 +292,11 @@ PUBLISHED:
   INLINE int get_ref_count() const;
   INLINE int get_node_ref_count() const;
 
+#ifdef HAVE_PYTHON
+  int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
+  void __releasebuffer__(PyObject *self, Py_buffer *view) const;
+#endif
+
 #else  // CPPPARSER
   // This is the actual, complete interface.
   typedef TYPENAME PointerToArrayBase<Element>::To To;
@@ -303,7 +320,7 @@ PUBLISHED:
   INLINE ConstPointerToArray(const ConstPointerToArray<Element> &copy);
 
 #ifdef HAVE_PYTHON
-  INLINE ConstPointerToArray(PyObject *self, PyObject *sequence);
+  INLINE ConstPointerToArray(PyObject *self, PyObject *source);
 #endif
 
   // Duplicating the interface of vector.
@@ -343,11 +360,18 @@ PUBLISHED:
   INLINE string get_subdata(size_type n, size_type count) const;
 
   INLINE int get_ref_count() const;
+  INLINE void ref() const;
+  INLINE bool unref() const;
 
   INLINE int get_node_ref_count() const;
   INLINE void node_ref() const;
   INLINE bool node_unref() const;
 
+#ifdef HAVE_PYTHON
+  int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
+  void __releasebuffer__(PyObject *self, Py_buffer *view) const;
+#endif
+
   // Reassignment is by pointer, not memberwise as with a vector.
   INLINE ConstPointerToArray<Element> &
   operator = (ReferenceCountedVector<Element> *ptr);
@@ -372,12 +396,40 @@ private:
   friend class PointerToArray<Element>;
 };
 
-
 // And the brevity macros.
-
 #define PTA(type) PointerToArray< type >
 #define CPTA(type) ConstPointerToArray< type >
 
+#ifdef HAVE_PYTHON
+// This macro is used to map a data type to a format code
+// as used in the Python 'struct' and 'array' modules.
+#define get_format_code(type) _get_format_code((const type *)0)
+#define define_format_code(code, type) template<> \
+  INLINE const char *_get_format_code(const type *) { \
+    return code; \
+  }
+
+template<class T>
+INLINE const char *_get_format_code(const T *) {
+  return NULL;
+}
+
+define_format_code("c", char);
+define_format_code("b", signed char);
+define_format_code("B", unsigned char);
+define_format_code("h", short);
+define_format_code("H", unsigned short);
+define_format_code("i", int);
+define_format_code("I", unsigned int);
+define_format_code("l", long);
+define_format_code("L", unsigned long);
+define_format_code("q", long long);
+define_format_code("Q", unsigned long long);
+define_format_code("f", float);
+define_format_code("d", double);
+
+#endif  // HAVE_PYTHON
+
 #include "pointerToArray.I"
 
-#endif
+#endif  // HAVE_POINTERTOARRAY_H

+ 0 - 67
panda/src/express/virtualFileSystem.cxx

@@ -920,41 +920,6 @@ get_global_ptr() {
   return _global_ptr;
 }
 
-#ifdef HAVE_PYTHON
-////////////////////////////////////////////////////////////////////
-//     Function: VirtualFileSystem::__py__read_file
-//       Access: Published
-//  Description: Convenience function; returns the entire contents of
-//               the indicated file as a string (or as a bytes object,
-//               in Python 3).
-//
-//               This variant on read_file() is implemented directly
-//               for Python, as a small optimization, to avoid the
-//               double-construction of a string object that would be
-//               otherwise required for the return value.
-////////////////////////////////////////////////////////////////////
-PyObject *VirtualFileSystem::
-__py__read_file(const Filename &filename, bool auto_unwrap) const {
-  pvector<unsigned char> pv;
-  bool okflag = read_file(filename, pv, auto_unwrap);
-  nassertr(okflag, NULL);
-
-#if PY_MAJOR_VERSION >= 3
-  if (pv.empty()) {
-    return PyBytes_FromStringAndSize("", 0);
-  } else {
-    return PyBytes_FromStringAndSize((const char *)&pv[0], pv.size());
-  }
-#else
-  if (pv.empty()) {
-    return PyString_FromStringAndSize("", 0);
-  } else {
-    return PyString_FromStringAndSize((const char *)&pv[0], pv.size());
-  }
-#endif
-}
-#endif  // HAVE_PYTHON
-
 ////////////////////////////////////////////////////////////////////
 //     Function: VirtualFileSystem::open_read_file
 //       Access: Published
@@ -1007,38 +972,6 @@ close_read_file(istream *stream) {
   }
 }
 
-#ifdef HAVE_PYTHON
-////////////////////////////////////////////////////////////////////
-//     Function: VirtualFileSystem::__py__write_file
-//       Access: Published
-//  Description: Convenience function; writes the entire contents of
-//               the indicated file as a string.
-//
-//               This variant on write_file() is implemented directly
-//               for Python, as a small optimization, to avoid the
-//               double-construction of a string object that would be
-//               otherwise required.
-////////////////////////////////////////////////////////////////////
-PyObject *VirtualFileSystem::
-__py__write_file(const Filename &filename, PyObject *data, bool auto_wrap) {
-  char *buffer;
-  Py_ssize_t length;
-
-#if PY_MAJOR_VERSION >= 3
-  if (PyBytes_AsStringAndSize(data, &buffer, &length) == -1) {
-    return NULL;
-  }
-#else
-  if (PyString_AsStringAndSize(data, &buffer, &length) == -1) {
-    return NULL;
-  }
-#endif
-   
-  bool result = write_file(filename, (const unsigned char *)buffer, length, auto_wrap);
-  return PyBool_FromLong(result);
-}
-#endif  // HAVE_PYTHON
-
 ////////////////////////////////////////////////////////////////////
 //     Function: VirtualFileSystem::open_write_file
 //       Access: Published

+ 6 - 9
panda/src/express/virtualFileSystem.h

@@ -98,18 +98,11 @@ PUBLISHED:
 
   static VirtualFileSystem *get_global_ptr();
 
-#ifdef HAVE_PYTHON
-  BLOCKING PyObject *__py__read_file(const Filename &filename, bool auto_unwrap) const;
-#endif  // HAVE_PYTHON
-  BLOCKING INLINE string read_file(const Filename &filename, bool auto_unwrap) const;
-
+  EXTENSION(BLOCKING PyObject *read_file(const Filename &filename, bool auto_unwrap) const);
   BLOCKING istream *open_read_file(const Filename &filename, bool auto_unwrap) const;
   BLOCKING static void close_read_file(istream *stream);
 
-#ifdef HAVE_PYTHON
-  BLOCKING PyObject *__py__write_file(const Filename &filename, PyObject *data, bool auto_wrap);
-#endif  // HAVE_PYTHON
-  BLOCKING INLINE bool write_file(const Filename &filename, const string &data, bool auto_wrap);
+  EXTENSION(BLOCKING PyObject *write_file(const Filename &filename, PyObject *data, bool auto_wrap));
   BLOCKING ostream *open_write_file(const Filename &filename, bool auto_wrap, bool truncate);
   BLOCKING ostream *open_append_file(const Filename &filename);
   BLOCKING static void close_write_file(ostream *stream);
@@ -119,6 +112,10 @@ PUBLISHED:
   BLOCKING static void close_read_write_file(iostream *stream);
 
 public:
+  // We provide Python versions of these as efficient extension methods, above.
+  BLOCKING INLINE string read_file(const Filename &filename, bool auto_unwrap) const;
+  BLOCKING INLINE bool write_file(const Filename &filename, const string &data, bool auto_wrap);
+
   bool atomic_compare_and_exchange_contents(const Filename &filename, string &orig_contents, const string &old_contents, const string &new_contents);
   bool atomic_read_contents(const Filename &filename, string &contents) const;
 

+ 82 - 0
panda/src/express/virtualFileSystem_ext.cxx

@@ -0,0 +1,82 @@
+// Filename: virtualFileSystem_ext.cxx
+// Created by:  rdb (12Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "virtualFileSystem_ext.h"
+
+#ifdef HAVE_PYTHON
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::read_file
+//       Access: Published
+//  Description: Convenience function; returns the entire contents of
+//               the indicated file as a string (or as a bytes object,
+//               in Python 3).
+//
+//               This variant on read_file() is implemented directly
+//               for Python, as a small optimization, to avoid the
+//               double-construction of a string object that would be
+//               otherwise required for the return value.
+////////////////////////////////////////////////////////////////////
+PyObject *Extension<VirtualFileSystem>::
+read_file(const Filename &filename, bool auto_unwrap) const {
+  pvector<unsigned char> pv;
+  bool okflag = _this->read_file(filename, pv, auto_unwrap);
+  nassertr(okflag, NULL);
+
+#if PY_MAJOR_VERSION >= 3
+  if (pv.empty()) {
+    return PyBytes_FromStringAndSize("", 0);
+  } else {
+    return PyBytes_FromStringAndSize((const char *)&pv[0], pv.size());
+  }
+#else
+  if (pv.empty()) {
+    return PyString_FromStringAndSize("", 0);
+  } else {
+    return PyString_FromStringAndSize((const char *)&pv[0], pv.size());
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::write_file
+//       Access: Published
+//  Description: Convenience function; writes the entire contents of
+//               the indicated file as a string.
+//
+//               This variant on write_file() is implemented directly
+//               for Python, as a small optimization, to avoid the
+//               double-construction of a string object that would be
+//               otherwise required.
+////////////////////////////////////////////////////////////////////
+PyObject *Extension<VirtualFileSystem>::
+write_file(const Filename &filename, PyObject *data, bool auto_wrap) {
+  char *buffer;
+  Py_ssize_t length;
+
+#if PY_MAJOR_VERSION >= 3
+  if (PyBytes_AsStringAndSize(data, &buffer, &length) == -1) {
+    return NULL;
+  }
+#else
+  if (PyString_AsStringAndSize(data, &buffer, &length) == -1) {
+    return NULL;
+  }
+#endif
+
+  bool result = _this->write_file(filename, (const unsigned char *)buffer, length, auto_wrap);
+  return PyBool_FromLong(result);
+}
+
+#endif  // HAVE_PYTHOS

+ 41 - 0
panda/src/express/virtualFileSystem_ext.h

@@ -0,0 +1,41 @@
+// Filename: virtualFileSystem_ext.h
+// Created by:  rdb (12Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef VIRTUALFILESYSTEM_EXT_H
+#define VIRTUALFILESYSTEM_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "virtualFileSystem.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<VirtualFileSystem>
+// Description : This class defines the extension methods for
+//               VirtualFileSystem, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<VirtualFileSystem> : public ExtensionBase<VirtualFileSystem> {
+public:
+  PyObject *read_file(Filename const &filename, bool auto_unwrap) const;
+  PyObject *write_file(Filename const &filename, PyObject *data, bool auto_wrap);
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // VIRTUALFILESYSTEM_EXT_H

+ 1 - 0
panda/src/gobj/Sources.pp

@@ -30,6 +30,7 @@
     geomLinestrips.h \
     geomPoints.h \
     geomVertexArrayData.h geomVertexArrayData.I \
+    geomVertexArrayData_ext.h geomVertexArrayData_ext.cxx \
     geomVertexArrayFormat.h geomVertexArrayFormat.I \
     geomCacheEntry.h geomCacheEntry.I \
     geomCacheManager.h geomCacheManager.I \

+ 4 - 0
panda/src/gobj/geomVertexArrayData.h

@@ -114,6 +114,10 @@ PUBLISHED:
   static void lru_epoch();
   INLINE static VertexDataBook &get_book();
 
+  EXTENSION(int __getbuffer__(PyObject *self, Py_buffer *view, int flags));
+  EXTENSION(int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const);
+  EXTENSION(void __releasebuffer__(PyObject *self, Py_buffer *view) const);
+
 public:
   virtual void evict_lru();
 

+ 167 - 0
panda/src/gobj/geomVertexArrayData_ext.cxx

@@ -0,0 +1,167 @@
+// Filename: geomVertexArrayData_ext.I
+// Created by:  rdb (05Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "geomVertexArrayData_ext.h"
+
+struct InternalBufferData {
+  CPT(GeomVertexArrayDataHandle) _handle;
+  Py_ssize_t _num_rows;
+  Py_ssize_t _stride;
+  string _format;
+};
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::__getbuffer__
+//       Access: Published
+//  Description: This is used to implement the buffer protocol, in
+//               order to allow efficient access to the array data
+//               through a Python multiview object.
+////////////////////////////////////////////////////////////////////
+int Extension<GeomVertexArrayData>::
+__getbuffer__(PyObject *self, Py_buffer *view, int flags) {
+
+  PT(GeomVertexArrayDataHandle) handle = _this->modify_handle();
+  CPT(GeomVertexArrayFormat) format = handle->get_array_format();
+
+  int row_size;
+  bool pad_fmt;
+
+  if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+    // The consumer is fine with having a stride value.
+    row_size = format->get_total_bytes();
+    pad_fmt = false;
+  } else {
+    // The consumer expects a contiguous buffer.  Give the
+    // stride as row size, and pad the format with extra bytes.
+    row_size = format->get_stride();
+    pad_fmt = true;
+  }
+
+  InternalBufferData *data = new InternalBufferData;
+  data->_handle = handle;
+  data->_num_rows = handle->get_num_rows();
+  data->_stride = format->get_stride();
+  data->_format = format->get_format_string(pad_fmt);
+
+  view->internal = (void*) data;
+
+  if (self != NULL) {
+    Py_INCREF(self);
+  }
+  view->obj = self;
+  view->buf = (void*) handle->get_write_pointer();
+  view->len = row_size * handle->get_num_rows();
+  view->readonly = 0;
+  view->itemsize = row_size;
+  view->format = NULL;
+  if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
+    view->format = (char*) data->_format.c_str();
+  }
+  view->ndim = 1;
+  view->shape = NULL;
+  if ((flags & PyBUF_ND) == PyBUF_ND) {
+    view->shape = &data->_num_rows;
+  }
+  view->strides = NULL;
+  if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+    view->strides = &data->_stride;
+  }
+  view->suboffsets = NULL;
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::__getbuffer__
+//       Access: Published
+//  Description: This is the const version of __getbuffer__, which
+//               does not support writing.
+////////////////////////////////////////////////////////////////////
+int Extension<GeomVertexArrayData>::
+__getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
+
+  if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) {
+      PyErr_SetString(PyExc_BufferError,
+                      "Object is not writable.");
+      return -1;
+  }
+
+  CPT(GeomVertexArrayDataHandle) handle = _this->get_handle();
+  CPT(GeomVertexArrayFormat) format = handle->get_array_format();
+
+  int row_size;
+  bool pad_fmt;
+
+  if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+    // The consumer is fine with having a stride value.
+    row_size = format->get_total_bytes();
+    pad_fmt = false;
+  } else {
+    // The consumer expects a contiguous buffer.  Give the
+    // stride as row size, and pad the format with extra bytes.
+    row_size = format->get_stride();
+    pad_fmt = true;
+  }
+
+  InternalBufferData *data = new InternalBufferData;
+  data->_handle = handle;
+  data->_num_rows = handle->get_num_rows();
+  data->_stride = format->get_stride();
+  data->_format = format->get_format_string(pad_fmt);
+
+  view->internal = (void*) data;
+
+  if (self != NULL) {
+    Py_INCREF(self);
+  }
+  view->obj = self;
+  view->buf = (void*) handle->get_read_pointer(true);
+  view->len = row_size * handle->get_num_rows();
+  view->readonly = 1;
+  view->itemsize = row_size;
+  view->format = NULL;
+  if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
+    view->format = (char*) data->_format.c_str();
+  }
+  view->ndim = 1;
+  view->shape = NULL;
+  if ((flags & PyBUF_ND) == PyBUF_ND) {
+    view->shape = &data->_num_rows;
+  }
+  view->strides = NULL;
+  if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+    view->strides = &data->_stride;
+  }
+  view->suboffsets = NULL;
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::__releasebuffer__
+//       Access: Published
+//  Description: Releases the buffer allocated by __getbuffer__.
+////////////////////////////////////////////////////////////////////
+void Extension<GeomVertexArrayData>::
+__releasebuffer__(PyObject *self, Py_buffer *view) const {
+  // Note: PyBuffer_Release automatically decrements view->obj.
+
+  InternalBufferData *data;
+  data = (InternalBufferData *) view->internal;
+  if (data == NULL) {
+    return;
+  }
+  delete data;
+  view->internal = NULL;
+}

+ 42 - 0
panda/src/gobj/geomVertexArrayData_ext.h

@@ -0,0 +1,42 @@
+// Filename: geomVertexArrayData_ext.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GEOMVERTEXARRAYDATA_EXT_H
+#define GEOMVERTEXARRAYDATA_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "geomVertexArrayData.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<GeomVertexArrayData>
+// Description : This class defines the extension methods for
+//               GeomVertexArrayData, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<GeomVertexArrayData> : public ExtensionBase<GeomVertexArrayData> {
+public:
+  int __getbuffer__(PyObject *self, Py_buffer *view, int flags);
+  int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
+  void __releasebuffer__(PyObject *self, Py_buffer *view) const;
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // GEOMVERTEXARRAYDATA_EXT_H

+ 77 - 0
panda/src/gobj/geomVertexArrayFormat.cxx

@@ -578,6 +578,83 @@ write_with_data(ostream &out, int indent_level,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayFormat::get_format_string
+//       Access: Published
+//  Description: Returns a string with format codes representing the
+//               exact memory layout of the columns in memory, as
+//               understood by Python's struct module.
+//               If pad is true, extra padding bytes are added to
+//               the end as 'x' characters as needed.
+////////////////////////////////////////////////////////////////////
+string GeomVertexArrayFormat::
+get_format_string(bool pad) const {
+  consider_sort_columns();
+
+  int row_size;
+  if (pad) {
+    row_size = get_stride();
+  } else {
+    row_size = get_total_bytes();
+  }
+
+  // Synthesize the format string.
+  char *fmt = (char*) malloc(row_size + 1);
+  memset((void*) fmt, 0, row_size + 1);
+  int fi = 0;
+  int offset = 0;
+
+  for (int ci = 0; ci < get_num_columns(); ++ci) {
+    const GeomVertexColumn *column = get_column(ci);
+
+    if (offset < column->get_start()) {
+      // Add padding bytes to fill the gap.
+      int pad = column->get_start() - offset;
+      memset((void*) (fmt + fi), 'x', pad);
+      fi += pad;
+      offset += pad;
+    }
+
+    char fmt_code = 'x';
+    switch (column->get_numeric_type()) {
+    case NT_uint8:
+      fmt_code = 'B';
+      break;
+    case NT_uint16:
+      fmt_code = 'H';
+      break;
+    case NT_uint32:
+    case NT_packed_dcba:
+    case NT_packed_dabc:
+      fmt_code = 'I';
+      break;
+    case NT_float32:
+      fmt_code = 'f';
+      break;
+    case NT_float64:
+      fmt_code = 'd';
+      break;
+    default:
+      gobj_cat.error()
+        << "Unknown numeric type " << column->get_numeric_type() << "!\n";
+      return NULL;
+    }
+    memset((void*) (fmt + fi), fmt_code, column->get_num_components());
+    offset += column->get_total_bytes();
+    fi += column->get_num_components();
+  }
+
+  if (offset < row_size) {
+    // Add padding bytes.
+    int pad = row_size - offset;
+    memset((void*) (fmt + fi), 'x', pad);
+  }
+
+  string fmt_string (fmt);
+  free(fmt);
+  return fmt_string;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::compare_to
 //       Access: Public

+ 2 - 0
panda/src/gobj/geomVertexArrayFormat.h

@@ -115,6 +115,8 @@ PUBLISHED:
   void write_with_data(ostream &out, int indent_level, 
                        const GeomVertexArrayData *array_data) const;
 
+  string get_format_string(bool pad = true) const;
+
 public:
   int compare_to(const GeomVertexArrayFormat &other) const;
 

+ 5 - 5
panda/src/linmath/Sources.pp

@@ -15,7 +15,7 @@
      coordinateSystem.h dbl2fltnames.h dblnames.h \
      deg_2_rad.h deg_2_rad.I \
      flt2dblnames.h fltnames.h lcast_to.h lcast_to_src.h  \
-     lcast_to_src.I lmatrix.h lmatrix_ext.I lmatrix3_src.I  \
+     lcast_to_src.I lmatrix.h lmatrix_ext.h lmatrix3_src.I  \
      lmatrix3_src.cxx lmatrix3_src.h lmatrix4_src.I  \
      lmatrix4_src.cxx lmatrix4_src.h lorientation.h  \
      lorientation_src.I lorientation_src.cxx lorientation_src.h  \
@@ -37,12 +37,12 @@
      lvector3.h lvector3_src.I lvector3_src.cxx lvector3_src.h  \
      lvector4.h lvector4_src.I lvector4_src.cxx lvector4_src.h  \
      lvector4.h lvector4_src.I lvector4_src.cxx lvector4_src.h  \
-     lvecBase2_ext.I lvecBase3_ext.I lvecBase4_ext.I \
-     lpoint2_ext.I lpoint3_ext.I lpoint4_ext.I \
-     lvector2_ext.I lvector3_ext.I lvector4_ext.I \
+     lvecBase2_ext.h lvecBase3_ext.h lvecBase4_ext.h \
+     lpoint2_ext.h lpoint3_ext.h lpoint4_ext.h \
+     lvector2_ext.h lvector3_ext.h lvector4_ext.h \
      mathNumbers.h mathNumbers.I 
     
-   #define INCLUDED_SOURCES \
+  #define INCLUDED_SOURCES \
      compose_matrix.cxx config_linmath.cxx coordinateSystem.cxx  \
      lmatrix.cxx \
      lorientation.cxx lpoint2.cxx  \

+ 19 - 19
panda/src/linmath/lmatrix3_ext_src.I

@@ -18,10 +18,10 @@
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_NESTED_METHOD_ARGS(FLOATNAME(LMatrix3), Row,
-__setitem__, int i, FLOATTYPE v) {
+INLINE_LINMATH void Extension<FLOATNAME(LMatrix3)::Row>::
+__setitem__(int i, FLOATTYPE v) {
   nassertv(i >= 0 && i < 3);
-  this->_row[i] = v;
+  _this->_row[i] = v;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -30,8 +30,8 @@ __setitem__, int i, FLOATTYPE v) {
 //  Description: This special Python method is implement to provide
 //               support for the pickle module.
 ////////////////////////////////////////////////////////////////////
-PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LMatrix3),
-__reduce__, PyObject *self) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LMatrix3)>::
+__reduce__(PyObject *self) const {
   // We should return at least a 2-tuple, (Class, (args)): the
   // necessary class object whose constructor we should call
   // (e.g. this), and the arguments necessary to reconstruct this
@@ -42,9 +42,9 @@ __reduce__, PyObject *self) {
   }
 
   PyObject *result = Py_BuildValue("(O(fffffffff))", this_class, 
-    this->_m(0, 0), this->_m(0, 1), this->_m(0, 2),
-    this->_m(1, 0), this->_m(1, 1), this->_m(1, 2),
-    this->_m(2, 0), this->_m(2, 1), this->_m(2, 2));
+    _this->_m(0, 0), _this->_m(0, 1), _this->_m(0, 2),
+    _this->_m(1, 0), _this->_m(1, 1), _this->_m(1, 2),
+    _this->_m(2, 0), _this->_m(2, 1), _this->_m(2, 2));
 
   Py_DECREF(this_class);
   return result;
@@ -55,19 +55,19 @@ __reduce__, PyObject *self) {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void EXT_CONST_METHOD_ARGS(FLOATNAME(LMatrix3),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LMatrix3)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "(" 
-      << MAYBE_ZERO(this->_m(0, 0)) << ", "
-      << MAYBE_ZERO(this->_m(0, 1)) << ", "
-      << MAYBE_ZERO(this->_m(0, 2)) << ", "
+      << MAYBE_ZERO(_this->_m(0, 0)) << ", "
+      << MAYBE_ZERO(_this->_m(0, 1)) << ", "
+      << MAYBE_ZERO(_this->_m(0, 2)) << ", "
 
-      << MAYBE_ZERO(this->_m(1, 0)) << ", "
-      << MAYBE_ZERO(this->_m(1, 1)) << ", "
-      << MAYBE_ZERO(this->_m(1, 2)) << ", "
+      << MAYBE_ZERO(_this->_m(1, 0)) << ", "
+      << MAYBE_ZERO(_this->_m(1, 1)) << ", "
+      << MAYBE_ZERO(_this->_m(1, 2)) << ", "
 
-      << MAYBE_ZERO(this->_m(2, 0)) << ", "
-      << MAYBE_ZERO(this->_m(2, 1)) << ", "
-      << MAYBE_ZERO(this->_m(2, 2)) << ")";
+      << MAYBE_ZERO(_this->_m(2, 0)) << ", "
+      << MAYBE_ZERO(_this->_m(2, 1)) << ", "
+      << MAYBE_ZERO(_this->_m(2, 2)) << ")";
 }
 

+ 41 - 0
panda/src/linmath/lmatrix3_ext_src.h

@@ -0,0 +1,41 @@
+// Filename: lmatrix3_ext_src.h
+// Created by:  rdb (12Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LMatrix3::Row>
+// Description : This class defines the extension methods for
+//               LMatrix3::Row, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LMatrix3)::Row> : public ExtensionBase<FLOATNAME(LMatrix3)::Row> {
+public:
+  INLINE_LINMATH void __setitem__(int i, FLOATTYPE v);
+};
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LMatrix3>
+// Description : This class defines the extension methods for
+//               LMatrix3, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LMatrix3)> : public ExtensionBase<FLOATNAME(LMatrix3)> {
+public:
+  INLINE_LINMATH PyObject *__reduce__(PyObject *self) const;
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+#include "lmatrix3_ext_src.I"

+ 2 - 2
panda/src/linmath/lmatrix3_src.h

@@ -63,7 +63,7 @@ PUBLISHED:
     FLOATTYPE e20, FLOATTYPE e21, FLOATTYPE e22);
   ALLOC_DELETED_CHAIN(FLOATNAME(LMatrix3));
 
-  EXTENSION(PyObject *__reduce__(PyObject *self) const);
+  EXTENSION(INLINE_LINMATH PyObject *__reduce__(PyObject *self) const);
 
   void fill(FLOATTYPE fill_value);
   INLINE_LINMATH void set(
@@ -283,7 +283,7 @@ PUBLISHED:
 
   void output(ostream &out) const;
   void write(ostream &out, int indent_level = 0) const;
-  EXTENSION(void python_repr(ostream &out, const string &class_name) const);
+  EXTENSION(INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const);
 
   INLINE_LINMATH void generate_hash(ChecksumHashGenerator &hashgen) const;
   void generate_hash(

+ 27 - 27
panda/src/linmath/lmatrix4_ext_src.I

@@ -18,10 +18,10 @@
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_NESTED_METHOD_ARGS(FLOATNAME(LMatrix4), Row,
-__setitem__, int i, FLOATTYPE v) {
+INLINE_LINMATH void Extension<FLOATNAME(LMatrix4)::Row>::
+__setitem__(int i, FLOATTYPE v) {
   nassertv(i >= 0 && i < 4);
-  this->_row[i] = v;
+  _this->_row[i] = v;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -30,8 +30,8 @@ __setitem__, int i, FLOATTYPE v) {
 //  Description: This special Python method is implement to provide
 //               support for the pickle module.
 ////////////////////////////////////////////////////////////////////
-PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LMatrix4),
-__reduce__, PyObject *self) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LMatrix4)>::
+__reduce__(PyObject *self) const {
   // We should return at least a 2-tuple, (Class, (args)): the
   // necessary class object whose constructor we should call
   // (e.g. this), and the arguments necessary to reconstruct this
@@ -42,10 +42,10 @@ __reduce__, PyObject *self) {
   }
 
   PyObject *result = Py_BuildValue("(O(ffffffffffffffff))", this_class, 
-    this->_m(0, 0), this->_m(0, 1), this->_m(0, 2), this->_m(0, 3),
-    this->_m(1, 0), this->_m(1, 1), this->_m(1, 2), this->_m(1, 3),
-    this->_m(2, 0), this->_m(2, 1), this->_m(2, 2), this->_m(2, 3),
-    this->_m(3, 0), this->_m(3, 1), this->_m(3, 2), this->_m(3, 3));
+    _this->_m(0, 0), _this->_m(0, 1), _this->_m(0, 2), _this->_m(0, 3),
+    _this->_m(1, 0), _this->_m(1, 1), _this->_m(1, 2), _this->_m(1, 3),
+    _this->_m(2, 0), _this->_m(2, 1), _this->_m(2, 2), _this->_m(2, 3),
+    _this->_m(3, 0), _this->_m(3, 1), _this->_m(3, 2), _this->_m(3, 3));
 
   Py_DECREF(this_class);
   return result;
@@ -56,27 +56,27 @@ __reduce__, PyObject *self) {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void EXT_CONST_METHOD_ARGS(FLOATNAME(LMatrix4),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LMatrix4)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "(" 
-      << MAYBE_ZERO(this->_m(0, 0)) << ", "
-      << MAYBE_ZERO(this->_m(0, 1)) << ", "
-      << MAYBE_ZERO(this->_m(0, 2)) << ", "
-      << MAYBE_ZERO(this->_m(0, 3)) << ", "
+      << MAYBE_ZERO(_this->_m(0, 0)) << ", "
+      << MAYBE_ZERO(_this->_m(0, 1)) << ", "
+      << MAYBE_ZERO(_this->_m(0, 2)) << ", "
+      << MAYBE_ZERO(_this->_m(0, 3)) << ", "
 
-      << MAYBE_ZERO(this->_m(1, 0)) << ", "
-      << MAYBE_ZERO(this->_m(1, 1)) << ", "
-      << MAYBE_ZERO(this->_m(1, 2)) << ", "
-      << MAYBE_ZERO(this->_m(1, 3)) << ", "
+      << MAYBE_ZERO(_this->_m(1, 0)) << ", "
+      << MAYBE_ZERO(_this->_m(1, 1)) << ", "
+      << MAYBE_ZERO(_this->_m(1, 2)) << ", "
+      << MAYBE_ZERO(_this->_m(1, 3)) << ", "
 
-      << MAYBE_ZERO(this->_m(2, 0)) << ", "
-      << MAYBE_ZERO(this->_m(2, 1)) << ", "
-      << MAYBE_ZERO(this->_m(2, 2)) << ", "
-      << MAYBE_ZERO(this->_m(2, 3)) << ", "
+      << MAYBE_ZERO(_this->_m(2, 0)) << ", "
+      << MAYBE_ZERO(_this->_m(2, 1)) << ", "
+      << MAYBE_ZERO(_this->_m(2, 2)) << ", "
+      << MAYBE_ZERO(_this->_m(2, 3)) << ", "
 
-      << MAYBE_ZERO(this->_m(3, 0)) << ", "
-      << MAYBE_ZERO(this->_m(3, 1)) << ", "
-      << MAYBE_ZERO(this->_m(3, 2)) << ", "
-      << MAYBE_ZERO(this->_m(3, 3)) << ")";
+      << MAYBE_ZERO(_this->_m(3, 0)) << ", "
+      << MAYBE_ZERO(_this->_m(3, 1)) << ", "
+      << MAYBE_ZERO(_this->_m(3, 2)) << ", "
+      << MAYBE_ZERO(_this->_m(3, 3)) << ")";
 }
 

+ 41 - 0
panda/src/linmath/lmatrix4_ext_src.h

@@ -0,0 +1,41 @@
+// Filename: lmatrix4_ext_src.h
+// Created by:  rdb (12Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LMatrix4::Row>
+// Description : This class defines the extension methods for
+//               LMatrix4::Row, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LMatrix4)::Row> : public ExtensionBase<FLOATNAME(LMatrix4)::Row> {
+public:
+  INLINE_LINMATH void __setitem__(int i, FLOATTYPE v);
+};
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LMatrix4>
+// Description : This class defines the extension methods for
+//               LMatrix4, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LMatrix4)> : public ExtensionBase<FLOATNAME(LMatrix4)> {
+public:
+  INLINE_LINMATH PyObject *__reduce__(PyObject *self) const;
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+#include "lmatrix4_ext_src.I"

+ 2 - 2
panda/src/linmath/lmatrix4_src.h

@@ -63,7 +63,7 @@ PUBLISHED:
                                      FLOATTYPE e30, FLOATTYPE e31, FLOATTYPE e32, FLOATTYPE e33);
   ALLOC_DELETED_CHAIN(FLOATNAME(LMatrix4));
 
-  EXTENSION(PyObject *__reduce__(PyObject *self) const);
+  EXTENSION(INLINE_LINMATH PyObject *__reduce__(PyObject *self) const);
 
   // Construct a 4x4 matrix given a 3x3 rotation matrix and an optional
   // translation component.
@@ -257,7 +257,7 @@ PUBLISHED:
 
   void output(ostream &out) const;
   void write(ostream &out, int indent_level = 0) const;
-  EXTENSION(void python_repr(ostream &out, const string &class_name) const);
+  EXTENSION(INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const);
 
   INLINE_LINMATH void generate_hash(ChecksumHashGenerator &hashgen) const;
   void generate_hash(ChecksumHashGenerator &hashgen, FLOATTYPE scale) const;

+ 12 - 6
panda/src/linmath/lmatrix_ext.I → panda/src/linmath/lmatrix_ext.h

@@ -1,5 +1,5 @@
-// Filename: lmatrix_ext.I
-// Created by:  rdb (02Jan11)
+// Filename: lmatrix_ext.h
+// Created by:  rdb (13Sep13)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,12 +12,18 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifndef LMATRIX_EXT_H
+#define LMATRIX_EXT_H
+
 #include "lmatrix.h"
+#include "extension.h"
 
 #include "fltnames.h"
-#include "lmatrix3_ext_src.I"
-#include "lmatrix4_ext_src.I"
+#include "lmatrix3_ext_src.h"
+#include "lmatrix4_ext_src.h"
 
 #include "dblnames.h"
-#include "lmatrix3_ext_src.I"
-#include "lmatrix4_ext_src.I"
+#include "lmatrix3_ext_src.h"
+#include "lmatrix4_ext_src.h"
+
+#endif

+ 10 - 3
panda/src/linmath/lpoint2_ext.I → panda/src/linmath/lpoint2_ext.h

@@ -1,5 +1,5 @@
 // Filename: lpoint2_ext.I
-// Created by:  rdb (02Jan11)
+// Created by:  rdb (13Sep13)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,11 +12,18 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifndef LPOINT2_EXT_H
+#define LPOINT2_EXT_H
+
 #include "lpoint2.h"
+#include "extension.h"
+
+#include "lvecBase2_ext.h"
 
 #include "fltnames.h"
-#include "lpoint2_ext_src.I"
+#include "lpoint2_ext_src.h"
 
 #include "dblnames.h"
-#include "lpoint2_ext_src.I"
+#include "lpoint2_ext_src.h"
 
+#endif

+ 36 - 20
panda/src/linmath/lpoint2_ext_src.I

@@ -12,9 +12,10 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
 #ifndef CPPPARSER
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint2);
+IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint3);
+IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint4);
 #endif
 
 ////////////////////////////////////////////////////////////////////
@@ -22,11 +23,11 @@ IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint2);
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_CONST_METHOD_ARGS(FLOATNAME(LPoint2),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LPoint2)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "("
-      << MAYBE_ZERO(this->_v(0)) << ", "
-      << MAYBE_ZERO(this->_v(1)) << ")";
+      << MAYBE_ZERO(_this->_v(0)) << ", "
+      << MAYBE_ZERO(_this->_v(1)) << ")";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -34,8 +35,8 @@ python_repr, ostream &out, const string &class_name) {
 //       Access: Published
 //  Description: This is used to implement swizzle masks.
 ////////////////////////////////////////////////////////////////////
-INLINE PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LPoint2),
-__getattr__, const string &attr_name) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LPoint2)>::
+__getattr__(const string &attr_name) const {
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
     if (*it != 'x' && *it != 'y') {
@@ -43,28 +44,43 @@ __getattr__, const string &attr_name) {
     }
   }
 
-  if (attr_name.size() == 1) {
-    return PyFloat_FromDouble(this->_v(attr_name[0] - 'x'));
+  switch (attr_name.size()) {
+    case 1:
+      return PyFloat_FromDouble(_this->_v(attr_name[0] - 'x'));
+
+    case 2: {
+      FLOATNAME(LPoint2) *vec = new FLOATNAME(LPoint2);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint2), true, false);
+
+    } case 3: {
+      FLOATNAME(LPoint3) *vec = new FLOATNAME(LPoint3);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint3), true, false);
 
-  } else if (attr_name.size() == 2) {
-    FLOATNAME(LPoint2) *vec = new FLOATNAME(LPoint2);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint2), true, false);
+    } case 4: {
+      FLOATNAME(LPoint4) *vec = new FLOATNAME(LPoint4);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      vec->_v(3) = _this->_v(attr_name[3] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint4), true, false);
+    }
   }
 
   return NULL;
 }
 
-int EXT_METHOD_ARGS(FLOATNAME(LVecBase2), __setattr__, PyObject*, const string&, PyObject*);
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint2::__setattr__
 //       Access: Published
 //  Description: This is used to implement write masks.
 ////////////////////////////////////////////////////////////////////
-INLINE int EXT_METHOD_ARGS(FLOATNAME(LPoint2),
-__setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
-  return CALL_EXT_METHOD(FLOATNAME(LVecBase2), __setattr__, this, self, attr_name, assign);
+INLINE_LINMATH int Extension<FLOATNAME(LPoint2)>::
+__setattr__(PyObject *self, const string &attr_name, PyObject *assign) {
+  // Upcall to LVecBase2.
+  return invoke_extension<FLOATNAME(LVecBase2)>(_this, _self).__setattr__(self, attr_name, assign);
 }
-

+ 30 - 0
panda/src/linmath/lpoint2_ext_src.h

@@ -0,0 +1,30 @@
+// Filename: lpoint2_ext_src.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LPoint2>
+// Description : This class defines the extension methods for
+//               LPoint2, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LPoint2)> : public ExtensionBase<FLOATNAME(LPoint2)> {
+public:
+  INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const;
+  INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign);
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+#include "lpoint2_ext_src.I"

+ 2 - 2
panda/src/linmath/lpoint2_src.h

@@ -26,8 +26,8 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LPoint2)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LPoint2)(FLOATTYPE x, FLOATTYPE y);
 
-  EXTENSION(PyObject *__getattr__(const string &attr_name) const);
-  EXTENSION(int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
+  EXTENSION(INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const);
+  EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH static const FLOATNAME(LPoint2) &zero();
   INLINE_LINMATH static const FLOATNAME(LPoint2) &unit_x();

+ 10 - 3
panda/src/linmath/lpoint3_ext.I → panda/src/linmath/lpoint3_ext.h

@@ -1,5 +1,5 @@
 // Filename: lpoint3_ext.I
-// Created by:  rdb (02Jan11)
+// Created by:  rdb (13Sep13)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,11 +12,18 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifndef LPOINT3_EXT_H
+#define LPOINT3_EXT_H
+
 #include "lpoint3.h"
+#include "extension.h"
+
+#include "lvecBase3_ext.h"
 
 #include "fltnames.h"
-#include "lpoint3_ext_src.I"
+#include "lpoint3_ext_src.h"
 
 #include "dblnames.h"
-#include "lpoint3_ext_src.I"
+#include "lpoint3_ext_src.h"
 
+#endif

+ 35 - 27
panda/src/linmath/lpoint3_ext_src.I

@@ -12,10 +12,10 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
 #ifndef CPPPARSER
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint2);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint3);
+IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint4);
 #endif
 
 ////////////////////////////////////////////////////////////////////
@@ -23,12 +23,12 @@ IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint3);
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_CONST_METHOD_ARGS(FLOATNAME(LPoint3),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LPoint3)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "("
-      << MAYBE_ZERO(this->_v(0)) << ", "
-      << MAYBE_ZERO(this->_v(1)) << ", "
-      << MAYBE_ZERO(this->_v(2)) << ")";
+      << MAYBE_ZERO(_this->_v(0)) << ", "
+      << MAYBE_ZERO(_this->_v(1)) << ", "
+      << MAYBE_ZERO(_this->_v(2)) << ")";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -36,8 +36,8 @@ python_repr, ostream &out, const string &class_name) {
 //       Access: Published
 //  Description: This is used to implement swizzle masks.
 ////////////////////////////////////////////////////////////////////
-PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LPoint3),
-__getattr__, const string &attr_name) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LPoint3)>::
+__getattr__(const string &attr_name) const {
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
     if (*it < 'x' || *it > 'z') {
@@ -45,35 +45,43 @@ __getattr__, const string &attr_name) {
     }
   }
 
-  if (attr_name.size() == 1) {
-    return PyFloat_FromDouble(this->_v(attr_name[0] - 'x'));
+  switch (attr_name.size()) {
+    case 1:
+      return PyFloat_FromDouble(_this->_v(attr_name[0] - 'x'));
+
+    case 2: {
+      FLOATNAME(LPoint2) *vec = new FLOATNAME(LPoint2);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint2), true, false);
 
-  } else if (attr_name.size() == 2) {
-    FLOATNAME(LPoint2) *vec = new FLOATNAME(LPoint2);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint2), true, false);
+    } case 3: {
+      FLOATNAME(LPoint3) *vec = new FLOATNAME(LPoint3);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint3), true, false);
 
-  } else if (attr_name.size() == 3) {
-    FLOATNAME(LPoint3) *vec = new FLOATNAME(LPoint3);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    vec->_v(2) = this->_v(attr_name[2] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint3), true, false);
+    } case 4: {
+      FLOATNAME(LPoint4) *vec = new FLOATNAME(LPoint4);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      vec->_v(3) = _this->_v(attr_name[3] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint4), true, false);
+    }
   }
 
   return NULL;
 }
 
-int EXT_METHOD_ARGS(FLOATNAME(LVecBase3), __setattr__, PyObject*, const string&, PyObject*);
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint3::__setattr__
 //       Access: Published
 //  Description: This is used to implement write masks.
 ////////////////////////////////////////////////////////////////////
-INLINE int EXT_METHOD_ARGS(FLOATNAME(LPoint3),
-__setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
-  return CALL_EXT_METHOD(FLOATNAME(LVecBase3), __setattr__, this, self, attr_name, assign);
+INLINE_LINMATH int Extension<FLOATNAME(LPoint3)>::
+__setattr__(PyObject *self, const string &attr_name, PyObject *assign) {
+  // Upcall to LVecBase2.
+  return invoke_extension<FLOATNAME(LVecBase3)>(_this, _self).__setattr__(self, attr_name, assign);
 }
-

+ 30 - 0
panda/src/linmath/lpoint3_ext_src.h

@@ -0,0 +1,30 @@
+// Filename: lpoint3_ext_src.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LPoint3>
+// Description : This class defines the extension methods for
+//               LPoint3, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LPoint3)> : public ExtensionBase<FLOATNAME(LPoint3)> {
+public:
+  INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const;
+  INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign);
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+#include "lpoint3_ext_src.I"

+ 2 - 2
panda/src/linmath/lpoint3_src.h

@@ -31,8 +31,8 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LPoint3)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LPoint3)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z);
 
-  EXTENSION(PyObject *__getattr__(const string &attr_name) const);
-  EXTENSION(int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
+  EXTENSION(INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const);
+  EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH static const FLOATNAME(LPoint3) &zero();
   INLINE_LINMATH static const FLOATNAME(LPoint3) &unit_x();

+ 10 - 3
panda/src/linmath/lpoint4_ext.I → panda/src/linmath/lpoint4_ext.h

@@ -1,5 +1,5 @@
 // Filename: lpoint4_ext.I
-// Created by:  rdb (02Jan11)
+// Created by:  rdb (13Sep13)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,11 +12,18 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifndef LPOINT4_EXT_H
+#define LPOINT4_EXT_H
+
 #include "lpoint4.h"
+#include "extension.h"
+
+#include "lvecBase4_ext.h"
 
 #include "fltnames.h"
-#include "lpoint4_ext_src.I"
+#include "lpoint4_ext_src.h"
 
 #include "dblnames.h"
-#include "lpoint4_ext_src.I"
+#include "lpoint4_ext_src.h"
 
+#endif

+ 38 - 39
panda/src/linmath/lpoint4_ext_src.I

@@ -12,7 +12,6 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
 #ifndef CPPPARSER
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint2);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint3);
@@ -24,13 +23,13 @@ IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LPoint4);
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_CONST_METHOD_ARGS(FLOATNAME(LPoint4),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LPoint4)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "("
-      << MAYBE_ZERO(this->_v(0)) << ", "
-      << MAYBE_ZERO(this->_v(1)) << ", "
-      << MAYBE_ZERO(this->_v(2)) << ", "
-      << MAYBE_ZERO(this->_v(3)) << ")";
+      << MAYBE_ZERO(_this->_v(0)) << ", "
+      << MAYBE_ZERO(_this->_v(1)) << ", "
+      << MAYBE_ZERO(_this->_v(2)) << ", "
+      << MAYBE_ZERO(_this->_v(3)) << ")";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -38,8 +37,8 @@ python_repr, ostream &out, const string &class_name) {
 //       Access: Published
 //  Description: This is used to implement swizzle masks.
 ////////////////////////////////////////////////////////////////////
-INLINE PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LPoint4),
-__getattr__, const string &attr_name) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LPoint4)>::
+__getattr__(const string &attr_name) const {
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
     if (*it < 'w' || *it > 'z') {
@@ -47,47 +46,47 @@ __getattr__, const string &attr_name) {
     }
   }
 
-  if (attr_name.size() == 1) {
-    if (attr_name[0] == 'w') {
-      return PyFloat_FromDouble(this->_v(3));
-    } else {
-      return PyFloat_FromDouble(this->_v(attr_name[0] - 'x'));
-    }
+  switch (attr_name.size()) {
+    case 1:
+      if (attr_name[0] == 'w') {
+        return PyFloat_FromDouble(_this->_v(3));
+      } else {
+        return PyFloat_FromDouble(_this->_v(attr_name[0] - 'x'));
+      }
 
-  } else if (attr_name.size() == 2) {
-    FLOATNAME(LPoint2) *vec = new FLOATNAME(LPoint2);
-    vec->_v(0) = this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
-    vec->_v(1) = this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint2), true, false);
+    case 2: {
+      FLOATNAME(LPoint2) *vec = new FLOATNAME(LPoint2);
+      vec->_v(0) = _this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
+      vec->_v(1) = _this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint2), true, false);
 
-  } else if (attr_name.size() == 3) {
-    FLOATNAME(LPoint3) *vec = new FLOATNAME(LPoint3);
-    vec->_v(0) = this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
-    vec->_v(1) = this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
-    vec->_v(2) = this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint3), true, false);
+    } case 3: {
+      FLOATNAME(LPoint3) *vec = new FLOATNAME(LPoint3);
+      vec->_v(0) = _this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
+      vec->_v(1) = _this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
+      vec->_v(2) = _this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint3), true, false);
 
-  } else if (attr_name.size() == 4) {
-    FLOATNAME(LPoint4) *vec = new FLOATNAME(LPoint4);
-    vec->_v(0) = this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
-    vec->_v(1) = this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
-    vec->_v(2) = this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
-    vec->_v(3) = this->_v((attr_name[3] == 'w') ? 3 : attr_name[3] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint4), true, false);
+    } case 4: {
+      FLOATNAME(LPoint4) *vec = new FLOATNAME(LPoint4);
+      vec->_v(0) = _this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
+      vec->_v(1) = _this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
+      vec->_v(2) = _this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
+      vec->_v(3) = _this->_v((attr_name[3] == 'w') ? 3 : attr_name[3] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LPoint4), true, false);
+    }
   }
 
   return NULL;
 }
 
-int EXT_METHOD_ARGS(FLOATNAME(LVecBase4), __setattr__, PyObject*, const string&, PyObject*);
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint4::__setattr__
 //       Access: Published
 //  Description: This is used to implement write masks.
 ////////////////////////////////////////////////////////////////////
-INLINE int EXT_METHOD_ARGS(FLOATNAME(LPoint4),
-__setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
-  return CALL_EXT_METHOD(FLOATNAME(LVecBase4), __setattr__, this, self, attr_name, assign);
+INLINE_LINMATH int Extension<FLOATNAME(LPoint4)>::
+__setattr__(PyObject *self, const string &attr_name, PyObject *assign) {
+  // Upcall to LVecBase4.
+  return invoke_extension<FLOATNAME(LVecBase4)>(_this, _self).__setattr__(self, attr_name, assign);
 }
-

+ 30 - 0
panda/src/linmath/lpoint4_ext_src.h

@@ -0,0 +1,30 @@
+// Filename: lpoint4_ext_src.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LPoint4>
+// Description : This class defines the extension methods for
+//               LPoint4, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LPoint4)> : public ExtensionBase<FLOATNAME(LPoint4)> {
+public:
+  INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const;
+  INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign);
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+#include "lpoint4_ext_src.I"

+ 2 - 2
panda/src/linmath/lpoint4_src.h

@@ -25,8 +25,8 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LPoint4)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LPoint4)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
 
-  EXTENSION(PyObject *__getattr__(const string &attr_name) const);
-  EXTENSION(int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
+  EXTENSION(INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const);
+  EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH static const FLOATNAME(LPoint4) &zero();
   INLINE_LINMATH static const FLOATNAME(LPoint4) &unit_x();

+ 8 - 3
panda/src/linmath/lvecBase2_ext.I → panda/src/linmath/lvecBase2_ext.h

@@ -1,5 +1,5 @@
 // Filename: lvecBase2_ext.I
-// Created by:  rdb (02Jan11)
+// Created by:  rdb (13Sep13)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,11 +12,16 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifndef LVECBASE2_EXT_H
+#define LVECBASE2_EXT_H
+
 #include "lvecBase2.h"
+#include "extension.h"
 
 #include "fltnames.h"
-#include "lvecBase2_ext_src.I"
+#include "lvecBase2_ext_src.h"
 
 #include "dblnames.h"
-#include "lvecBase2_ext_src.I"
+#include "lvecBase2_ext_src.h"
 
+#endif

+ 41 - 39
panda/src/linmath/lvecBase2_ext_src.I

@@ -24,10 +24,10 @@ IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase4);
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_METHOD_ARGS(FLOATNAME(LVecBase2),
-__setitem__, int i, FLOATTYPE v) {
+INLINE_LINMATH void Extension<FLOATNAME(LVecBase2)>::
+__setitem__(int i, FLOATTYPE v) {
   nassertv(i >= 0 && i < 2);
-  this->_v(i) = v;
+  _this->_v(i) = v;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -35,11 +35,11 @@ __setitem__, int i, FLOATTYPE v) {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_CONST_METHOD_ARGS(FLOATNAME(LVecBase2),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LVecBase2)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "("
-      << MAYBE_ZERO(this->_v(0)) << ", "
-      << MAYBE_ZERO(this->_v(1)) << ")";
+      << MAYBE_ZERO(_this->_v(0)) << ", "
+      << MAYBE_ZERO(_this->_v(1)) << ")";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -48,8 +48,8 @@ python_repr, ostream &out, const string &class_name) {
 //  Description: This special Python method is implement to provide
 //               support for the pickle module.
 ////////////////////////////////////////////////////////////////////
-INLINE PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LVecBase2),
-__reduce__, PyObject *self) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase2)>::
+__reduce__(PyObject *self) const {
   // We should return at least a 2-tuple, (Class, (args)): the
   // necessary class object whose constructor we should call
   // (e.g. this), and the arguments necessary to reconstruct this
@@ -60,7 +60,7 @@ __reduce__, PyObject *self) {
   }
 
   PyObject *result = Py_BuildValue("(O(ff))", this_class,
-                                   (*this)[0], (*this)[1]);
+                                   (*_this)[0], (*_this)[1]);
   Py_DECREF(this_class);
   return result;
 }
@@ -70,8 +70,8 @@ __reduce__, PyObject *self) {
 //       Access: Published
 //  Description: This is used to implement swizzle masks.
 ////////////////////////////////////////////////////////////////////
-PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LVecBase2),
-__getattr__, const string &attr_name) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase2)>::
+__getattr__(const string &attr_name) const {
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
     if (*it != 'x' && *it != 'y') {
@@ -79,29 +79,31 @@ __getattr__, const string &attr_name) {
     }
   }
 
-  if (attr_name.size() == 1) {
-    return PyFloat_FromDouble(this->_v(attr_name[0] - 'x'));
-
-  } else if (attr_name.size() == 2) {
-    FLOATNAME(LVecBase2) *vec = new FLOATNAME(LVecBase2);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase2), true, false);
-
-  } else if (attr_name.size() == 3) {
-    FLOATNAME(LVecBase3) *vec = new FLOATNAME(LVecBase3);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    vec->_v(2) = this->_v(attr_name[2] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase3), true, false);
-
-  } else if (attr_name.size() == 4) {
-    FLOATNAME(LVecBase4) *vec = new FLOATNAME(LVecBase4);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    vec->_v(2) = this->_v(attr_name[2] - 'x');
-    vec->_v(3) = this->_v(attr_name[3] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase4), true, false);
+  switch (attr_name.size()) {
+    case 1:
+      return PyFloat_FromDouble(_this->_v(attr_name[0] - 'x'));
+
+    case 2: {
+      FLOATNAME(LVecBase2) *vec = new FLOATNAME(LVecBase2);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase2), true, false);
+
+    } case 3: {
+      FLOATNAME(LVecBase3) *vec = new FLOATNAME(LVecBase3);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase3), true, false);
+
+    } case 4: {
+      FLOATNAME(LVecBase4) *vec = new FLOATNAME(LVecBase4);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      vec->_v(3) = _this->_v(attr_name[3] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase4), true, false);
+    }
   }
 
   return NULL;
@@ -112,8 +114,8 @@ __getattr__, const string &attr_name) {
 //       Access: Published
 //  Description: This is used to implement write masks.
 ////////////////////////////////////////////////////////////////////
-int EXT_METHOD_ARGS(FLOATNAME(LVecBase2),
-__setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
+INLINE_LINMATH int Extension<FLOATNAME(LVecBase2)>::
+__setattr__(PyObject *self, const string &attr_name, PyObject *assign) {
 #ifndef NDEBUG
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
@@ -156,7 +158,7 @@ __setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
       double value = PyFloat_AS_DOUBLE(fl);
       Py_DECREF(fl);
 
-      this->_v(attr_name[i] - 'x') = value;
+      _this->_v(attr_name[i] - 'x') = value;
     }
 
     Py_DECREF(fast);
@@ -181,7 +183,7 @@ __setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
     // Loop through the components in the attribute name,
     // and assign the floating-point value to every one of them.
     for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
-      this->_v((*it) - 'x') = value;
+      _this->_v((*it) - 'x') = value;
     }
   }
 

+ 32 - 0
panda/src/linmath/lvecBase2_ext_src.h

@@ -0,0 +1,32 @@
+// Filename: lvecBase2_ext_src.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LVecBase2>
+// Description : This class defines the extension methods for
+//               LVecBase2, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LVecBase2)> : public ExtensionBase<FLOATNAME(LVecBase2)> {
+public:
+  INLINE_LINMATH PyObject *__reduce__(PyObject *self) const;
+  INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const;
+  INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign);
+  INLINE_LINMATH void __setitem__(int i, FLOATTYPE v);
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+#include "lvecBase2_ext_src.I"

+ 3 - 3
panda/src/linmath/lvecBase2_src.h

@@ -37,9 +37,9 @@ PUBLISHED:
 
   INLINE_LINMATH ~FLOATNAME(LVecBase2)();
 
-  EXTENSION(PyObject *__reduce__(PyObject *self) const);
-  EXTENSION(PyObject *__getattr__(const string &attr_name) const);
-  EXTENSION(int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
+  EXTENSION(INLINE_LINMATH PyObject *__reduce__(PyObject *self) const);
+  EXTENSION(INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const);
+  EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH FLOATTYPE operator [](int i) const;
   INLINE_LINMATH FLOATTYPE &operator [](int i);

+ 8 - 3
panda/src/linmath/lvecBase3_ext.I → panda/src/linmath/lvecBase3_ext.h

@@ -1,5 +1,5 @@
 // Filename: lvecBase3_ext.I
-// Created by:  rdb (02Jan11)
+// Created by:  rdb (13Sep13)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,11 +12,16 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifndef LVECBASE3_EXT_H
+#define LVECBASE3_EXT_H
+
 #include "lvecBase3.h"
+#include "extension.h"
 
 #include "fltnames.h"
-#include "lvecBase3_ext_src.I"
+#include "lvecBase3_ext_src.h"
 
 #include "dblnames.h"
-#include "lvecBase3_ext_src.I"
+#include "lvecBase3_ext_src.h"
 
+#endif

+ 42 - 40
panda/src/linmath/lvecBase3_ext_src.I

@@ -24,10 +24,10 @@ IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase4);
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_METHOD_ARGS(FLOATNAME(LVecBase3),
-__setitem__, int i, FLOATTYPE v) {
+INLINE_LINMATH void Extension<FLOATNAME(LVecBase3)>::
+__setitem__(int i, FLOATTYPE v) {
   nassertv(i >= 0 && i < 3);
-  this->_v(i) = v;
+  _this->_v(i) = v;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -35,12 +35,12 @@ __setitem__, int i, FLOATTYPE v) {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_CONST_METHOD_ARGS(FLOATNAME(LVecBase3),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LVecBase3)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "("
-      << MAYBE_ZERO(this->_v(0)) << ", "
-      << MAYBE_ZERO(this->_v(1)) << ", "
-      << MAYBE_ZERO(this->_v(2)) << ")";
+      << MAYBE_ZERO(_this->_v(0)) << ", "
+      << MAYBE_ZERO(_this->_v(1)) << ", "
+      << MAYBE_ZERO(_this->_v(2)) << ")";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -49,8 +49,8 @@ python_repr, ostream &out, const string &class_name) {
 //  Description: This special Python method is implement to provide
 //               support for the pickle module.
 ////////////////////////////////////////////////////////////////////
-INLINE PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LVecBase3),
-__reduce__, PyObject *self) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase3)>::
+__reduce__(PyObject *self) const {
   // We should return at least a 2-tuple, (Class, (args)): the
   // necessary class object whose constructor we should call
   // (e.g. this), and the arguments necessary to reconstruct this
@@ -61,7 +61,7 @@ __reduce__, PyObject *self) {
   }
 
   PyObject *result = Py_BuildValue("(O(fff))", this_class,
-                                   (*this)[0], (*this)[1], (*this)[2]);
+                                   (*_this)[0], (*_this)[1], (*_this)[2]);
   Py_DECREF(this_class);
   return result;
 }
@@ -71,8 +71,8 @@ __reduce__, PyObject *self) {
 //       Access: Published
 //  Description: This is used to implement swizzle masks.
 ////////////////////////////////////////////////////////////////////
-PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LVecBase3),
-__getattr__, const string &attr_name) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase3)>::
+__getattr__(const string &attr_name) const {
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
     if (*it < 'x' || *it > 'z') {
@@ -80,29 +80,31 @@ __getattr__, const string &attr_name) {
     }
   }
 
-  if (attr_name.size() == 1) {
-    return PyFloat_FromDouble(this->_v(attr_name[0] - 'x'));
-
-  } else if (attr_name.size() == 2) {
-    FLOATNAME(LVecBase2) *vec = new FLOATNAME(LVecBase2);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase2), true, false);
-
-  } else if (attr_name.size() == 3) {
-    FLOATNAME(LVecBase3) *vec = new FLOATNAME(LVecBase3);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    vec->_v(2) = this->_v(attr_name[2] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase3), true, false);
-
-  } else if (attr_name.size() == 4) {
-    FLOATNAME(LVecBase4) *vec = new FLOATNAME(LVecBase4);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    vec->_v(2) = this->_v(attr_name[2] - 'x');
-    vec->_v(3) = this->_v(attr_name[3] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase4), true, false);
+  switch (attr_name.size()) {
+    case 1:
+      return PyFloat_FromDouble(_this->_v(attr_name[0] - 'x'));
+
+    case 2: {
+      FLOATNAME(LVecBase2) *vec = new FLOATNAME(LVecBase2);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase2), true, false);
+
+    } case 3: {
+      FLOATNAME(LVecBase3) *vec = new FLOATNAME(LVecBase3);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase3), true, false);
+
+    } case 4: {
+      FLOATNAME(LVecBase4) *vec = new FLOATNAME(LVecBase4);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      vec->_v(3) = _this->_v(attr_name[3] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase4), true, false);
+    }
   }
 
   return NULL;
@@ -113,8 +115,8 @@ __getattr__, const string &attr_name) {
 //       Access: Published
 //  Description: This is used to implement write masks.
 ////////////////////////////////////////////////////////////////////
-int EXT_METHOD_ARGS(FLOATNAME(LVecBase3),
-__setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
+INLINE_LINMATH int Extension<FLOATNAME(LVecBase3)>::
+__setattr__(PyObject *self, const string &attr_name, PyObject *assign) {
 #ifndef NDEBUG
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
@@ -157,7 +159,7 @@ __setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
       double value = PyFloat_AS_DOUBLE(fl);
       Py_DECREF(fl);
 
-      this->_v(attr_name[i] - 'x') = value;
+      _this->_v(attr_name[i] - 'x') = value;
     }
 
     Py_DECREF(fast);
@@ -182,7 +184,7 @@ __setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
     // Loop through the components in the attribute name,
     // and assign the floating-point value to every one of them.
     for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
-      this->_v((*it) - 'x') = value;
+      _this->_v((*it) - 'x') = value;
     }
   }
 

+ 32 - 0
panda/src/linmath/lvecBase3_ext_src.h

@@ -0,0 +1,32 @@
+// Filename: lvecBase3_ext_src.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LVecBase3>
+// Description : This class defines the extension methods for
+//               LVecBase3, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LVecBase3)> : public ExtensionBase<FLOATNAME(LVecBase3)> {
+public:
+  INLINE_LINMATH PyObject *__reduce__(PyObject *self) const;
+  INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const;
+  INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign);
+  INLINE_LINMATH void __setitem__(int i, FLOATTYPE v);
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+#include "lvecBase3_ext_src.I"

+ 3 - 3
panda/src/linmath/lvecBase3_src.h

@@ -38,9 +38,9 @@ PUBLISHED:
 
   INLINE_LINMATH ~FLOATNAME(LVecBase3)();
 
-  EXTENSION(PyObject *__reduce__(PyObject *self) const);
-  EXTENSION(PyObject *__getattr__(const string &attr_name) const);
-  EXTENSION(int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
+  EXTENSION(INLINE_LINMATH PyObject *__reduce__(PyObject *self) const);
+  EXTENSION(INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const);
+  EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH FLOATTYPE operator [](int i) const;
   INLINE_LINMATH FLOATTYPE &operator [](int i);

+ 8 - 3
panda/src/linmath/lvecBase4_ext.I → panda/src/linmath/lvecBase4_ext.h

@@ -1,5 +1,5 @@
 // Filename: lvecBase4_ext.I
-// Created by:  rdb (02Jan11)
+// Created by:  rdb (13Sep13)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,11 +12,16 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifndef LVECBASE4_EXT_H
+#define LVECBASE4_EXT_H
+
 #include "lvecBase4.h"
+#include "extension.h"
 
 #include "fltnames.h"
-#include "lvecBase4_ext_src.I"
+#include "lvecBase4_ext_src.h"
 
 #include "dblnames.h"
-#include "lvecBase4_ext_src.I"
+#include "lvecBase4_ext_src.h"
 
+#endif

+ 49 - 48
panda/src/linmath/lvecBase4_ext_src.I

@@ -24,10 +24,10 @@ IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase4);
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_METHOD_ARGS(FLOATNAME(LVecBase4),
-__setitem__, int i, FLOATTYPE v) {
+INLINE_LINMATH void Extension<FLOATNAME(LVecBase4)>::
+__setitem__(int i, FLOATTYPE v) {
   nassertv(i >= 0 && i < 4);
-  this->_v(i) = v;
+  _this->_v(i) = v;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -35,13 +35,13 @@ __setitem__, int i, FLOATTYPE v) {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_CONST_METHOD_ARGS(FLOATNAME(LVecBase4),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LVecBase4)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "("
-      << MAYBE_ZERO(this->_v(0)) << ", "
-      << MAYBE_ZERO(this->_v(1)) << ", "
-      << MAYBE_ZERO(this->_v(2)) << ", "
-      << MAYBE_ZERO(this->_v(3)) << ")";
+      << MAYBE_ZERO(_this->_v(0)) << ", "
+      << MAYBE_ZERO(_this->_v(1)) << ", "
+      << MAYBE_ZERO(_this->_v(2)) << ", "
+      << MAYBE_ZERO(_this->_v(3)) << ")";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -50,8 +50,8 @@ python_repr, ostream &out, const string &class_name) {
 //  Description: This special Python method is implement to provide
 //               support for the pickle module.
 ////////////////////////////////////////////////////////////////////
-INLINE PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LVecBase4),
-__reduce__, PyObject *self) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase4)>::
+__reduce__(PyObject *self) const {
   // We should return at least a 2-tuple, (Class, (args)): the
   // necessary class object whose constructor we should call
   // (e.g. this), and the arguments necessary to reconstruct this
@@ -62,7 +62,7 @@ __reduce__, PyObject *self) {
   }
 
   PyObject *result = Py_BuildValue("(O(ffff))", this_class,
-                                   (*this)[0], (*this)[1], (*this)[2], (*this)[3]);
+                                   (*_this)[0], (*_this)[1], (*_this)[2], (*_this)[3]);
   Py_DECREF(this_class);
   return result;
 }
@@ -72,8 +72,8 @@ __reduce__, PyObject *self) {
 //       Access: Published
 //  Description: This is used to implement swizzle masks.
 ////////////////////////////////////////////////////////////////////
-PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LVecBase4),
-__getattr__, const string &attr_name) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase4)>::
+__getattr__(const string &attr_name) const {
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
     if (*it < 'w' || *it > 'z') {
@@ -81,33 +81,35 @@ __getattr__, const string &attr_name) {
     }
   }
 
-  if (attr_name.size() == 1) {
-    if (attr_name[0] == 'w') {
-      return PyFloat_FromDouble(this->_v(3));
-    } else {
-      return PyFloat_FromDouble(this->_v(attr_name[0] - 'x'));
-    }
+  switch (attr_name.size()) {
+    case 1:
+      if (attr_name[0] == 'w') {
+        return PyFloat_FromDouble(_this->_v(3));
+      } else {
+        return PyFloat_FromDouble(_this->_v(attr_name[0] - 'x'));
+      }
 
-  } else if (attr_name.size() == 2) {
-    FLOATNAME(LVecBase2) *vec = new FLOATNAME(LVecBase2);
-    vec->_v(0) = this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
-    vec->_v(1) = this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase2), true, false);
-
-  } else if (attr_name.size() == 3) {
-    FLOATNAME(LVecBase3) *vec = new FLOATNAME(LVecBase3);
-    vec->_v(0) = this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
-    vec->_v(1) = this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
-    vec->_v(2) = this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase3), true, false);
-
-  } else if (attr_name.size() == 4) {
-    FLOATNAME(LVecBase4) *vec = new FLOATNAME(LVecBase4);
-    vec->_v(0) = this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
-    vec->_v(1) = this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
-    vec->_v(2) = this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
-    vec->_v(3) = this->_v((attr_name[3] == 'w') ? 3 : attr_name[3] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase4), true, false);
+    case 2: {
+      FLOATNAME(LVecBase2) *vec = new FLOATNAME(LVecBase2);
+      vec->_v(0) = _this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
+      vec->_v(1) = _this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase2), true, false);
+
+    } case 3: {
+      FLOATNAME(LVecBase3) *vec = new FLOATNAME(LVecBase3);
+      vec->_v(0) = _this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
+      vec->_v(1) = _this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
+      vec->_v(2) = _this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase3), true, false);
+
+    } case 4: {
+      FLOATNAME(LVecBase4) *vec = new FLOATNAME(LVecBase4);
+      vec->_v(0) = _this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
+      vec->_v(1) = _this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
+      vec->_v(2) = _this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
+      vec->_v(3) = _this->_v((attr_name[3] == 'w') ? 3 : attr_name[3] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVecBase4), true, false);
+    }
   }
 
   return NULL;
@@ -118,8 +120,8 @@ __getattr__, const string &attr_name) {
 //       Access: Published
 //  Description: This is used to implement write masks.
 ////////////////////////////////////////////////////////////////////
-int EXT_METHOD_ARGS(FLOATNAME(LVecBase4),
-__setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
+INLINE_LINMATH int Extension<FLOATNAME(LVecBase4)>::
+__setattr__(PyObject *self, const string &attr_name, PyObject *assign) {
 #ifndef NDEBUG
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
@@ -162,7 +164,7 @@ __setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
       double value = PyFloat_AS_DOUBLE(fl);
       Py_DECREF(fl);
 
-      this->_v((attr_name[i] == 'w') ? 3 : attr_name[i] - 'x') = value;
+      _this->_v((attr_name[i] == 'w') ? 3 : attr_name[i] - 'x') = value;
     }
 
     Py_DECREF(fast);
@@ -187,21 +189,20 @@ __setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
     // Loop through the components in the attribute name,
     // and assign the floating-point value to every one of them.
     for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
-      this->_v(((*it) == 'w') ? 3 : (*it) - 'x') = value;
+      _this->_v(((*it) == 'w') ? 3 : (*it) - 'x') = value;
     }
   }
 
   return 0;
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: UnalignedLVecBase4::__setitem__
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_METHOD_ARGS(FLOATNAME(UnalignedLVecBase4),
-__setitem__, int i, FLOATTYPE v) {
+INLINE_LINMATH void Extension<FLOATNAME(UnalignedLVecBase4)>::
+__setitem__(int i, FLOATTYPE v) {
   nassertv(i >= 0 && i < 4);
-  this->_v(i) = v;
+  _this->_v(i) = v;
 }

+ 44 - 0
panda/src/linmath/lvecBase4_ext_src.h

@@ -0,0 +1,44 @@
+// Filename: lvecBase4_ext_src.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LVecBase4>
+// Description : This class defines the extension methods for
+//               LVecBase4, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LVecBase4)> : public ExtensionBase<FLOATNAME(LVecBase4)> {
+public:
+  INLINE_LINMATH PyObject *__reduce__(PyObject *self) const;
+  INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const;
+  INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign);
+  INLINE_LINMATH void __setitem__(int i, FLOATTYPE v);
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<UnalignedLVecBase4>
+// Description : This class defines the extension methods for
+//               UnalignedLVecBase4, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(UnalignedLVecBase4)> : public ExtensionBase<FLOATNAME(UnalignedLVecBase4)> {
+public:
+  INLINE_LINMATH void __setitem__(int i, FLOATTYPE v);
+};
+
+#include "lvecBase4_ext_src.I"

+ 3 - 3
panda/src/linmath/lvecBase4_src.h

@@ -44,9 +44,9 @@ PUBLISHED:
 
   INLINE_LINMATH ~FLOATNAME(LVecBase4)();
 
-  EXTENSION(PyObject *__reduce__(PyObject *self) const);
-  EXTENSION(PyObject *__getattr__(const string &attr_name) const);
-  EXTENSION(int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
+  EXTENSION(INLINE_LINMATH PyObject *__reduce__(PyObject *self) const);
+  EXTENSION(INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const);
+  EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH FLOATTYPE operator [](int i) const;
   INLINE_LINMATH FLOATTYPE &operator [](int i);

+ 10 - 3
panda/src/linmath/lvector2_ext.I → panda/src/linmath/lvector2_ext.h

@@ -1,5 +1,5 @@
 // Filename: lvector2_ext.I
-// Created by:  rdb (02Jan11)
+// Created by:  rdb (13Sep13)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,11 +12,18 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifndef LVECTOR2_EXT_H
+#define LVECTOR2_EXT_H
+
 #include "lvector2.h"
+#include "extension.h"
+
+#include "lvecBase2_ext.h"
 
 #include "fltnames.h"
-#include "lvector2_ext_src.I"
+#include "lvector2_ext_src.h"
 
 #include "dblnames.h"
-#include "lvector2_ext_src.I"
+#include "lvector2_ext_src.h"
 
+#endif

+ 32 - 32
panda/src/linmath/lvector2_ext_src.I

@@ -12,7 +12,6 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
 #ifndef CPPPARSER
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector2);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector3);
@@ -24,11 +23,11 @@ IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector4);
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_CONST_METHOD_ARGS(FLOATNAME(LVector2),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LVector2)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "("
-      << MAYBE_ZERO(this->_v(0)) << ", "
-      << MAYBE_ZERO(this->_v(1)) << ")";
+      << MAYBE_ZERO(_this->_v(0)) << ", "
+      << MAYBE_ZERO(_this->_v(1)) << ")";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -36,8 +35,8 @@ python_repr, ostream &out, const string &class_name) {
 //       Access: Published
 //  Description: This is used to implement swizzle masks.
 ////////////////////////////////////////////////////////////////////
-INLINE PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LVector2),
-__getattr__, const string &attr_name) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVector2)>::
+__getattr__(const string &attr_name) const {
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
     if (*it != 'x' && *it != 'y') {
@@ -45,42 +44,43 @@ __getattr__, const string &attr_name) {
     }
   }
 
-  if (attr_name.size() == 1) {
-    return PyFloat_FromDouble(this->_v(attr_name[0] - 'x'));
+  switch (attr_name.size()) {
+    case 1:
+      return PyFloat_FromDouble(_this->_v(attr_name[0] - 'x'));
 
-  } else if (attr_name.size() == 2) {
-    FLOATNAME(LVector2) *vec = new FLOATNAME(LVector2);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector2), true, false);
+    case 2: {
+      FLOATNAME(LVector2) *vec = new FLOATNAME(LVector2);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector2), true, false);
 
-  } else if (attr_name.size() == 3) {
-    FLOATNAME(LVector3) *vec = new FLOATNAME(LVector3);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    vec->_v(2) = this->_v(attr_name[2] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector3), true, false);
+    } case 3: {
+      FLOATNAME(LVector3) *vec = new FLOATNAME(LVector3);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector3), true, false);
 
-  } else if (attr_name.size() == 4) {
-    FLOATNAME(LVector4) *vec = new FLOATNAME(LVector4);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    vec->_v(2) = this->_v(attr_name[2] - 'x');
-    vec->_v(3) = this->_v(attr_name[3] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector4), true, false);
+    } case 4: {
+      FLOATNAME(LVector4) *vec = new FLOATNAME(LVector4);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      vec->_v(3) = _this->_v(attr_name[3] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector4), true, false);
+    }
   }
 
   return NULL;
 }
 
-int EXT_METHOD_ARGS(FLOATNAME(LVecBase2), __setattr__, PyObject*, const string&, PyObject*);
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector2::__setattr__
 //       Access: Published
 //  Description: This is used to implement write masks.
 ////////////////////////////////////////////////////////////////////
-INLINE int EXT_METHOD_ARGS(FLOATNAME(LVector2),
-__setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
-  return CALL_EXT_METHOD(FLOATNAME(LVecBase2), __setattr__, this, self, attr_name, assign);
+INLINE_LINMATH int Extension<FLOATNAME(LVector2)>::
+__setattr__(PyObject *self, const string &attr_name, PyObject *assign) {
+  // Upcall to LVecBase2.
+  return invoke_extension<FLOATNAME(LVecBase2)>(_this, _self).__setattr__(self, attr_name, assign);
 }

+ 30 - 0
panda/src/linmath/lvector2_ext_src.h

@@ -0,0 +1,30 @@
+// Filename: lvector2_ext_src.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LVector2>
+// Description : This class defines the extension methods for
+//               LVector2, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LVector2)> : public ExtensionBase<FLOATNAME(LVector2)> {
+public:
+  INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const;
+  INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign);
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+#include "lvector2_ext_src.I"

+ 2 - 2
panda/src/linmath/lvector2_src.h

@@ -25,8 +25,8 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LVector2)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector2)(FLOATTYPE x, FLOATTYPE y);
 
-  EXTENSION(PyObject *__getattr__(const string &attr_name) const);
-  EXTENSION(int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
+  EXTENSION(INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const);
+  EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH static const FLOATNAME(LVector2) &zero();
   INLINE_LINMATH static const FLOATNAME(LVector2) &unit_x();

+ 10 - 3
panda/src/linmath/lvector3_ext.I → panda/src/linmath/lvector3_ext.h

@@ -1,5 +1,5 @@
 // Filename: lvector3_ext.I
-// Created by:  rdb (02Jan11)
+// Created by:  rdb (13Sep13)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,11 +12,18 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifndef LVECTOR3_EXT_H
+#define LVECTOR3_EXT_H
+
 #include "lvector3.h"
+#include "extension.h"
+
+#include "lvecBase3_ext.h"
 
 #include "fltnames.h"
-#include "lvector3_ext_src.I"
+#include "lvector3_ext_src.h"
 
 #include "dblnames.h"
-#include "lvector3_ext_src.I"
+#include "lvector3_ext_src.h"
 
+#endif

+ 33 - 34
panda/src/linmath/lvector3_ext_src.I

@@ -12,7 +12,6 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
 #ifndef CPPPARSER
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector2);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector3);
@@ -24,12 +23,12 @@ IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector4);
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_CONST_METHOD_ARGS(FLOATNAME(LVector3),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LVector3)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "("
-      << MAYBE_ZERO(this->_v(0)) << ", "
-      << MAYBE_ZERO(this->_v(1)) << ", "
-      << MAYBE_ZERO(this->_v(2)) << ")";
+      << MAYBE_ZERO(_this->_v(0)) << ", "
+      << MAYBE_ZERO(_this->_v(1)) << ", "
+      << MAYBE_ZERO(_this->_v(2)) << ")";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -37,8 +36,8 @@ python_repr, ostream &out, const string &class_name) {
 //       Access: Published
 //  Description: This is used to implement swizzle masks.
 ////////////////////////////////////////////////////////////////////
-INLINE PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LVector3),
-__getattr__, const string &attr_name) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVector3)>::
+__getattr__(const string &attr_name) const {
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
     if (*it < 'x' || *it > 'z') {
@@ -46,43 +45,43 @@ __getattr__, const string &attr_name) {
     }
   }
 
-  if (attr_name.size() == 1) {
-    return PyFloat_FromDouble(this->_v(attr_name[0] - 'x'));
+  switch (attr_name.size()) {
+    case 1:
+      return PyFloat_FromDouble(_this->_v(attr_name[0] - 'x'));
 
-  } else if (attr_name.size() == 2) {
-    FLOATNAME(LVector2) *vec = new FLOATNAME(LVector2);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector2), true, false);
+    case 2: {
+      FLOATNAME(LVector2) *vec = new FLOATNAME(LVector2);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector2), true, false);
 
-  } else if (attr_name.size() == 3) {
-    FLOATNAME(LVector3) *vec = new FLOATNAME(LVector3);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    vec->_v(2) = this->_v(attr_name[2] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector3), true, false);
+    } case 3: {
+      FLOATNAME(LVector3) *vec = new FLOATNAME(LVector3);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector3), true, false);
 
-  } else if (attr_name.size() == 4) {
-    FLOATNAME(LVector4) *vec = new FLOATNAME(LVector4);
-    vec->_v(0) = this->_v(attr_name[0] - 'x');
-    vec->_v(1) = this->_v(attr_name[1] - 'x');
-    vec->_v(2) = this->_v(attr_name[2] - 'x');
-    vec->_v(3) = this->_v(attr_name[3] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector4), true, false);
+    } case 4: {
+      FLOATNAME(LVector4) *vec = new FLOATNAME(LVector4);
+      vec->_v(0) = _this->_v(attr_name[0] - 'x');
+      vec->_v(1) = _this->_v(attr_name[1] - 'x');
+      vec->_v(2) = _this->_v(attr_name[2] - 'x');
+      vec->_v(3) = _this->_v(attr_name[3] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector4), true, false);
+    }
   }
 
   return NULL;
 }
 
-int EXT_METHOD_ARGS(FLOATNAME(LVecBase3), __setattr__, PyObject*, const string&, PyObject*);
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector3::__setattr__
 //       Access: Published
 //  Description: This is used to implement write masks.
 ////////////////////////////////////////////////////////////////////
-INLINE int EXT_METHOD_ARGS(FLOATNAME(LVector3),
-__setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
-  return CALL_EXT_METHOD(FLOATNAME(LVecBase3), __setattr__, this, self, attr_name, assign);
+INLINE_LINMATH int Extension<FLOATNAME(LVector3)>::
+__setattr__(PyObject *self, const string &attr_name, PyObject *assign) {
+  // Upcall to LVecBase3.
+  return invoke_extension<FLOATNAME(LVecBase3)>(_this, _self).__setattr__(self, attr_name, assign);
 }
-

+ 30 - 0
panda/src/linmath/lvector3_ext_src.h

@@ -0,0 +1,30 @@
+// Filename: lvector3_ext_src.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LVector3>
+// Description : This class defines the extension methods for
+//               LVector3, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LVector3)> : public ExtensionBase<FLOATNAME(LVector3)> {
+public:
+  INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const;
+  INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign);
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+#include "lvector3_ext_src.I"

+ 2 - 2
panda/src/linmath/lvector3_src.h

@@ -31,8 +31,8 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LVector3)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector3)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z);
 
-  EXTENSION(PyObject *__getattr__(const string &attr_name) const);
-  EXTENSION(int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
+  EXTENSION(INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const);
+  EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH static const FLOATNAME(LVector3) &zero();
   INLINE_LINMATH static const FLOATNAME(LVector3) &unit_x();

+ 10 - 3
panda/src/linmath/lvector4_ext.I → panda/src/linmath/lvector4_ext.h

@@ -1,5 +1,5 @@
 // Filename: lvector4_ext.I
-// Created by:  rdb (02Jan11)
+// Created by:  rdb (13Sep13)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,11 +12,18 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifndef LVECTOR4_EXT_H
+#define LVECTOR4_EXT_H
+
 #include "lvector4.h"
+#include "extension.h"
+
+#include "lvecBase4_ext.h"
 
 #include "fltnames.h"
-#include "lvector4_ext_src.I"
+#include "lvector4_ext_src.h"
 
 #include "dblnames.h"
-#include "lvector4_ext_src.I"
+#include "lvector4_ext_src.h"
 
+#endif

+ 38 - 39
panda/src/linmath/lvector4_ext_src.I

@@ -12,7 +12,6 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
 #ifndef CPPPARSER
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector2);
 IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector3);
@@ -24,13 +23,13 @@ IMPORT_THIS struct Dtool_PyTypedObject FLOATNAME(Dtool_LVector4);
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE void EXT_CONST_METHOD_ARGS(FLOATNAME(LVector4),
-python_repr, ostream &out, const string &class_name) {
+INLINE_LINMATH void Extension<FLOATNAME(LVector4)>::
+python_repr(ostream &out, const string &class_name) const {
   out << class_name << "("
-      << MAYBE_ZERO(this->_v(0)) << ", "
-      << MAYBE_ZERO(this->_v(1)) << ", "
-      << MAYBE_ZERO(this->_v(2)) << ", "
-      << MAYBE_ZERO(this->_v(3)) << ")";
+      << MAYBE_ZERO(_this->_v(0)) << ", "
+      << MAYBE_ZERO(_this->_v(1)) << ", "
+      << MAYBE_ZERO(_this->_v(2)) << ", "
+      << MAYBE_ZERO(_this->_v(3)) << ")";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -38,8 +37,8 @@ python_repr, ostream &out, const string &class_name) {
 //       Access: Published
 //  Description: This is used to implement swizzle masks.
 ////////////////////////////////////////////////////////////////////
-INLINE PyObject *EXT_CONST_METHOD_ARGS(FLOATNAME(LVector4),
-__getattr__, const string &attr_name) {
+INLINE_LINMATH PyObject *Extension<FLOATNAME(LVector4)>::
+__getattr__(const string &attr_name) const {
   // Validate the attribute name.
   for (string::const_iterator it = attr_name.begin(); it < attr_name.end(); it++) {
     if (*it < 'w' || *it > 'z') {
@@ -47,47 +46,47 @@ __getattr__, const string &attr_name) {
     }
   }
 
-  if (attr_name.size() == 1) {
-    if (attr_name[0] == 'w') {
-      return PyFloat_FromDouble(this->_v(3));
-    } else {
-      return PyFloat_FromDouble(this->_v(attr_name[0] - 'x'));
-    }
+  switch (attr_name.size()) {
+    case 1:
+      if (attr_name[0] == 'w') {
+        return PyFloat_FromDouble(_this->_v(3));
+      } else {
+        return PyFloat_FromDouble(_this->_v(attr_name[0] - 'x'));
+      }
 
-  } else if (attr_name.size() == 2) {
-    FLOATNAME(LVector2) *vec = new FLOATNAME(LVector2);
-    vec->_v(0) = this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
-    vec->_v(1) = this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector2), true, false);
+    case 2: {
+      FLOATNAME(LVector2) *vec = new FLOATNAME(LVector2);
+      vec->_v(0) = _this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
+      vec->_v(1) = _this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector2), true, false);
 
-  } else if (attr_name.size() == 3) {
-    FLOATNAME(LVector3) *vec = new FLOATNAME(LVector3);
-    vec->_v(0) = this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
-    vec->_v(1) = this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
-    vec->_v(2) = this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector3), true, false);
+    } case 3: {
+      FLOATNAME(LVector3) *vec = new FLOATNAME(LVector3);
+      vec->_v(0) = _this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
+      vec->_v(1) = _this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
+      vec->_v(2) = _this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector3), true, false);
 
-  } else if (attr_name.size() == 4) {
-    FLOATNAME(LVector4) *vec = new FLOATNAME(LVector4);
-    vec->_v(0) = this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
-    vec->_v(1) = this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
-    vec->_v(2) = this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
-    vec->_v(3) = this->_v((attr_name[3] == 'w') ? 3 : attr_name[3] - 'x');
-    return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector4), true, false);
+    } case 4: {
+      FLOATNAME(LVector4) *vec = new FLOATNAME(LVector4);
+      vec->_v(0) = _this->_v((attr_name[0] == 'w') ? 3 : attr_name[0] - 'x');
+      vec->_v(1) = _this->_v((attr_name[1] == 'w') ? 3 : attr_name[1] - 'x');
+      vec->_v(2) = _this->_v((attr_name[2] == 'w') ? 3 : attr_name[2] - 'x');
+      vec->_v(3) = _this->_v((attr_name[3] == 'w') ? 3 : attr_name[3] - 'x');
+      return DTool_CreatePyInstance((void *)vec, FLOATNAME(Dtool_LVector4), true, false);
+    }
   }
 
   return NULL;
 }
 
-int EXT_METHOD_ARGS(FLOATNAME(LVecBase4), __setattr__, PyObject*, const string&, PyObject*);
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector4::__setattr__
 //       Access: Published
 //  Description: This is used to implement write masks.
 ////////////////////////////////////////////////////////////////////
-INLINE int EXT_METHOD_ARGS(FLOATNAME(LVector4),
-__setattr__, PyObject *self, const string &attr_name, PyObject *assign) {
-  return CALL_EXT_METHOD(FLOATNAME(LVecBase4), __setattr__, this, self, attr_name, assign);
+INLINE_LINMATH int Extension<FLOATNAME(LVector4)>::
+__setattr__(PyObject *self, const string &attr_name, PyObject *assign) {
+  // Upcall to LVecBase4.
+  return invoke_extension<FLOATNAME(LVecBase4)>(_this, _self).__setattr__(self, attr_name, assign);
 }
-

+ 30 - 0
panda/src/linmath/lvector4_ext_src.h

@@ -0,0 +1,30 @@
+// Filename: lvector4_ext_src.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<LVector4>
+// Description : This class defines the extension methods for
+//               LVector4, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<FLOATNAME(LVector4)> : public ExtensionBase<FLOATNAME(LVector4)> {
+public:
+  INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const;
+  INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign);
+  INLINE_LINMATH void python_repr(ostream &out, const string &class_name) const;
+};
+
+#include "lvector4_ext_src.I"

+ 2 - 2
panda/src/linmath/lvector4_src.h

@@ -25,8 +25,8 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LVector4)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector4)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
 
-  EXTENSION(PyObject *__getattr__(const string &attr_name) const);
-  EXTENSION(int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
+  EXTENSION(INLINE_LINMATH PyObject *__getattr__(const string &attr_name) const);
+  EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH static const FLOATNAME(LVector4) &zero();
   INLINE_LINMATH static const FLOATNAME(LVector4) &unit_x();

+ 5 - 5
panda/src/rocket/rocketRegion_ext.I → panda/src/rocket/rocketRegion_ext.cxx

@@ -1,4 +1,4 @@
-// Filename: rocketRegion_ext.I
+// Filename: rocketRegion_ext.cxx
 // Created by:  rdb (06Dec11)
 //
 ////////////////////////////////////////////////////////////////////
@@ -13,9 +13,9 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "rocketRegion.h"
+#include "extension.h"
 
 #ifndef CPPPARSER
-#undef this
 #define HAVE_LONG_LONG 1
 #include <Rocket/Core/Context.h>
 #include <Rocket/Core/Python/Utilities.h>
@@ -31,10 +31,10 @@
 //               It's best to call this method just once and store
 //               the context in a Python variable, to avoid overhead.
 ////////////////////////////////////////////////////////////////////
-PyObject* EXT_CONST_METHOD(RocketRegion,
-get_context) {
+PyObject* Extension<RocketRegion>::
+get_context() const {
   try {
-    Rocket::Core::Context* context = _ext_this->get_context();
+    Rocket::Core::Context* context = _this->get_context();
     python::object py_context = Rocket::Core::Python::Utilities::MakeObject(context);
 
     // Make sure the context won't be destroyed before both the Python

+ 39 - 0
panda/src/rocket/rocketRegion_ext.h

@@ -0,0 +1,39 @@
+// Filename: rocketRegion_ext.h
+// Created by:  rdb (13Sep13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef ROCKETREGION_EXT_H
+#define ROCKETREGION_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "geomVertexArrayData.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<RocketRegion>
+// Description : This class defines the extension methods for
+//               GeomVertexArrayData, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<RocketRegion> : public ExtensionBase<RocketRegion> {
+public:
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // ROCKETREGION_EXT_H

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