Browse Source

Fix various issues with Python 3 support, fix samples to work with Python 3

rdb 10 years ago
parent
commit
de0b0dd879

+ 8 - 9
direct/src/filter/CommonFilters.py

@@ -16,11 +16,10 @@ clunky approach.  - Josh
 """
 
 from FilterManager import FilterManager
-from pandac.PandaModules import Point3, Vec3, Vec4, Point2
-from pandac.PandaModules import NodePath, PandaNode
-from pandac.PandaModules import Filename
-from pandac.PandaModules import AuxBitplaneAttrib
-from pandac.PandaModules import RenderState, Texture, Shader, ATSNone
+from panda3d.core import LVecBase4, LPoint2
+from panda3d.core import Filename
+from panda3d.core import AuxBitplaneAttrib
+from panda3d.core import RenderState, Texture, Shader, ATSNone
 import sys,os
 
 CARTOON_BODY="""
@@ -348,13 +347,13 @@ class CommonFilters:
         if (changed == "CartoonInk") or fullrebuild:
             if ("CartoonInk" in configuration):
                 c = configuration["CartoonInk"]
-                self.finalQuad.setShaderInput("cartoonseparation", Vec4(c.separation, 0, c.separation, 0))
+                self.finalQuad.setShaderInput("cartoonseparation", LVecBase4(c.separation, 0, c.separation, 0))
                 self.finalQuad.setShaderInput("cartooncolor", c.color)
 
         if (changed == "BlurSharpen") or fullrebuild:
             if ("BlurSharpen" in configuration):
                 blurval = configuration["BlurSharpen"]
-                self.finalQuad.setShaderInput("blurval", Vec4(blurval, blurval, blurval, blurval))
+                self.finalQuad.setShaderInput("blurval", LVecBase4(blurval, blurval, blurval, blurval))
 
         if (changed == "Bloom") or fullrebuild:
             if ("Bloom" in configuration):
@@ -386,9 +385,9 @@ class CommonFilters:
 
         if "VolumetricLighting" in self.configuration:
             caster = self.configuration["VolumetricLighting"].caster
-            casterpos = Point2()
+            casterpos = LPoint2()
             self.manager.camera.node().getLens().project(caster.getPos(self.manager.camera), casterpos)
-            self.finalQuad.setShaderInput("casterpos", Vec4(casterpos.getX() * 0.5 + 0.5, (casterpos.getY() * 0.5 + 0.5), 0, 0))
+            self.finalQuad.setShaderInput("casterpos", LVecBase4(casterpos.getX() * 0.5 + 0.5, (casterpos.getY() * 0.5 + 0.5), 0, 0))
         if task != None:
             return task.cont
 

+ 20 - 21
direct/src/filter/FilterManager.py

@@ -14,16 +14,15 @@ Still need to implement:
 
 """
 
-from pandac.PandaModules import Point3, Vec3, Vec4
-from pandac.PandaModules import NodePath, PandaNode
-from pandac.PandaModules import RenderState, Texture, Shader
-from pandac.PandaModules import CardMaker
-from pandac.PandaModules import TextureStage
-from pandac.PandaModules import GraphicsPipe, GraphicsOutput
-from pandac.PandaModules import WindowProperties, FrameBufferProperties
-from pandac.PandaModules import Camera, DisplayRegion
-from pandac.PandaModules import OrthographicLens
-from pandac.PandaModules import AuxBitplaneAttrib
+from panda3d.core import NodePath, PandaNode
+from panda3d.core import RenderState, Texture, Shader
+from panda3d.core import CardMaker
+from panda3d.core import TextureStage
+from panda3d.core import GraphicsPipe, GraphicsOutput
+from panda3d.core import WindowProperties, FrameBufferProperties
+from panda3d.core import Camera, DisplayRegion
+from panda3d.core import OrthographicLens
+from panda3d.core import AuxBitplaneAttrib
 from direct.directnotify.DirectNotifyGlobal import *
 from direct.showbase.DirectObject import DirectObject
 
@@ -111,16 +110,16 @@ class FilterManager(DirectObject):
 
         winx = self.forcex
         winy = self.forcey
-        if (winx == 0): winx = self.win.getXSize()
-        if (winy == 0): winy = self.win.getYSize()
+        if winx == 0: winx = self.win.getXSize()
+        if winy == 0: winy = self.win.getYSize()
 
-        if (div != 1):
-            winx = ((winx+align-1) / align) * align
-            winy = ((winy+align-1) / align) * align
-            winx = winx / div
-            winy = winy / div
+        if div != 1:
+            winx = ((winx+align-1) // align) * align
+            winy = ((winy+align-1) // align) * align
+            winx = winx // div
+            winy = winy // div
 
-        if (mul != 1):
+        if mul != 1:
             winx = winx * mul
             winy = winy * mul
 
@@ -198,7 +197,7 @@ class FilterManager(DirectObject):
         quad.setDepthTest(0)
         quad.setDepthWrite(0)
         quad.setTexture(colortex)
-        quad.setColor(Vec4(1,0.5,0.5,1))
+        quad.setColor(1, 0.5, 0.5, 1)
 
         cs = NodePath("dummy")
         cs.setState(self.camstate)
@@ -221,7 +220,7 @@ class FilterManager(DirectObject):
         self.setStackedClears(buffer, self.rclears, self.wclears)
         if (auxtex0):
             buffer.setClearActive(GraphicsOutput.RTPAuxRgba0, 1)
-            buffer.setClearValue(GraphicsOutput.RTPAuxRgba0, Vec4(0.5, 0.5, 1.0, 0.0))
+            buffer.setClearValue(GraphicsOutput.RTPAuxRgba0, (0.5, 0.5, 1.0, 0.0))
         if (auxtex1):
             buffer.setClearActive(GraphicsOutput.RTPAuxRgba1, 1)
         self.region.disableClears()
@@ -262,7 +261,7 @@ class FilterManager(DirectObject):
         quad = NodePath(cm.generate())
         quad.setDepthTest(0)
         quad.setDepthWrite(0)
-        quad.setColor(Vec4(1,0.5,0.5,1))
+        quad.setColor(1, 0.5, 0.5, 1)
 
         quadcamnode = Camera("filter-quad-cam")
         lens = OrthographicLens()

+ 50 - 50
direct/src/showbase/ShowBase.py

@@ -11,8 +11,8 @@ from panda3d.core import *
 from panda3d.direct import get_config_showbase, throw_new_frame, init_app_for_gui
 
 # This needs to be available early for DirectGUI imports
-import __builtin__
-__builtin__.config = get_config_showbase()
+import __builtin__ as builtins
+builtins.config = get_config_showbase()
 
 from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify
 from MessengerGlobal import messenger
@@ -44,17 +44,17 @@ if __debug__:
 import OnScreenDebug
 import AppRunnerGlobal
 
-__builtin__.FADE_SORT_INDEX = 1000
-__builtin__.NO_FADE_SORT_INDEX = 2000
+builtins.FADE_SORT_INDEX = 1000
+builtins.NO_FADE_SORT_INDEX = 2000
 
 def legacyRun():
-    __builtin__.base.notify.warning("run() is deprecated, use base.run() instead")
-    __builtin__.base.run()
+    builtins.base.notify.warning("run() is deprecated, use base.run() instead")
+    builtins.base.run()
 
 @atexit.register
 def exitfunc():
-    if getattr(__builtin__, 'base', None) is not None:
-        __builtin__.base.destroy()
+    if getattr(builtins, 'base', None) is not None:
+        builtins.base.destroy()
 
 # Now ShowBase is a DirectObject.  We need this so ShowBase can hang
 # hooks on messages, particularly on window-event.  This doesn't
@@ -65,7 +65,7 @@ class ShowBase(DirectObject.DirectObject):
 
     def __init__(self, fStartDirect = True, windowType = None):
         self.__dev__ = config.GetBool('want-dev', __debug__)
-        __builtin__.__dev__ = self.__dev__
+        builtins.__dev__ = self.__dev__
 
         logStackDump = (config.GetBool('log-stack-dump', False) or
                         config.GetBool('client-log-stack-dump', False))
@@ -327,8 +327,8 @@ class ShowBase(DirectObject.DirectObject):
             # assigned to a single CPU
             autoAffinity = self.config.GetBool('auto-single-cpu-affinity', 0)
             affinity = None
-            if autoAffinity and ('clientIndex' in __builtin__.__dict__):
-                affinity = abs(int(__builtin__.clientIndex))
+            if autoAffinity and ('clientIndex' in builtins.__dict__):
+                affinity = abs(int(builtins.clientIndex))
             else:
                 affinity = self.config.GetInt('client-cpu-affinity', -1)
             if (affinity in (None, -1)) and autoAffinity:
@@ -338,44 +338,44 @@ class ShowBase(DirectObject.DirectObject):
                 TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 32))
 
         # Make sure we're not making more than one ShowBase.
-        if 'base' in __builtin__.__dict__:
+        if 'base' in builtins.__dict__:
             raise StandardError, "Attempt to spawn multiple ShowBase instances!"
 
         # DO NOT ADD TO THIS LIST.  We're trying to phase out the use of
         # built-in variables by ShowBase.  Use a Global module if necessary.
-        __builtin__.base = self
-        __builtin__.render2d = self.render2d
-        __builtin__.aspect2d = self.aspect2d
-        __builtin__.pixel2d = self.pixel2d
-        __builtin__.render = self.render
-        __builtin__.hidden = self.hidden
-        __builtin__.camera = self.camera
-        __builtin__.loader = self.loader
-        __builtin__.taskMgr = self.taskMgr
-        __builtin__.jobMgr = self.jobMgr
-        __builtin__.eventMgr = self.eventMgr
-        __builtin__.messenger = self.messenger
-        __builtin__.bboard = self.bboard
+        builtins.base = self
+        builtins.render2d = self.render2d
+        builtins.aspect2d = self.aspect2d
+        builtins.pixel2d = self.pixel2d
+        builtins.render = self.render
+        builtins.hidden = self.hidden
+        builtins.camera = self.camera
+        builtins.loader = self.loader
+        builtins.taskMgr = self.taskMgr
+        builtins.jobMgr = self.jobMgr
+        builtins.eventMgr = self.eventMgr
+        builtins.messenger = self.messenger
+        builtins.bboard = self.bboard
         # Config needs to be defined before ShowBase is constructed
-        #__builtin__.config = self.config
-        __builtin__.run = legacyRun
-        __builtin__.ostream = Notify.out()
-        __builtin__.directNotify = directNotify
-        __builtin__.giveNotify = giveNotify
-        __builtin__.globalClock = globalClock
-        __builtin__.vfs = vfs
-        __builtin__.cpMgr = ConfigPageManager.getGlobalPtr()
-        __builtin__.cvMgr = ConfigVariableManager.getGlobalPtr()
-        __builtin__.pandaSystem = PandaSystem.getGlobalPtr()
-        __builtin__.wantUberdog = base.config.GetBool('want-uberdog', 1)
+        #builtins.config = self.config
+        builtins.run = legacyRun
+        builtins.ostream = Notify.out()
+        builtins.directNotify = directNotify
+        builtins.giveNotify = giveNotify
+        builtins.globalClock = globalClock
+        builtins.vfs = vfs
+        builtins.cpMgr = ConfigPageManager.getGlobalPtr()
+        builtins.cvMgr = ConfigVariableManager.getGlobalPtr()
+        builtins.pandaSystem = PandaSystem.getGlobalPtr()
+        builtins.wantUberdog = base.config.GetBool('want-uberdog', 1)
         if __debug__:
-            __builtin__.deltaProfiler = DeltaProfiler.DeltaProfiler("ShowBase")
-        __builtin__.onScreenDebug = OnScreenDebug.OnScreenDebug()
+            builtins.deltaProfiler = DeltaProfiler.DeltaProfiler("ShowBase")
+        builtins.onScreenDebug = OnScreenDebug.OnScreenDebug()
 
         if self.wantRender2dp:
-            __builtin__.render2dp = self.render2dp
-            __builtin__.aspect2dp = self.aspect2dp
-            __builtin__.pixel2dp = self.pixel2dp
+            builtins.render2dp = self.render2dp
+            builtins.aspect2dp = self.aspect2dp
+            builtins.pixel2dp = self.pixel2dp
 
         if __dev__:
             ShowBase.notify.debug('__dev__ == %s' % __dev__)
@@ -497,10 +497,10 @@ class ShowBase(DirectObject.DirectObject):
             cb()
 
         # Remove the built-in base reference
-        if getattr(__builtin__, 'base', None) is self:
-            del __builtin__.base
-            del __builtin__.loader
-            del __builtin__.taskMgr
+        if getattr(builtins, 'base', None) is self:
+            del builtins.base
+            del builtins.loader
+            del builtins.taskMgr
 
         # [gjeon] restore sticky key settings
         if self.config.GetBool('disable-sticky-keys', 0):
@@ -1308,7 +1308,7 @@ class ShowBase(DirectObject.DirectObject):
             # camera.
             self.camera = self.render.attachNewNode(ModelNode('camera'))
             self.camera.node().setPreserveTransform(ModelNode.PTLocal)
-            __builtin__.camera = self.camera
+            builtins.camera = self.camera
 
             self.mouse2cam.node().setNode(self.camera.node())
 
@@ -2814,7 +2814,7 @@ class ShowBase(DirectObject.DirectObject):
             # wx is now the main loop, not us any more.
             self.run = self.wxRun
             self.taskMgr.run = self.wxRun
-            __builtin__.run = self.wxRun
+            builtins.run = self.wxRun
             if self.appRunner:
                 self.appRunner.run = self.wxRun
 
@@ -2876,7 +2876,7 @@ class ShowBase(DirectObject.DirectObject):
 
         # Create a new Tk root.
         self.tkRoot = Pmw.initialise()
-        __builtin__.tkroot = self.tkRoot
+        builtins.tkroot = self.tkRoot
 
         init_app_for_gui()
 
@@ -2893,7 +2893,7 @@ class ShowBase(DirectObject.DirectObject):
             # wx is now the main loop, not us any more.
             self.run = self.tkRun
             self.taskMgr.run = self.tkRun
-            __builtin__.run = self.tkRun
+            builtins.run = self.tkRun
             if self.appRunner:
                 self.appRunner.run = self.tkRun
 
@@ -2938,7 +2938,7 @@ class ShowBase(DirectObject.DirectObject):
             from direct.directtools import DirectSession
             base.direct.enable()
         else:
-            __builtin__.direct = self.direct = None
+            builtins.direct = self.direct = None
 
     def getRepository(self):
         return None

+ 27 - 3
dtool/src/interrogate/functionRemap.cxx

@@ -743,7 +743,8 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     _args_type = InterfaceMaker::AT_varargs;
   }
 
-  if (_type == T_normal) {
+  switch (_type) {
+  case T_normal:
     if (fname == "operator []" || fname == "__getitem__") {
       _flags |= F_getitem;
       if (_has_this && _parameters.size() == 2) {
@@ -824,6 +825,13 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
         _flags |= F_coerce_constructor;
       }
 
+    } else if (fname == "operator /") {
+      if (_has_this && _parameters.size() == 2 &&
+          TypeManager::is_float(_parameters[1]._remap->get_new_type())) {
+        // This division operator takes a single float argument.
+        _flags |= F_divide_float;
+      }
+
     } else if (fname == "operator ()" || fname == "__call__") {
       // Call operators always take keyword arguments.
       _args_type = InterfaceMaker::AT_keyword_args;
@@ -840,8 +848,19 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
         _args_type = InterfaceMaker::AT_keyword_args;
       }
     }
+    break;
 
-  } else if (_type == T_item_assignment_operator) {
+  case T_assignment_method:
+    if (fname == "operator /=") {
+      if (_has_this && _parameters.size() == 2 &&
+          TypeManager::is_float(_parameters[1]._remap->get_new_type())) {
+        // This division operator takes a single float argument.
+        _flags |= F_divide_float;
+      }
+    }
+    break;
+
+  case T_item_assignment_operator:
     // The concept of "item assignment operator" doesn't really exist in C++,
     // but it does in scripting languages, and this allows us to wrap cases
     // where the C++ getitem returns an assignable reference.
@@ -853,8 +872,9 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
       }
     }
     _args_type = InterfaceMaker::AT_varargs;
+    break;
 
-  } else if (_type == T_constructor) {
+  case T_constructor:
     if (!_has_this && _parameters.size() == 1 &&
         TypeManager::unwrap(_parameters[0]._remap->get_orig_type()) ==
         TypeManager::unwrap(_return_type->get_orig_type())) {
@@ -870,6 +890,10 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
 
     // Constructors always take varargs and keyword args.
     _args_type = InterfaceMaker::AT_keyword_args;
+    break;
+
+  default:
+    break;
   }
 
   return true;

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

@@ -98,6 +98,7 @@ public:
     F_releasebuffer      = 0x1000,
     F_compare_to         = 0x2000,
     F_coerce_constructor = 0x4000,
+    F_divide_float       = 0x8000,
   };
 
   typedef vector<Parameter> Parameters;

+ 87 - 40
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -311,7 +311,6 @@ get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap,
     return false;
   }
 
-  def._func = func;
   def._answer_location = string();
   def._wrapper_type = WT_none;
   def._min_version = 0;
@@ -344,8 +343,6 @@ get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap,
   }
 
   if (method_name == "operator /") {
-    // Note: nb_divide does not exist in Python 3.  We will probably need some
-    // smart mechanism for dispatching to either floor_divide or true_divide.
     def._answer_location = "nb_divide";
     def._wrapper_type = WT_binary_operator;
     return true;
@@ -620,7 +617,6 @@ write_function_slot(ostream &out, int indent_level, const SlottedFunctions &slot
   }
 
   const SlottedFunctionDef &def = rfi->second;
-  Function *func = def._func;
 
   // Add an #ifdef if there is a specific version requirement on this function.
   if (def._min_version > 0) {
@@ -1469,6 +1465,29 @@ write_module_class(ostream &out, Object *obj) {
           slots[key] = slotted_def;
           slots[key]._remaps.insert(remap);
         }
+
+        // Python 3 doesn't support nb_divide.  It has nb_true_divide and also
+        // nb_floor_divide, but they have different semantics than in C++.  Ugh.
+        // Make special slots to store the nb_divide members that take a float.
+        // We'll use this to build up nb_true_divide, so that we can still properly
+        // divide float vector types.
+        if (remap->_flags & FunctionRemap::F_divide_float) {
+          string true_key;
+          if (key == "nb_inplace_divide") {
+            true_key = "nb_inplace_true_divide";
+          } else {
+            true_key = "nb_true_divide";
+          }
+          if (slots.count(true_key) == 0) {
+            SlottedFunctionDef def;
+            def._answer_location = true_key;
+            def._wrapper_type = slotted_def._wrapper_type;
+            def._min_version = 0x03000000;
+            def._wrapper_name = func->_name + "_" + true_key;
+            slots[true_key] = def;
+          }
+          slots[true_key]._remaps.insert(remap);
+        }
       } else {
         has_nonslotted = true;
       }
@@ -1565,12 +1584,21 @@ write_module_class(ostream &out, Object *obj) {
   }
 
   {
-    Function *getitem_func;
-
     SlottedFunctions::iterator rfi;
     for (rfi = slots.begin(); rfi != slots.end(); rfi++) {
       const SlottedFunctionDef &def = rfi->second;
-      Function *func = def._func;
+
+      // This is just for reporting.  There might be remaps from multiple
+      // functions with different names mapped to the same slot.
+      string fname;
+      if (def._remaps.size() > 0) {
+        const FunctionRemap *first_remap = *def._remaps.begin();
+        fname = first_remap->_cppfunc->get_simple_name();
+      }
+
+      if (def._min_version > 0) {
+        out << "#if PY_VERSION_HEX >= 0x" << hex << def._min_version << dec << "\n";
+      }
 
       switch (rfi->second._wrapper_type) {
       case WT_no_params:
@@ -1578,8 +1606,8 @@ write_module_class(ostream &out, Object *obj) {
         // PyObject *func(PyObject *self)
         {
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static PyObject *" << def._wrapper_name << "(PyObject *self) {\n";
           out << "  " << cClassName  << " *local_this = NULL;\n";
@@ -1613,8 +1641,8 @@ write_module_class(ostream &out, Object *obj) {
             return_flags |= RF_pyobject;
           }
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static PyObject *" << def._wrapper_name << "(PyObject *self, PyObject *arg) {\n";
           out << "  " << cClassName << " *local_this = NULL;\n";
@@ -1656,8 +1684,8 @@ write_module_class(ostream &out, Object *obj) {
         // int func(PyObject *self, PyObject *one, PyObject *two = NULL)
         {
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static int " << def._wrapper_name << "(PyObject *self, PyObject *arg, PyObject *arg2) {\n";
           out << "  " << cClassName  << " *local_this = NULL;\n";
@@ -1735,8 +1763,8 @@ write_module_class(ostream &out, Object *obj) {
         // If one wants to override this completely, one should define __getattribute__ instead.
         {
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static PyObject *" << def._wrapper_name << "(PyObject *self, PyObject *arg) {\n";
           out << "  PyObject *res = PyObject_GenericGetAttr(self, arg);\n";
@@ -1768,8 +1796,8 @@ write_module_class(ostream &out, Object *obj) {
         // PyObject *func(PyObject *self, Py_ssize_t index)
         {
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static PyObject *" << def._wrapper_name << "(PyObject *self, Py_ssize_t index) {\n";
           out << "  " << cClassName  << " *local_this = NULL;\n";
@@ -1797,8 +1825,6 @@ write_module_class(ostream &out, Object *obj) {
           out << "  }\n";
           out << "  return NULL;\n";
           out << "}\n\n";
-
-          getitem_func = func;
         }
         break;
 
@@ -1806,8 +1832,8 @@ write_module_class(ostream &out, Object *obj) {
         // int_t func(PyObject *self, Py_ssize_t index, PyObject *value)
         {
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static int " << def._wrapper_name << "(PyObject *self, Py_ssize_t index, PyObject *arg) {\n";
           out << "  " << cClassName  << " *local_this = NULL;\n";
@@ -1860,8 +1886,8 @@ write_module_class(ostream &out, Object *obj) {
         // Py_ssize_t func(PyObject *self)
         {
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static Py_ssize_t " << def._wrapper_name << "(PyObject *self) {\n";
           out << "  " << cClassName  << " *local_this = NULL;\n";
@@ -1870,7 +1896,7 @@ write_module_class(ostream &out, Object *obj) {
           out << "  }\n\n";
 
           // This is a cheap cheat around all of the overhead of calling the wrapper function.
-          out << "  return (Py_ssize_t) local_this->" << func->_ifunc.get_name() << "();\n";
+          out << "  return (Py_ssize_t) local_this->" << fname << "();\n";
           out << "}\n\n";
         }
         break;
@@ -1879,8 +1905,8 @@ write_module_class(ostream &out, Object *obj) {
         // int func(PyObject *self, PyObject *one, PyObject *two)
         {
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static int " << def._wrapper_name << "(PyObject *self, PyObject *arg, PyObject *arg2) {\n";
           out << "  " << cClassName  << " *local_this = NULL;\n";
@@ -1930,8 +1956,8 @@ write_module_class(ostream &out, Object *obj) {
         // int func(PyObject *self)
         {
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static int " << def._wrapper_name << "(PyObject *self) {\n";
           out << "  " << cClassName  << " *local_this = NULL;\n";
@@ -1956,8 +1982,8 @@ write_module_class(ostream &out, Object *obj) {
           has_local_getbuffer = true;
 
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static int " << def._wrapper_name << "(PyObject *self, Py_buffer *buffer, int flags) {\n";
           out << "  " << cClassName << " *local_this = NULL;\n";
@@ -2023,8 +2049,8 @@ write_module_class(ostream &out, Object *obj) {
         // Same story as __getbuffer__ above.
         {
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static void " << def._wrapper_name << "(PyObject *self, Py_buffer *buffer) {\n";
           out << "  " << cClassName << " *local_this = NULL;\n";
@@ -2105,8 +2131,8 @@ write_module_class(ostream &out, Object *obj) {
             return_flags |= RF_pyobject;
           }
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static PyObject *" << def._wrapper_name << "(PyObject *self, PyObject *arg, PyObject *arg2) {\n";
           out << "  " << cClassName << " *local_this = NULL;\n";
@@ -2162,8 +2188,8 @@ write_module_class(ostream &out, Object *obj) {
         // This is a low-level function.  Overloads are not supported.
         {
           out << "//////////////////\n";
-          out << "//  A wrapper function to satisfy Python's internal calling conventions.\n";
-          out << "//     " << ClassName << " ..." << rfi->second._answer_location << " = " << methodNameFromCppName(func, export_class_name, false) << "\n";
+          out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
+          out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
           out << "//////////////////\n";
           out << "static int " << def._wrapper_name << "(PyObject *self, visitproc visit, void *arg) {\n";
           out << "  " << cClassName << " *local_this = NULL;\n";
@@ -2174,7 +2200,7 @@ write_module_class(ostream &out, Object *obj) {
           out << "  }\n\n";
 
           // Find the remap.  There should be only one.
-          FunctionRemap *remap = func->_remaps.front();
+          FunctionRemap *remap = *def._remaps.begin();
 
           vector_string params(1);
           if (remap->_flags & FunctionRemap::F_explicit_self) {
@@ -2191,10 +2217,17 @@ write_module_class(ostream &out, Object *obj) {
       case WT_none:
         // Nothing special about the wrapper function: just write it normally.
         string fname = "static PyObject *" + def._wrapper_name + "(PyObject *self, PyObject *args, PyObject *kwds)\n";
+
+        vector<FunctionRemap *> remaps;
+        remaps.insert(remaps.end(), def._remaps.begin(), def._remaps.end());
         string expected_params;
-        write_function_for_name(out, obj, func->_remaps, fname, expected_params, true, AT_keyword_args, RF_pyobject | RF_err_null);
+        write_function_for_name(out, obj, remaps, fname, expected_params, true, AT_keyword_args, RF_pyobject | RF_err_null);
         break;
       }
+
+      if (def._min_version > 0) {
+        out << "#endif  // PY_VERSION_HEX >= 0x" << hex << def._min_version << dec << "\n";
+      }
     }
 
     string get_key = HasAGetKeyFunction(obj->_itype);
@@ -2352,7 +2385,13 @@ write_module_class(ostream &out, Object *obj) {
     if (compare_to_func != NULL) {
       out << "#if PY_MAJOR_VERSION >= 3\n";
       out << "  // All is not lost; we still have the compare_to function to fall back onto.\n";
-      out << "  PyObject *result = " << compare_to_func->_name << "(self, arg);\n";
+      if (compare_to_func->_args_type == AT_single_arg) {
+        out << "  PyObject *result = " << compare_to_func->_name << "(self, arg);\n";
+      } else {
+        out << "  PyObject *args = PyTuple_Pack(1, arg);\n";
+        out << "  PyObject *result = " << compare_to_func->_name << "(self, args);\n";
+        out << "  Py_DECREF(args);\n";
+      }
       out << "  if (result != NULL) {\n";
       out << "    if (PyLong_Check(result)) {;\n";
       out << "      long cmpval = PyLong_AS_LONG(result);\n";
@@ -2466,7 +2505,9 @@ write_module_class(ostream &out, Object *obj) {
   write_function_slot(out, 2, slots, "nb_and");
   write_function_slot(out, 2, slots, "nb_xor");
   write_function_slot(out, 2, slots, "nb_or");
+  out << "#if PY_MAJOR_VERSION < 3\n";
   write_function_slot(out, 2, slots, "nb_coerce");
+  out << "#endif\n";
   write_function_slot(out, 2, slots, "nb_int");
   out << "  0, // nb_long\n"; // removed in Python 3
   write_function_slot(out, 2, slots, "nb_float");
@@ -2637,7 +2678,7 @@ write_module_class(ostream &out, Object *obj) {
 
   // long tp_flags;
   if (has_local_getbuffer) {
-    out << "#if PY_VERSION_HEX >= 0x02060000\n";
+    out << "#if PY_VERSION_HEX >= 0x02060000 && PY_VERSION_HEX < 0x03000000\n";
     out << "    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_NEWBUFFER" << gcflag << ",\n";
     out << "#else\n";
     out << "    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES" << gcflag << ",\n";
@@ -2991,7 +3032,9 @@ write_function_for_top(ostream &out, InterfaceMaker::Object *obj, InterfaceMaker
 
     SlottedFunctionDef slotted_def;
     if (!get_slotted_function_def(obj, func, remap, slotted_def)) {
+      // It has a non-slotted remap, so we should write it.
       has_remaps = true;
+      break;
     }
   }
 
@@ -4567,7 +4610,11 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       only_pyobjects = false;
 
     } else if (TypeManager::is_wchar(type)) {
+      indent(out, indent_level) << "#if PY_VERSION_HEX >= 0x03020000\n";
+      indent(out, indent_level) << "PyObject *" << param_name << ";\n";
+      indent(out, indent_level) << "#else\n";
       indent(out, indent_level) << "PyUnicodeObject *" << param_name << ";\n";
+      indent(out, indent_level) << "#endif\n";
       format_specifiers += "U";
       parameter_list += ", &" + param_name;
 

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

@@ -112,7 +112,6 @@ private:
     string _answer_location;
     WrapperType _wrapper_type;
     int _min_version;
-    Function *_func;
     string _wrapper_name;
     set<FunctionRemap*> _remaps;
   };

+ 2 - 0
makepanda/makepandacore.py

@@ -2275,6 +2275,8 @@ def SetupBuildEnvironment(compiler):
         handle = subprocess.Popen(cmd, stdout=null, stderr=subprocess.PIPE, shell=True)
         scanning = False
         for line in handle.communicate()[1].splitlines():
+            line = line.decode('utf-8', 'replace')
+
             # Start looking at a line that says:  #include "..." search starts here
             if not scanning:
                 if line.startswith('#include'):

+ 3 - 3
samples/asteroids/main.py

@@ -180,9 +180,9 @@ class AsteroidsDemo(ShowBase):
             # ... 20) and chooses a value from it. Since the player starts at 0
             # and this list doesn't contain anything from -4 to 4, it won't be
             # close to the player.
-            asteroid.setX(choice(range(-SCREEN_X, -5) + range(5, SCREEN_X)))
-            # Same thing for Y, but from -15 to 15
-            asteroid.setZ(choice(range(-SCREEN_Y, -5) + range(5, SCREEN_Y)))
+            asteroid.setX(choice(tuple(range(-SCREEN_X, -5)) + tuple(range(5, SCREEN_X))))
+            # Same thing for Y
+            asteroid.setZ(choice(tuple(range(-SCREEN_Y, -5)) + tuple(range(5, SCREEN_Y))))
 
             # Heading is a random angle in radians
             heading = random() * 2 * pi

+ 2 - 2
samples/chessboard/main.py

@@ -39,12 +39,12 @@ def PointAtZ(z, point, vec):
 
 # A handy little function for getting the proper position for a given square1
 def SquarePos(i):
-    return LPoint3((i % 8) - 3.5, int(i / 8) - 3.5, 0)
+    return LPoint3((i % 8) - 3.5, int(i // 8) - 3.5, 0)
 
 # Helper function for determining wheter a square should be white or black
 # The modulo operations (%) generate the every-other pattern of a chess-board
 def SquareColor(i):
-    if (i + ((i / 8) % 2)) % 2:
+    if (i + ((i // 8) % 2)) % 2:
         return BLACK
     else:
         return WHITE

+ 1 - 1
samples/culling/occluder_culling.py

@@ -102,7 +102,7 @@ class Game(ShowBase):
         self.models = []
         box_model = self.loader.loadModel('box')
 
-        for dummy in xrange(0, 500):
+        for dummy in range(0, 500):
             pos = LPoint3((random.random() - 0.5) * 9,
                          (random.random() - 0.5) * 9,
                          random.random() * 8)

+ 1 - 1
samples/culling/portal_culling.py

@@ -108,7 +108,7 @@ class Game(ShowBase):
 
         # Randomly spawn some models to test the portals
         self.models = []
-        for dummy in xrange(0, 500):
+        for dummy in range(0, 500):
             pos = LPoint3((random.random() - 0.5) * 6,
                          (random.random() - 0.5) * 6,
                          random.random() * 7)

+ 4 - 4
samples/solar-system/step6_controllable_system.py

@@ -117,7 +117,7 @@ class World(DirectObject):
         # When the mouse is clicked, if the simulation is running pause all the
         # planets and sun, otherwise resume it
         if self.simRunning:
-            print "Pausing Simulation"
+            print("Pausing Simulation")
             # changing the text to reflect the change from "RUNNING" to
             # "PAUSED"
             self.mouse1EventText.setText(
@@ -146,7 +146,7 @@ class World(DirectObject):
                                   self.orbit_period_mars, self.mkeyEventText)
         else:
             #"The simulation is paused, so resume it
-            print "Resuming Simulation"
+            print("Resuming Simulation")
             self.mouse1EventText.setText(
                 "Mouse Button 1: Toggle entire Solar System [RUNNING]")
             # the not operator does the reverse of the previous code
@@ -179,10 +179,10 @@ class World(DirectObject):
     # Text is the OnscreenText object that needs to be updated
     def togglePlanet(self, planet, day, orbit=None, text=None):
         if day.isPlaying():
-            print "Pausing " + planet
+            print("Pausing " + planet)
             state = " [PAUSED]"
         else:
-            print "Resuming " + planet
+            print("Resuming " + planet)
             state = " [RUNNING]"
 
         # Update the onscreen text if it is given as an argument