Browse Source

Merge remote-tracking branch 'origin/master' into deploy-ng

Mitchell Stokes 7 years ago
parent
commit
49c47164ff
100 changed files with 3245 additions and 1480 deletions
  1. 1 1
      .travis.yml
  2. 1 1
      contrib/src/sceneeditor/MetadataPanel.py
  3. 37 29
      contrib/src/sceneeditor/SideWindow.py
  4. 3 4
      contrib/src/sceneeditor/collisionWindow.py
  5. 186 180
      contrib/src/sceneeditor/controllerWindow.py
  6. 50 48
      contrib/src/sceneeditor/dataHolder.py
  7. 2 2
      contrib/src/sceneeditor/duplicateWindow.py
  8. 32 25
      contrib/src/sceneeditor/lightingPanel.py
  9. 4 5
      contrib/src/sceneeditor/propertyWindow.py
  10. 6 8
      contrib/src/sceneeditor/quad.py
  11. 48 37
      contrib/src/sceneeditor/sceneEditor.py
  12. 9 5
      contrib/src/sceneeditor/seAnimPanel.py
  13. 9 5
      contrib/src/sceneeditor/seBlendAnimPanel.py
  14. 10 11
      contrib/src/sceneeditor/seCameraControl.py
  15. 8 2
      contrib/src/sceneeditor/seColorEntry.py
  16. 18 18
      contrib/src/sceneeditor/seFileSaver.py
  17. 1 3
      contrib/src/sceneeditor/seForceGroup.py
  18. 8 8
      contrib/src/sceneeditor/seGeometry.py
  19. 10 11
      contrib/src/sceneeditor/seLights.py
  20. 1 1
      contrib/src/sceneeditor/seManipulation.py
  21. 153 146
      contrib/src/sceneeditor/seMopathRecorder.py
  22. 4 4
      contrib/src/sceneeditor/seParticleEffect.py
  23. 29 22
      contrib/src/sceneeditor/seParticlePanel.py
  24. 5 25
      contrib/src/sceneeditor/seParticles.py
  25. 34 27
      contrib/src/sceneeditor/sePlacer.py
  26. 16 9
      contrib/src/sceneeditor/seSceneGraphExplorer.py
  27. 20 11
      contrib/src/sceneeditor/seSelection.py
  28. 9 6
      contrib/src/sceneeditor/seSession.py
  29. 15 9
      contrib/src/sceneeditor/seTree.py
  30. 17 1
      direct/src/interval/MetaInterval.py
  31. 2 2
      direct/src/interval/cMetaInterval.cxx
  32. 20 12
      direct/src/showbase/Transitions.py
  33. 2 2
      direct/src/stdpy/threading.py
  34. 2 1
      direct/src/tkpanels/ParticlePanel.py
  35. 224 222
      dtool/src/cppparser/cppBison.cxx.prebuilt
  36. 2 2
      dtool/src/cppparser/cppBison.h.prebuilt
  37. 27 5
      dtool/src/cppparser/cppBison.yxx
  38. 4 0
      dtool/src/dtoolbase/dtoolbase_cc.h
  39. 7 0
      dtool/src/parser-inc/time.h
  40. 1 1
      dtool/src/parser-inc/ws2tcpip.h
  41. 18 19
      dtool/src/pystub/pystub.cxx
  42. 3 0
      makepanda/makepanda.py
  43. 0 4
      makepanda/makepanda.vcproj
  44. 2 1
      makepanda/makepandacore.py
  45. 4 1
      makepanda/makewheel.py
  46. 1 1
      panda/src/chan/partBundle.h
  47. 5 1
      panda/src/char/characterJointEffect.I
  48. 274 100
      panda/src/collide/collisionBox.cxx
  49. 9 0
      panda/src/collide/collisionBox.h
  50. 144 8
      panda/src/collide/collisionTube.cxx
  51. 10 3
      panda/src/collide/collisionTube.h
  52. 0 70
      panda/src/collide/test_collide.cxx
  53. 3 5
      panda/src/cull/cullBinBackToFront.cxx
  54. 3 5
      panda/src/cull/cullBinFixed.cxx
  55. 3 5
      panda/src/cull/cullBinFrontToBack.cxx
  56. 3 5
      panda/src/cull/cullBinStateSorted.cxx
  57. 3 5
      panda/src/cull/cullBinUnsorted.cxx
  58. 0 18
      panda/src/display/test_display.cxx
  59. 10 4
      panda/src/dxgsg9/dxGeomMunger9.cxx
  60. 6 0
      panda/src/egg/eggData.h
  61. 1 0
      panda/src/egg/eggGroupNode.h
  62. 9 6
      panda/src/egg/eggNode.h
  63. 20 0
      panda/src/express/pointerTo.h
  64. 1 0
      panda/src/express/pointerToBase.h
  65. 0 7
      panda/src/express/pointerToVoid.I
  66. 2 2
      panda/src/express/pointerToVoid.h
  67. 264 34
      panda/src/express/weakPointerTo.I
  68. 77 2
      panda/src/express/weakPointerTo.h
  69. 191 33
      panda/src/express/weakPointerToBase.I
  70. 21 1
      panda/src/express/weakPointerToBase.h
  71. 6 9
      panda/src/express/weakPointerToVoid.I
  72. 2 2
      panda/src/express/weakPointerToVoid.h
  73. 9 1
      panda/src/framework/pandaFramework.cxx
  74. 1 0
      panda/src/framework/pandaFramework.h
  75. 15 8
      panda/src/glstuff/glCgShaderContext_src.cxx
  76. 20 8
      panda/src/glstuff/glGeomMunger_src.cxx
  77. 87 15
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  78. 10 1
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  79. 99 22
      panda/src/glstuff/glShaderContext_src.cxx
  80. 631 31
      panda/src/glstuff/panda_glext.h
  81. 0 12
      panda/src/gobj/config_gobj.cxx
  82. 0 1
      panda/src/gobj/config_gobj.h
  83. 49 12
      panda/src/gobj/geom.cxx
  84. 11 3
      panda/src/gobj/geomPrimitive.I
  85. 1 0
      panda/src/gobj/geomPrimitive.h
  86. 16 10
      panda/src/gobj/lens.I
  87. 43 15
      panda/src/gobj/material.I
  88. 25 34
      panda/src/gobj/material.cxx
  89. 6 0
      panda/src/gobj/material.h
  90. 5 0
      panda/src/gobj/perspectiveLens.cxx
  91. 22 5
      panda/src/gobj/shader.cxx
  92. 10 9
      panda/src/gobj/shader.h
  93. 8 4
      panda/src/gobj/shaderBuffer.I
  94. 1 1
      panda/src/gobj/shaderBuffer.cxx
  95. 1 1
      panda/src/gobj/shaderBuffer.h
  96. 0 25
      panda/src/gobj/test_gobj.cxx
  97. 18 0
      panda/src/gobj/texture.I
  98. 1 0
      panda/src/gobj/texture.h
  99. 4 0
      panda/src/gobj/texturePeeker.cxx
  100. 20 0
      panda/src/gobj/texturePool.I

+ 1 - 1
.travis.yml

@@ -51,4 +51,4 @@ notifications:
     on_success: change
     on_success: change
     on_failure: always
     on_failure: always
     use_notice: true
     use_notice: true
-    skip_join: true
+    skip_join: false

+ 1 - 1
contrib/src/sceneeditor/MetadataPanel.py

@@ -36,7 +36,7 @@ class MetadataPanel(AppShell,Pmw.MegaWidget):
 
 
 
 
     def appInit(self):
     def appInit(self):
-        print "Metadata Panel"
+        print("Metadata Panel")
 
 
     def createInterface(self):
     def createInterface(self):
         interior = self.interior()
         interior = self.interior()

+ 37 - 29
contrib/src/sceneeditor/SideWindow.py

@@ -6,8 +6,16 @@ from direct.tkwidgets.AppShell import AppShell
 from direct.tkwidgets.VectorWidgets import ColorEntry
 from direct.tkwidgets.VectorWidgets import ColorEntry
 from direct.showbase.TkGlobal import spawnTkLoop
 from direct.showbase.TkGlobal import spawnTkLoop
 import seSceneGraphExplorer
 import seSceneGraphExplorer
-from Tkinter import Frame, IntVar, Checkbutton, Toplevel
-import Pmw, Tkinter
+
+import Pmw, sys
+
+if sys.version_info >= (3, 0):
+    from tkinter import Frame, IntVar, Checkbutton, Toplevel
+    import tkinter
+else:
+    from Tkinter import Frame, IntVar, Checkbutton, Toplevel
+    import Tkinter as tkinter
+
 
 
 class sideWindow(AppShell):
 class sideWindow(AppShell):
     #################################################################
     #################################################################
@@ -65,7 +73,7 @@ class sideWindow(AppShell):
         self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
         self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
 
 
     def appInit(self):
     def appInit(self):
-        print '----SideWindow is Initialized!!'
+        print('----SideWindow is Initialized!!')
 
 
     def createInterface(self):
     def createInterface(self):
         # The interior of the toplevel panel
         # The interior of the toplevel panel
@@ -73,7 +81,7 @@ class sideWindow(AppShell):
         mainFrame = Frame(interior)
         mainFrame = Frame(interior)
         ## Creat NoteBook
         ## Creat NoteBook
         self.notebookFrame = Pmw.NoteBook(mainFrame)
         self.notebookFrame = Pmw.NoteBook(mainFrame)
-        self.notebookFrame.pack(fill=Tkinter.BOTH,expand=1)
+        self.notebookFrame.pack(fill=tkinter.BOTH,expand=1)
         sgePage = self.notebookFrame.add('Tree Graph')
         sgePage = self.notebookFrame.add('Tree Graph')
         envPage = self.notebookFrame.add('World Setting')
         envPage = self.notebookFrame.add('World Setting')
         self.notebookFrame['raisecommand'] = self.updateInfo
         self.notebookFrame['raisecommand'] = self.updateInfo
@@ -83,7 +91,7 @@ class sideWindow(AppShell):
             sgePage, nodePath = render,
             sgePage, nodePath = render,
             scrolledCanvas_hull_width = 270,
             scrolledCanvas_hull_width = 270,
             scrolledCanvas_hull_height = 570)
             scrolledCanvas_hull_height = 570)
-        self.SGE.pack(fill = Tkinter.BOTH, expand = 0)
+        self.SGE.pack(fill = tkinter.BOTH, expand = 0)
 
 
         ## World Setting Page
         ## World Setting Page
         envPage = Frame(envPage)
         envPage = Frame(envPage)
@@ -95,8 +103,8 @@ class sideWindow(AppShell):
             text = 'Enable Lighting',
             text = 'Enable Lighting',
             variable = self.LightingVar,
             variable = self.LightingVar,
             command = self.toggleLights)
             command = self.toggleLights)
-        self.LightingButton.pack(side=Tkinter.LEFT, expand=False)
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        self.LightingButton.pack(side=tkinter.LEFT, expand=False)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         pageFrame = Frame(envPage)
         pageFrame = Frame(envPage)
         self.CollisionVar = IntVar()
         self.CollisionVar = IntVar()
@@ -106,8 +114,8 @@ class sideWindow(AppShell):
             text = 'Show Collision Object',
             text = 'Show Collision Object',
             variable = self.CollisionVar,
             variable = self.CollisionVar,
             command = self.showCollision)
             command = self.showCollision)
-        self.CollisionButton.pack(side=Tkinter.LEFT, expand=False)
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        self.CollisionButton.pack(side=tkinter.LEFT, expand=False)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         pageFrame = Frame(envPage)
         pageFrame = Frame(envPage)
         self.ParticleVar = IntVar()
         self.ParticleVar = IntVar()
@@ -117,8 +125,8 @@ class sideWindow(AppShell):
             text = 'Show Particle Dummy',
             text = 'Show Particle Dummy',
             variable = self.ParticleVar,
             variable = self.ParticleVar,
             command = self.enableParticle)
             command = self.enableParticle)
-        self.ParticleButton.pack(side=Tkinter.LEFT, expand=False)
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        self.ParticleButton.pack(side=tkinter.LEFT, expand=False)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         pageFrame = Frame(envPage)
         pageFrame = Frame(envPage)
         self.baseUseDriveVar = IntVar()
         self.baseUseDriveVar = IntVar()
@@ -128,8 +136,8 @@ class sideWindow(AppShell):
             text = 'Enable base.usedrive',
             text = 'Enable base.usedrive',
             variable = self.baseUseDriveVar,
             variable = self.baseUseDriveVar,
             command = self.enablebaseUseDrive)
             command = self.enablebaseUseDrive)
-        self.baseUseDriveButton.pack(side=Tkinter.LEFT, expand=False)
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        self.baseUseDriveButton.pack(side=tkinter.LEFT, expand=False)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         pageFrame = Frame(envPage)
         pageFrame = Frame(envPage)
         self.backfaceVar = IntVar()
         self.backfaceVar = IntVar()
@@ -139,8 +147,8 @@ class sideWindow(AppShell):
             text = 'Enable BackFace',
             text = 'Enable BackFace',
             variable = self.backfaceVar,
             variable = self.backfaceVar,
             command = self.toggleBackface)
             command = self.toggleBackface)
-        self.backfaceButton.pack(side=Tkinter.LEFT, expand=False)
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        self.backfaceButton.pack(side=tkinter.LEFT, expand=False)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         pageFrame = Frame(envPage)
         pageFrame = Frame(envPage)
         self.textureVar = IntVar()
         self.textureVar = IntVar()
@@ -150,8 +158,8 @@ class sideWindow(AppShell):
             text = 'Enable Texture',
             text = 'Enable Texture',
             variable = self.textureVar,
             variable = self.textureVar,
             command = self.toggleTexture)
             command = self.toggleTexture)
-        self.textureButton.pack(side=Tkinter.LEFT, expand=False)
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        self.textureButton.pack(side=tkinter.LEFT, expand=False)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         pageFrame = Frame(envPage)
         pageFrame = Frame(envPage)
         self.wireframeVar = IntVar()
         self.wireframeVar = IntVar()
@@ -161,8 +169,8 @@ class sideWindow(AppShell):
             text = 'Enable Wireframe',
             text = 'Enable Wireframe',
             variable = self.wireframeVar,
             variable = self.wireframeVar,
             command = self.toggleWireframe)
             command = self.toggleWireframe)
-        self.wireframeButton.pack(side=Tkinter.LEFT, expand=False)
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        self.wireframeButton.pack(side=tkinter.LEFT, expand=False)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         pageFrame = Frame(envPage)
         pageFrame = Frame(envPage)
         self.gridVar = IntVar()
         self.gridVar = IntVar()
@@ -172,8 +180,8 @@ class sideWindow(AppShell):
             text = 'Enable Grid',
             text = 'Enable Grid',
             variable = self.gridVar,
             variable = self.gridVar,
             command = self.toggleGrid)
             command = self.toggleGrid)
-        self.gridButton.pack(side=Tkinter.LEFT, expand=False)
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        self.gridButton.pack(side=tkinter.LEFT, expand=False)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         pageFrame = Frame(envPage)
         pageFrame = Frame(envPage)
         self.widgetVisVar = IntVar()
         self.widgetVisVar = IntVar()
@@ -183,8 +191,8 @@ class sideWindow(AppShell):
             text = 'Enable WidgetVisible',
             text = 'Enable WidgetVisible',
             variable = self.widgetVisVar,
             variable = self.widgetVisVar,
             command = self.togglewidgetVis)
             command = self.togglewidgetVis)
-        self.widgetVisButton.pack(side=Tkinter.LEFT, expand=False)
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        self.widgetVisButton.pack(side=tkinter.LEFT, expand=False)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         pageFrame = Frame(envPage)
         pageFrame = Frame(envPage)
         self.enableAutoCameraVar = IntVar()
         self.enableAutoCameraVar = IntVar()
@@ -194,17 +202,17 @@ class sideWindow(AppShell):
             text = 'Enable Auto Camera Movement for Loading Objects',
             text = 'Enable Auto Camera Movement for Loading Objects',
             variable = self.enableAutoCameraVar,
             variable = self.enableAutoCameraVar,
             command = self.toggleAutoCamera)
             command = self.toggleAutoCamera)
-        self.enableAutoCameraButton.pack(side=Tkinter.LEFT, expand=False)
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        self.enableAutoCameraButton.pack(side=tkinter.LEFT, expand=False)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         pageFrame = Frame(envPage)
         pageFrame = Frame(envPage)
         self.backgroundColor = ColorEntry(
         self.backgroundColor = ColorEntry(
             pageFrame, text = 'BG Color', value=self.worldColor)
             pageFrame, text = 'BG Color', value=self.worldColor)
         self.backgroundColor['command'] = self.setBackgroundColorVec
         self.backgroundColor['command'] = self.setBackgroundColorVec
         self.backgroundColor['resetValue'] = [0,0,0,0]
         self.backgroundColor['resetValue'] = [0,0,0,0]
-        self.backgroundColor.pack(side=Tkinter.LEFT, expand=False)
+        self.backgroundColor.pack(side=tkinter.LEFT, expand=False)
         self.bind(self.backgroundColor, 'Set background color')
         self.bind(self.backgroundColor, 'Set background color')
-        pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
+        pageFrame.pack(side=tkinter.TOP, fill=tkinter.X, expand=True)
 
 
         envPage.pack(expand=False)
         envPage.pack(expand=False)
 
 
@@ -320,11 +328,11 @@ class sideWindow(AppShell):
         #
         #
         #################################################################
         #################################################################
         if self.enableBaseUseDrive==0:
         if self.enableBaseUseDrive==0:
-            print 'Enabled'
+            print('Enabled')
             base.useDrive()
             base.useDrive()
             self.enableBaseUseDrive = 1
             self.enableBaseUseDrive = 1
         else:
         else:
-            print 'disabled'
+            print('disabled')
             #base.useTrackball()
             #base.useTrackball()
             base.disableMouse()
             base.disableMouse()
             self.enableBaseUseDrive = 0
             self.enableBaseUseDrive = 0

+ 3 - 4
contrib/src/sceneeditor/collisionWindow.py

@@ -9,9 +9,8 @@ from seColorEntry import *
 from direct.tkwidgets import VectorWidgets
 from direct.tkwidgets import VectorWidgets
 from direct.tkwidgets import Floater
 from direct.tkwidgets import Floater
 from direct.tkwidgets import Slider
 from direct.tkwidgets import Slider
-from Tkinter import *
 import string, math, types
 import string, math, types
-from pandac.PandaModules import *
+from panda3d.core import *
 
 
 
 
 class collisionWindow(AppShell):
 class collisionWindow(AppShell):
@@ -195,7 +194,7 @@ class collisionWindow(AppShell):
         # put the object into a CollisionNode and attach it to the target nodePath
         # put the object into a CollisionNode and attach it to the target nodePath
         #################################################################
         #################################################################
         collisionObject = None
         collisionObject = None
-        print self.objType
+        print(self.objType)
         if self.objType=='collisionPolygon':
         if self.objType=='collisionPolygon':
             pointA =  Point3(float(self.widgetDict['PolygonPoint A'][0]._entry.get()),
             pointA =  Point3(float(self.widgetDict['PolygonPoint A'][0]._entry.get()),
                              float(self.widgetDict['PolygonPoint A'][1]._entry.get()),
                              float(self.widgetDict['PolygonPoint A'][1]._entry.get()),
@@ -236,7 +235,7 @@ class collisionWindow(AppShell):
                            float(self.widgetDict['RayDirection'][1]._entry.get()),
                            float(self.widgetDict['RayDirection'][1]._entry.get()),
                            float(self.widgetDict['RayDirection'][2]._entry.get()))
                            float(self.widgetDict['RayDirection'][2]._entry.get()))
 
 
-            print vector, point
+            print(vector, point)
 
 
             collisionObject = CollisionRay()
             collisionObject = CollisionRay()
             collisionObject.setOrigin(point)
             collisionObject.setOrigin(point)

+ 186 - 180
contrib/src/sceneeditor/controllerWindow.py

@@ -4,8 +4,14 @@
 #################################################################
 #################################################################
 
 
 from direct.tkwidgets.AppShell import AppShell
 from direct.tkwidgets.AppShell import AppShell
-from Tkinter import Frame, Label, Button
-import string, Pmw, Tkinter
+import sys, Pmw
+
+if sys.version_info >= (3, 0):
+    from tkinter import Frame, Label, Button
+    import tkinter
+else:
+    from Tkinter import Frame, Label, Button
+    import Tkinter as tkinter
 
 
 # Define the Category
 # Define the Category
 KEYBOARD = 'Keyboard-'
 KEYBOARD = 'Keyboard-'
@@ -75,11 +81,11 @@ class controllerWindow(AppShell):
         self.cotrollerTypeEntry = self.createcomponent(
         self.cotrollerTypeEntry = self.createcomponent(
             'Controller Type', (), None,
             'Controller Type', (), None,
             Pmw.ComboBox, (frame,),
             Pmw.ComboBox, (frame,),
-            labelpos = Tkinter.W, label_text='Controller Type:', entry_width = 20,entry_state = Tkinter.DISABLED,
+            labelpos = tkinter.W, label_text='Controller Type:', entry_width = 20,entry_state = tkinter.DISABLED,
             selectioncommand = self.setControllerType,
             selectioncommand = self.setControllerType,
             scrolledlist_items = self.controllerList)
             scrolledlist_items = self.controllerList)
-        self.cotrollerTypeEntry.pack(side=Tkinter.LEFT)
-        frame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=False, pady = 3)
+        self.cotrollerTypeEntry.pack(side=tkinter.LEFT)
+        frame.pack(side=tkinter.TOP, fill=tkinter.X, expand=False, pady = 3)
         self.cotrollerTypeEntry.selectitem('Keyboard', setentry=True)
         self.cotrollerTypeEntry.selectitem('Keyboard', setentry=True)
 
 
         self.inputZone = Pmw.Group(mainFrame, tag_pyclass = None)
         self.inputZone = Pmw.Group(mainFrame, tag_pyclass = None)
@@ -102,7 +108,7 @@ class controllerWindow(AppShell):
         keyboardPage = self.objNotebook.add('Keyboard')
         keyboardPage = self.objNotebook.add('Keyboard')
         tarckerPage = self.objNotebook.add('Tracker')
         tarckerPage = self.objNotebook.add('Tracker')
         self.objNotebook.selectpage('Keyboard')
         self.objNotebook.selectpage('Keyboard')
-        self.objNotebook.pack(side = Tkinter.TOP, fill='both',expand=False)
+        self.objNotebook.pack(side = tkinter.TOP, fill='both',expand=False)
         # Put this here so it isn't called right away
         # Put this here so it isn't called right away
         self.objNotebook['raisecommand'] = self.updateControlInfo
         self.objNotebook['raisecommand'] = self.updateControlInfo
 
 
@@ -113,11 +119,11 @@ class controllerWindow(AppShell):
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Target Type', (), None,
             'Target Type', (), None,
             Pmw.ComboBox, (Interior,),
             Pmw.ComboBox, (Interior,),
-            labelpos = Tkinter.W, label_text='Target Object:', entry_width = 20, entry_state = Tkinter.DISABLED,
+            labelpos = tkinter.W, label_text='Target Object:', entry_width = 20, entry_state = tkinter.DISABLED,
             selectioncommand = self.setTargetObj,
             selectioncommand = self.setTargetObj,
             scrolledlist_items = self.listOfObj)
             scrolledlist_items = self.listOfObj)
-        widget.pack(side=Tkinter.LEFT, padx=3)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 5)
+        widget.pack(side=tkinter.LEFT, padx=3)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 5)
         widget.selectitem(self.nameOfNode, setentry=True)
         widget.selectitem(self.nameOfNode, setentry=True)
         self.widgetsDict[KEYBOARD+'ObjList'] = widget
         self.widgetsDict[KEYBOARD+'ObjList'] = widget
 
 
@@ -126,411 +132,411 @@ class controllerWindow(AppShell):
         settingFrame = inputZone.interior()
         settingFrame = inputZone.interior()
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Assign a Key For:').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True,pady = 6 )
+        widget = Label(Interior, text = 'Assign a Key For:').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True,pady = 6 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Forward   :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Forward   :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Forward key', (), None,
             'Forward key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyForward'],
             value = self.keyboardMapDict['KeyForward'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyForward'] = widget
         self.widgetsDict[KEYBOARD+'KeyForward'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Forward Speed', (), None,
             'Forward Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedForward'],
             value = self.keyboardSpeedDict['SpeedForward'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedForward'] = widget
         self.widgetsDict[KEYBOARD+'SpeedForward'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Backward  :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Backward  :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Backward key', (), None,
             'Backward key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyBackward'],
             value = self.keyboardMapDict['KeyBackward'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyBackward'] = widget
         self.widgetsDict[KEYBOARD+'KeyBackward'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Backward Speed', (), None,
             'Backward Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedBackward'],
             value = self.keyboardSpeedDict['SpeedBackward'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedBackward'] = widget
         self.widgetsDict[KEYBOARD+'SpeedBackward'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Right     :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Right     :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Right key', (), None,
             'Right key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyRight'],
             value = self.keyboardMapDict['KeyRight'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyRight'] = widget
         self.widgetsDict[KEYBOARD+'KeyRight'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Right Speed', (), None,
             'Right Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedRight'],
             value = self.keyboardSpeedDict['SpeedRight'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedRight'] = widget
         self.widgetsDict[KEYBOARD+'SpeedRight'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Left      :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Left      :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Left key', (), None,
             'Left key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyLeft'],
             value = self.keyboardMapDict['KeyLeft'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyLeft'] = widget
         self.widgetsDict[KEYBOARD+'KeyLeft'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Left Speed', (), None,
             'Left Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedLeft'],
             value = self.keyboardSpeedDict['SpeedLeft'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedLeft'] = widget
         self.widgetsDict[KEYBOARD+'SpeedLeft'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Up        :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Up        :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Up key', (), None,
             'Up key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyUp'],
             value = self.keyboardMapDict['KeyUp'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyUp'] = widget
         self.widgetsDict[KEYBOARD+'KeyUp'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Up Speed', (), None,
             'Up Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedUp'],
             value = self.keyboardSpeedDict['SpeedUp'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedUp'] = widget
         self.widgetsDict[KEYBOARD+'SpeedUp'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Down      :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Down      :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Down key', (), None,
             'Down key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyDown'],
             value = self.keyboardMapDict['KeyDown'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyDown'] = widget
         self.widgetsDict[KEYBOARD+'KeyDown'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Down Speed', (), None,
             'Down Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedDown'],
             value = self.keyboardSpeedDict['SpeedDown'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedDown'] = widget
         self.widgetsDict[KEYBOARD+'SpeedDown'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Turn Right:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Turn Right:', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Turn Right key', (), None,
             'Turn Right key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyTurnRight'],
             value = self.keyboardMapDict['KeyTurnRight'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyTurnRight'] = widget
         self.widgetsDict[KEYBOARD+'KeyTurnRight'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Turn Right Speed', (), None,
             'Turn Right Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedTurnRight'],
             value = self.keyboardSpeedDict['SpeedTurnRight'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedTurnRight'] = widget
         self.widgetsDict[KEYBOARD+'SpeedTurnRight'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Turn Left :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Turn Left :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Turn Left key', (), None,
             'Turn Left key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyTurnLeft'],
             value = self.keyboardMapDict['KeyTurnLeft'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyTurnLeft'] = widget
         self.widgetsDict[KEYBOARD+'KeyTurnLeft'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Turn Left Speed', (), None,
             'Turn Left Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedTurnLeft'],
             value = self.keyboardSpeedDict['SpeedTurnLeft'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedTurnLeft'] = widget
         self.widgetsDict[KEYBOARD+'SpeedTurnLeft'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Turn UP   :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Turn UP   :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Turn UP key', (), None,
             'Turn UP key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyTurnUp'],
             value = self.keyboardMapDict['KeyTurnUp'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyTurnUp'] = widget
         self.widgetsDict[KEYBOARD+'KeyTurnUp'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Turn UP Speed', (), None,
             'Turn UP Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedTurnUp'],
             value = self.keyboardSpeedDict['SpeedTurnUp'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedTurnUp'] = widget
         self.widgetsDict[KEYBOARD+'SpeedTurnUp'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Turn Down :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Turn Down :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Turn Down key', (), None,
             'Turn Down key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyTurnDown'],
             value = self.keyboardMapDict['KeyTurnDown'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyTurnDown'] = widget
         self.widgetsDict[KEYBOARD+'KeyTurnDown'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Turn Down Speed', (), None,
             'Turn Down Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedTurnDown'],
             value = self.keyboardSpeedDict['SpeedTurnDown'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedTurnDown'] = widget
         self.widgetsDict[KEYBOARD+'SpeedTurnDown'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Roll Right:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Roll Right:', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Roll Right key', (), None,
             'Roll Right key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyRollRight'],
             value = self.keyboardMapDict['KeyRollRight'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyRollRight'] = widget
         self.widgetsDict[KEYBOARD+'KeyRollRight'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Roll Right Speed', (), None,
             'Roll Right Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedRollRight'],
             value = self.keyboardSpeedDict['SpeedRollRight'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedRollRight'] = widget
         self.widgetsDict[KEYBOARD+'SpeedRollRight'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Roll Left :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Roll Left :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Roll Left key', (), None,
             'Roll Left key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyRollLeft'],
             value = self.keyboardMapDict['KeyRollLeft'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyRollLeft'] = widget
         self.widgetsDict[KEYBOARD+'KeyRollLeft'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Roll Left Speed', (), None,
             'Roll Left Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedRollLeft'],
             value = self.keyboardSpeedDict['SpeedRollLeft'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedRollLeft'] = widget
         self.widgetsDict[KEYBOARD+'SpeedRollLeft'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Scale UP :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Scale UP :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale UP key', (), None,
             'Scale UP key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyScaleUp'],
             value = self.keyboardMapDict['KeyScaleUp'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyScaleUp'] = widget
         self.widgetsDict[KEYBOARD+'KeyScaleUp'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale UP Speed', (), None,
             'Scale UP Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedScaleUp'],
             value = self.keyboardSpeedDict['SpeedScaleUp'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedScaleUp'] = widget
         self.widgetsDict[KEYBOARD+'SpeedScaleUp'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Scale Down:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Scale Down:', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Down key', (), None,
             'Scale Down key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyScaleDown'],
             value = self.keyboardMapDict['KeyScaleDown'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyScaleDown'] = widget
         self.widgetsDict[KEYBOARD+'KeyScaleDown'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Down Speed', (), None,
             'Scale Down Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedScaleDown'],
             value = self.keyboardSpeedDict['SpeedScaleDown'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedScaleDown'] = widget
         self.widgetsDict[KEYBOARD+'SpeedScaleDown'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Scale X UP :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Scale X UP :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale X UP key', (), None,
             'Scale X UP key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyScaleXUp'],
             value = self.keyboardMapDict['KeyScaleXUp'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyScaleXUp'] = widget
         self.widgetsDict[KEYBOARD+'KeyScaleXUp'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale X UP Speed', (), None,
             'Scale X UP Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedScaleXUp'],
             value = self.keyboardSpeedDict['SpeedScaleXUp'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedScaleXUp'] = widget
         self.widgetsDict[KEYBOARD+'SpeedScaleXUp'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Scale X Down:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Scale X Down:', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale X Down key', (), None,
             'Scale X Down key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyScaleXDown'],
             value = self.keyboardMapDict['KeyScaleXDown'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyScaleXDown'] = widget
         self.widgetsDict[KEYBOARD+'KeyScaleXDown'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Down X Speed', (), None,
             'Scale Down X Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedScaleXDown'],
             value = self.keyboardSpeedDict['SpeedScaleXDown'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedScaleXDown'] = widget
         self.widgetsDict[KEYBOARD+'SpeedScaleXDown'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Scale Y UP :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Scale Y UP :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Y UP key', (), None,
             'Scale Y UP key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyScaleYUp'],
             value = self.keyboardMapDict['KeyScaleYUp'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyScaleYUp'] = widget
         self.widgetsDict[KEYBOARD+'KeyScaleYUp'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Y UP Speed', (), None,
             'Scale Y UP Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedScaleYUp'],
             value = self.keyboardSpeedDict['SpeedScaleYUp'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedScaleYUp'] = widget
         self.widgetsDict[KEYBOARD+'SpeedScaleYUp'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Scale Y Down:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Scale Y Down:', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Y Down key', (), None,
             'Scale Y Down key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyScaleYDown'],
             value = self.keyboardMapDict['KeyScaleYDown'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyScaleYDown'] = widget
         self.widgetsDict[KEYBOARD+'KeyScaleYDown'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Down XY Speed', (), None,
             'Scale Down XY Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedScaleYDown'],
             value = self.keyboardSpeedDict['SpeedScaleYDown'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedScaleYDown'] = widget
         self.widgetsDict[KEYBOARD+'SpeedScaleYDown'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Scale Z UP :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Scale Z UP :', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Z UP key', (), None,
             'Scale Z UP key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyScaleZUp'],
             value = self.keyboardMapDict['KeyScaleZUp'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyScaleZUp'] = widget
         self.widgetsDict[KEYBOARD+'KeyScaleZUp'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Z UP Speed', (), None,
             'Scale Z UP Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedScaleZUp'],
             value = self.keyboardSpeedDict['SpeedScaleZUp'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedScaleZUp'] = widget
         self.widgetsDict[KEYBOARD+'SpeedScaleZUp'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
         Interior = Frame(settingFrame)
         Interior = Frame(settingFrame)
-        widget = Label(Interior, text = 'Scale Z Down:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = 'Scale Z Down:', width = 20, anchor = tkinter.W).pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Z Down key', (), None,
             'Scale Z Down key', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardMapDict['KeyScaleZDown'],
             value = self.keyboardMapDict['KeyScaleZDown'],
-            labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Key :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'KeyScaleZDown'] = widget
         self.widgetsDict[KEYBOARD+'KeyScaleZDown'] = widget
-        widget = Label(Interior, text = '   ').pack(side=Tkinter.LEFT, expand = False)
+        widget = Label(Interior, text = '   ').pack(side=tkinter.LEFT, expand = False)
         widget = self.createcomponent(
         widget = self.createcomponent(
             'Scale Down Z Speed', (), None,
             'Scale Down Z Speed', (), None,
             Pmw.EntryField, (Interior,),
             Pmw.EntryField, (Interior,),
             value = self.keyboardSpeedDict['SpeedScaleZDown'],
             value = self.keyboardSpeedDict['SpeedScaleZDown'],
-            labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
-        widget.pack(side=Tkinter.LEFT, expand = False)
+            labelpos = tkinter.W, label_text='Speed :', entry_width = 10)
+        widget.pack(side=tkinter.LEFT, expand = False)
         self.widgetsDict[KEYBOARD+'SpeedScaleZDown'] = widget
         self.widgetsDict[KEYBOARD+'SpeedScaleZDown'] = widget
-        widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
-        Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
+        widget = Label(Interior, text = 'Per Second').pack(side=tkinter.LEFT, expand = False)
+        Interior.pack(side=tkinter.TOP, fill=tkinter.X, expand=True, pady = 4 )
 
 
-        assignFrame.pack(side=Tkinter.TOP, expand=True, fill = Tkinter.X)
-        keyboardPage.pack(side=Tkinter.TOP, expand=True, fill = Tkinter.X)
+        assignFrame.pack(side=tkinter.TOP, expand=True, fill = tkinter.X)
+        keyboardPage.pack(side=tkinter.TOP, expand=True, fill = tkinter.X)
 
 
         ####################################################################
         ####################################################################
         ####################################################################
         ####################################################################
@@ -539,12 +545,12 @@ class controllerWindow(AppShell):
         ####################################################################
         ####################################################################
         # Pack the mainFrame
         # Pack the mainFrame
         frame = Frame(mainFrame)
         frame = Frame(mainFrame)
-        widget = Button(frame, text='OK', width = 13, command=self.ok_press).pack(side=Tkinter.RIGHT)
-        widget = Button(frame, text='Enable Control', width = 13, command=self.enableControl).pack(side=Tkinter.LEFT)
-        widget = Button(frame, text='Disable Control', width = 13, command=self.disableControl).pack(side=Tkinter.LEFT)
-        widget = Button(frame, text='Save & Keep', width = 13, command=self.saveKeepControl).pack(side=Tkinter.LEFT)
-        frame.pack(side = Tkinter.BOTTOM, expand=1, fill = Tkinter.X)
-        mainFrame.pack(expand=1, fill = Tkinter.BOTH)
+        widget = Button(frame, text='OK', width = 13, command=self.ok_press).pack(side=tkinter.RIGHT)
+        widget = Button(frame, text='Enable Control', width = 13, command=self.enableControl).pack(side=tkinter.LEFT)
+        widget = Button(frame, text='Disable Control', width = 13, command=self.disableControl).pack(side=tkinter.LEFT)
+        widget = Button(frame, text='Save & Keep', width = 13, command=self.saveKeepControl).pack(side=tkinter.LEFT)
+        frame.pack(side = tkinter.BOTTOM, expand=1, fill = tkinter.X)
+        mainFrame.pack(expand=1, fill = tkinter.BOTH)
 
 
     def onDestroy(self, event):
     def onDestroy(self, event):
         # Check if user wish to keep the control after the window closed.
         # Check if user wish to keep the control after the window closed.
@@ -688,7 +694,7 @@ class controllerWindow(AppShell):
                 self.keyboardMapDict[index] = self.widgetsDict['Keyboard-'+index].getvalue()
                 self.keyboardMapDict[index] = self.widgetsDict['Keyboard-'+index].getvalue()
             for index in self.keyboardSpeedDict:
             for index in self.keyboardSpeedDict:
                 self.keyboardSpeedDict[index] = float(self.widgetsDict['Keyboard-'+index].getvalue())
                 self.keyboardSpeedDict[index] = float(self.widgetsDict['Keyboard-'+index].getvalue())
-            print self.nodePath
+            print(self.nodePath)
             messenger.send('ControlW_saveSetting', ['Keyboard', [self.nodePath, self.keyboardMapDict, self.keyboardSpeedDict]])
             messenger.send('ControlW_saveSetting', ['Keyboard', [self.nodePath, self.keyboardMapDict, self.keyboardSpeedDict]])
         return
         return
 
 

+ 50 - 48
contrib/src/sceneeditor/dataHolder.py

@@ -2,13 +2,15 @@
 # TK and PMW INTERFACE MODULES#
 # TK and PMW INTERFACE MODULES#
 ###############################
 ###############################
 from direct.showbase.TkGlobal import*
 from direct.showbase.TkGlobal import*
-from tkFileDialog import *
 import Pmw
 import Pmw
-import tkFileDialog
-import tkMessageBox
 from direct.tkwidgets import Dial
 from direct.tkwidgets import Dial
 from direct.tkwidgets import Floater
 from direct.tkwidgets import Floater
 
 
+if sys.version_info >= (3, 0):
+    from tkinter.filedialog import askopenfilename
+else:
+    from tkFileDialog import askopenfilename
+
 
 
 #############################
 #############################
 # Scene Editor Python Files #
 # Scene Editor Python Files #
@@ -154,7 +156,7 @@ class dataHolder:
         self.ActorNum=0
         self.ActorNum=0
         self.theScene=None
         self.theScene=None
         messenger.send('SGE_Update Explorer',[render])
         messenger.send('SGE_Update Explorer',[render])
-        print 'Scene should be cleaned up!'
+        print('Scene should be cleaned up!')
 
 
     def removeObj(self, nodePath):
     def removeObj(self, nodePath):
         #################################################################
         #################################################################
@@ -169,7 +171,7 @@ class dataHolder:
         childrenList = nodePath.getChildren()
         childrenList = nodePath.getChildren()
 
 
 
 
-        if self.ModelDic.has_key(name):
+        if name in self.ModelDic:
             del self.ModelDic[name]
             del self.ModelDic[name]
             del self.ModelRefDic[name]
             del self.ModelRefDic[name]
             if len(childrenList) != 0:
             if len(childrenList) != 0:
@@ -178,7 +180,7 @@ class dataHolder:
             nodePath.removeNode()
             nodePath.removeNode()
             self.ModelNum -= 1
             self.ModelNum -= 1
             pass
             pass
-        elif self.ActorDic.has_key(name):
+        elif name in self.ActorDic:
             del self.ActorDic[name]
             del self.ActorDic[name]
             del self.ActorRefDic[name]
             del self.ActorRefDic[name]
             if len(childrenList) != 0:
             if len(childrenList) != 0:
@@ -187,14 +189,14 @@ class dataHolder:
             nodePath.removeNode()
             nodePath.removeNode()
             self.ActorNum -= 1
             self.ActorNum -= 1
             pass
             pass
-        elif self.collisionDict.has_key(name):
+        elif name in self.collisionDict:
             del self.collisionDict[name]
             del self.collisionDict[name]
             if len(childrenList) != 0:
             if len(childrenList) != 0:
                 for node in childrenList:
                 for node in childrenList:
                     self.removeObj(node)
                     self.removeObj(node)
             nodePath.removeNode()
             nodePath.removeNode()
             pass
             pass
-        elif self.dummyDict.has_key(name):
+        elif name in self.dummyDict:
             del self.dummyDict[name]
             del self.dummyDict[name]
             if len(childrenList) != 0:
             if len(childrenList) != 0:
                 for node in childrenList:
                 for node in childrenList:
@@ -207,12 +209,12 @@ class dataHolder:
                     self.removeObj(node)
                     self.removeObj(node)
             list = self.lightManager.delete(name)
             list = self.lightManager.delete(name)
             return list
             return list
-        elif self.particleNodes.has_key(name):
+        elif name in self.particleNodes:
             self.particleNodes[name].removeNode()
             self.particleNodes[name].removeNode()
             del self.particleNodes[name]
             del self.particleNodes[name]
             del self.particleDict[name]
             del self.particleDict[name]
         else:
         else:
-            print 'You cannot remove this NodePath'
+            print('You cannot remove this NodePath')
             return
             return
 
 
         messenger.send('SGE_Update Explorer',[render])
         messenger.send('SGE_Update Explorer',[render])
@@ -237,15 +239,15 @@ class dataHolder:
         cHpr = hpr
         cHpr = hpr
         cScale = scale
         cScale = scale
         parent = nodePath.getParent()
         parent = nodePath.getParent()
-        if self.ActorDic.has_key(name):
+        if name in self.ActorDic:
             holder = self.ActorDic
             holder = self.ActorDic
             holderRef = self.ActorRefDic
             holderRef = self.ActorRefDic
             isModel = False
             isModel = False
-        elif self.ModelDic.has_key(name):
+        elif name in self.ModelDic:
             holder = self.ModelDic
             holder = self.ModelDic
             holderRef = self.ModelRefDic
             holderRef = self.ModelRefDic
         else:
         else:
-            print '---- DataHolder: Target Obj is not a legal object could be duplicate!'
+            print('---- DataHolder: Target Obj is not a legal object could be duplicate!')
             return
             return
 
 
         FilePath = holderRef[name]
         FilePath = holderRef[name]
@@ -356,7 +358,7 @@ class dataHolder:
         # This funciton will return True if there is an Actor in the scene named "name"
         # This funciton will return True if there is an Actor in the scene named "name"
         # and will return False if not.
         # and will return False if not.
         ###########################################################################
         ###########################################################################
-        return self.ActorDic.has_key(name)
+        return name in self.ActorDic
 
 
     def getActor(self, name):
     def getActor(self, name):
         ###########################################################################
         ###########################################################################
@@ -366,7 +368,7 @@ class dataHolder:
         if self.isActor(name):
         if self.isActor(name):
             return self.ActorDic[name]
             return self.ActorDic[name]
         else:
         else:
-            print '----No Actor named: ', name
+            print('----No Actor named: ', name)
             return None
             return None
 
 
     def getModel(self, name):
     def getModel(self, name):
@@ -377,7 +379,7 @@ class dataHolder:
         if self.isModel(name):
         if self.isModel(name):
             return self.ModelDic[name]
             return self.ModelDic[name]
         else:
         else:
-            print '----No Model named: ', name
+            print('----No Model named: ', name)
             return None
             return None
 
 
     def isModel(self, name):
     def isModel(self, name):
@@ -386,7 +388,7 @@ class dataHolder:
         # This funciton will return True if there is a Model in the scene named "name"
         # This funciton will return True if there is a Model in the scene named "name"
         # and will return False if not.
         # and will return False if not.
         ###########################################################################
         ###########################################################################
-        return self.ModelDic.has_key(name)
+        return name in self.ModelDic
 
 
     def loadAnimation(self,name, Dic):
     def loadAnimation(self,name, Dic):
         ###########################################################################
         ###########################################################################
@@ -406,7 +408,7 @@ class dataHolder:
             messenger.send('DataH_loadFinish'+name)
             messenger.send('DataH_loadFinish'+name)
             return
             return
         else:
         else:
-            print '------ Error when loading animation for Actor: ', name
+            print('------ Error when loading animation for Actor: ', name)
 
 
     def removeAnimation(self, name, anim):
     def removeAnimation(self, name, anim):
         ###########################################################################
         ###########################################################################
@@ -527,7 +529,7 @@ class dataHolder:
             self.ActorDic[nName]= self.ActorDic[oName]
             self.ActorDic[nName]= self.ActorDic[oName]
             self.ActorRefDic[nName]= self.ActorRefDic[oName]
             self.ActorRefDic[nName]= self.ActorRefDic[oName]
             self.ActorDic[nName].setName(nName)
             self.ActorDic[nName].setName(nName)
-            if self.blendAnimDict.has_key(oName):
+            if oName in self.blendAnimDict:
                 self.blendAnimDict[nName] = self.blendAnimDict[oName]
                 self.blendAnimDict[nName] = self.blendAnimDict[oName]
                 del self.blendAnimDict[oName]
                 del self.blendAnimDict[oName]
             del self.ActorDic[oName]
             del self.ActorDic[oName]
@@ -540,16 +542,16 @@ class dataHolder:
             del self.ModelRefDic[oName]
             del self.ModelRefDic[oName]
         elif self.lightManager.isLight(oName):
         elif self.lightManager.isLight(oName):
             list, lightNode = self.lightManager.rename(oName, nName)
             list, lightNode = self.lightManager.rename(oName, nName)
-        elif self.dummyDict.has_key(oName):
+        elif oName in self.dummyDict:
             self.dummyDict[nName]= self.dummyDict[oName]
             self.dummyDict[nName]= self.dummyDict[oName]
             self.dummyDict[nName].setName(nName)
             self.dummyDict[nName].setName(nName)
             del self.dummyDict[oName]
             del self.dummyDict[oName]
-        elif self.collisionDict.has_key(oName):
+        elif oName in self.collisionDict:
             self.collisionDict[nName]= self.collisionDict[oName]
             self.collisionDict[nName]= self.collisionDict[oName]
             self.collisionDict[nName].setName(nName)
             self.collisionDict[nName].setName(nName)
             del self.collisionDict[oName]
             del self.collisionDict[oName]
 
 
-        elif self.particleNodes.has_key(oName):
+        elif oName in self.particleNodes:
             self.particleNodes[nName]= self.particleNodes[oName]
             self.particleNodes[nName]= self.particleNodes[oName]
             self.particleDict[nName]= self.particleDict[oName]
             self.particleDict[nName]= self.particleDict[oName]
             self.particleDict[nName].setName(nName)
             self.particleDict[nName].setName(nName)
@@ -557,9 +559,9 @@ class dataHolder:
             del self.particleNodes[oName]
             del self.particleNodes[oName]
             del self.particleDict[oName]
             del self.particleDict[oName]
         else:
         else:
-            print '----Error: This Object is not allowed to this function!'
+            print('----Error: This Object is not allowed to this function!')
 
 
-        if self.curveDict.has_key(oName):
+        if oName in self.curveDict:
             self.curveDict[nName] = self.curveDict[oName]
             self.curveDict[nName] = self.curveDict[oName]
             del self.curveDict[oName]
             del self.curveDict[oName]
 
 
@@ -578,11 +580,11 @@ class dataHolder:
             return True
             return True
         elif self.lightManager.isLight(name):
         elif self.lightManager.isLight(name):
             return True
             return True
-        elif self.dummyDict.has_key(name):
+        elif name in self.dummyDict:
             return True
             return True
-        elif self.collisionDict.has_key(name):
+        elif name in self.collisionDict:
             return True
             return True
-        elif self.particleNodes.has_key(name):
+        elif name in self.particleNodes:
             return True
             return True
         elif (name == 'render')or(name == 'SEditor')or(name == 'Lights')or(name == 'camera'):
         elif (name == 'render')or(name == 'SEditor')or(name == 'Lights')or(name == 'camera'):
             return True
             return True
@@ -596,7 +598,7 @@ class dataHolder:
         # using the node name as a reference to assosiate a list which contains all curves related to that node.
         # using the node name as a reference to assosiate a list which contains all curves related to that node.
         ###########################################################################
         ###########################################################################
         name = node.getName()
         name = node.getName()
-        if self.curveDict.has_key(name):
+        if name in self.curveDict:
             self.curveDict[name].append(curveCollection)
             self.curveDict[name].append(curveCollection)
             return
             return
         else:
         else:
@@ -612,7 +614,7 @@ class dataHolder:
         # If the input node has not been bindedwith any curve, it will return None.
         # If the input node has not been bindedwith any curve, it will return None.
         ###########################################################################
         ###########################################################################
         name = nodePath.getName()
         name = nodePath.getName()
-        if self.curveDict.has_key(name):
+        if name in self.curveDict:
             return self.curveDict[name]
             return self.curveDict[name]
         else:
         else:
             return None
             return None
@@ -626,7 +628,7 @@ class dataHolder:
         # This message will be caught by Property Window for this node.
         # This message will be caught by Property Window for this node.
         ###########################################################################
         ###########################################################################
         name =nodePath.getName()
         name =nodePath.getName()
-        if self.curveDict.has_key(name):
+        if name in self.curveDict:
             index = None
             index = None
             for curve in self.curveDict[name]:
             for curve in self.curveDict[name]:
                 if curve.getCurve(0).getName() == curveName:
                 if curve.getCurve(0).getName() == curveName:
@@ -677,12 +679,12 @@ class dataHolder:
         elif self.isLight(name):
         elif self.isLight(name):
             type = 'Light'
             type = 'Light'
             info['lightNode'] = self.lightManager.getLightNode(name)
             info['lightNode'] = self.lightManager.getLightNode(name)
-        elif self.dummyDict.has_key(name):
+        elif name in self.dummyDict:
             type = 'dummy'
             type = 'dummy'
-        elif self.collisionDict.has_key(name):
+        elif name in self.collisionDict:
             type = 'collisionNode'
             type = 'collisionNode'
             info['collisionNode'] = self.collisionDict[name]
             info['collisionNode'] = self.collisionDict[name]
-        if self.curveDict.has_key(name):
+        if name in self.curveDict:
             info['curveList'] = self.getCurveList(nodePath)
             info['curveList'] = self.getCurveList(nodePath)
 
 
         return type, info
         return type, info
@@ -794,7 +796,7 @@ class dataHolder:
         # The formate of thsi dictionary is
         # The formate of thsi dictionary is
         # {"name of Blend Animation" : ["Animation A, Animation B, Effect(Float, 0~1)"]}
         # {"name of Blend Animation" : ["Animation A, Animation B, Effect(Float, 0~1)"]}
         ###########################################################################
         ###########################################################################
-        if self.blendAnimDict.has_key(name):
+        if name in self.blendAnimDict:
             return self.blendAnimDict[name]
             return self.blendAnimDict[name]
         else:
         else:
             return {}
             return {}
@@ -808,8 +810,8 @@ class dataHolder:
         # Also, if this blend is the first blend animation that the target actor has,
         # Also, if this blend is the first blend animation that the target actor has,
         # this function will add a "Blending" tag on this actor which is "True".
         # this function will add a "Blending" tag on this actor which is "True".
         ###########################################################################
         ###########################################################################
-        if self.blendAnimDict.has_key(actorName):
-            if self.blendAnimDict[actorName].has_key(blendName):
+        if actorName in self.blendAnimDict:
+            if blendName in self.blendAnimDict[actorName]:
                 ### replace the original setting
                 ### replace the original setting
                 self.blendAnimDict[actorName][blendName][0] = animNameA
                 self.blendAnimDict[actorName][blendName][0] = animNameA
                 self.blendAnimDict[actorName][blendName][1] = animNameB
                 self.blendAnimDict[actorName][blendName][1] = animNameB
@@ -832,7 +834,7 @@ class dataHolder:
         # it will also rewrite the data to the newest one.
         # it will also rewrite the data to the newest one.
         ###########################################################################
         ###########################################################################
         self.removeBlendAnim(actorName,oName)
         self.removeBlendAnim(actorName,oName)
-        print self.blendAnimDict
+        print(self.blendAnimDict)
         return self.saveBlendAnim(actorName, nName, animNameA, animNameB, effect)
         return self.saveBlendAnim(actorName, nName, animNameA, animNameB, effect)
 
 
     def removeBlendAnim(self, actorName, blendName):
     def removeBlendAnim(self, actorName, blendName):
@@ -844,8 +846,8 @@ class dataHolder:
         # Also, it will check that there is any blended animation remained for this actor,
         # Also, it will check that there is any blended animation remained for this actor,
         # If none, this function will clear the "Blending" tag of this object.
         # If none, this function will clear the "Blending" tag of this object.
         ###########################################################################
         ###########################################################################
-        if self.blendAnimDict.has_key(actorName):
-            if self.blendAnimDict[actorName].has_key(blendName):
+        if actorName in self.blendAnimDict:
+            if blendName in self.blendAnimDict[actorName]:
                 ### replace the original setting
                 ### replace the original setting
                 del self.blendAnimDict[actorName][blendName]
                 del self.blendAnimDict[actorName][blendName]
             if len(self.blendAnimDict[actorName])==0:
             if len(self.blendAnimDict[actorName])==0:
@@ -876,15 +878,15 @@ class dataHolder:
         ###########################################################################
         ###########################################################################
         if name == 'camera':
         if name == 'camera':
             return camera
             return camera
-        elif self.ModelDic.has_key(name):
+        elif name in self.ModelDic:
             return self.ModelDic[name]
             return self.ModelDic[name]
-        elif self.ActorDic.has_key(name):
+        elif name in self.ActorDic:
             return self.ActorDic[name]
             return self.ActorDic[name]
-        elif self.collisionDict.has_key(name):
+        elif name in self.collisionDict:
             return self.collisionDict[name]
             return self.collisionDict[name]
-        elif self.dummyDict.has_key(name):
+        elif name in self.dummyDict:
             return self.dummyDict[name]
             return self.dummyDict[name]
-        elif self.particleNodes.has_key(name):
+        elif name in self.particleNodes:
             return self.particleNodes[name]
             return self.particleNodes[name]
         elif self.lightManager.isLight(name):
         elif self.lightManager.isLight(name):
             return self.lightManager.getLightNode(name)
             return self.lightManager.getLightNode(name)
@@ -935,13 +937,13 @@ class dataHolder:
         ###########################################################################
         ###########################################################################
 
 
         ### Ask for a filename
         ### Ask for a filename
-        OpenFilename = tkFileDialog.askopenfilename(filetypes = [("PY","py")],title = "Load Scene")
+        OpenFilename = askopenfilename(filetypes = [("PY","py")],title = "Load Scene")
         if(not OpenFilename):
         if(not OpenFilename):
             return None
             return None
         f=Filename.fromOsSpecific(OpenFilename)
         f=Filename.fromOsSpecific(OpenFilename)
         fileName=f.getBasenameWoExtension()
         fileName=f.getBasenameWoExtension()
         dirName=f.getFullpathWoExtension()
         dirName=f.getFullpathWoExtension()
-        print "DATAHOLDER::" + dirName
+        print("DATAHOLDER::" + dirName)
         ############################################################################
         ############################################################################
         # Append the path to this file to our sys path where python looks for modules
         # Append the path to this file to our sys path where python looks for modules
         # We do this so that we can use "import"  on our saved scene code and execute it
         # We do this so that we can use "import"  on our saved scene code and execute it
@@ -976,7 +978,7 @@ class dataHolder:
             self.ActorDic[actor]=self.Scene.ActorDic[actor]
             self.ActorDic[actor]=self.Scene.ActorDic[actor]
             #self.ActorRefDic[actor]=self.Scene.ActorRefDic[actor] # Old way of doing absolute paths
             #self.ActorRefDic[actor]=self.Scene.ActorRefDic[actor] # Old way of doing absolute paths
             self.ActorRefDic[actor]=Filename(dirName + "/" + self.Scene.ActorRefDic[actor]) # Relative Paths
             self.ActorRefDic[actor]=Filename(dirName + "/" + self.Scene.ActorRefDic[actor]) # Relative Paths
-            if(self.Scene.blendAnimDict.has_key(str(actor))):
+            if(str(actor) in self.Scene.blendAnimDict):
                 self.blendAnimDict[actor]=self.Scene.blendAnimDict[actor]
                 self.blendAnimDict[actor]=self.Scene.blendAnimDict[actor]
             self.ActorNum=self.ActorNum+1
             self.ActorNum=self.ActorNum+1
 
 
@@ -1006,7 +1008,7 @@ class dataHolder:
                 atten=alight.getAttenuation()
                 atten=alight.getAttenuation()
                 self.lightManager.create('spot',alight.getColor(),alight.getSpecularColor(),thenode.getPos(),thenode.getHpr(),atten.getX(),atten.getY(),atten.getZ(),alight.getExponent(),name=alight.getName(),tag=thenode.getTag("Metadata"))
                 self.lightManager.create('spot',alight.getColor(),alight.getSpecularColor(),thenode.getPos(),thenode.getHpr(),atten.getX(),atten.getY(),atten.getZ(),alight.getExponent(),name=alight.getName(),tag=thenode.getTag("Metadata"))
             else:
             else:
-                print 'Invalid light type'
+                print('Invalid light type')
 
 
         ############################################################################
         ############################################################################
         # Populate Dummy related Dictionaries
         # Populate Dummy related Dictionaries

+ 2 - 2
contrib/src/sceneeditor/duplicateWindow.py

@@ -45,7 +45,7 @@ class duplicateWindow(AppShell):
         self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
         self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
 
 
     def appInit(self):
     def appInit(self):
-        print '----SideWindow is Initialized!!'
+        print('----SideWindow is Initialized!!')
 
 
     def createInterface(self):
     def createInterface(self):
         # The interior of the toplevel panel
         # The interior of the toplevel panel
@@ -122,7 +122,7 @@ class duplicateWindow(AppShell):
         # This message will be caught by sceneEditor.
         # This message will be caught by sceneEditor.
         #################################################################
         #################################################################
         if not self.allEntryValid():
         if not self.allEntryValid():
-            print '---- Duplication Window: Invalid value!!'
+            print('---- Duplication Window: Invalid value!!')
             return
             return
         x = self.move_x.getvalue()
         x = self.move_x.getvalue()
         y = self.move_y.getvalue()
         y = self.move_y.getvalue()

+ 32 - 25
contrib/src/sceneeditor/lightingPanel.py

@@ -7,9 +7,16 @@ from direct.tkwidgets.AppShell import AppShell
 from seColorEntry import *
 from seColorEntry import *
 from direct.tkwidgets.VectorWidgets import Vector3Entry
 from direct.tkwidgets.VectorWidgets import Vector3Entry
 from direct.tkwidgets.Slider import Slider
 from direct.tkwidgets.Slider import Slider
-from Tkinter import Frame, Button, Menubutton, Menu
-import string, math, types, Pmw, Tkinter
-from pandac.PandaModules import *
+import sys, math, types, Pmw
+from panda3d.core import *
+
+if sys.version_info >= (3, 0):
+    from tkinter import Frame, Button, Menubutton, Menu
+    import tkinter
+else:
+    from Tkinter import Frame, Button, Menubutton, Menu
+    import Tkinter as tkinter
+
 
 
 class lightingPanel(AppShell):
 class lightingPanel(AppShell):
     #################################################################
     #################################################################
@@ -51,25 +58,25 @@ class lightingPanel(AppShell):
         mainFrame = Frame(interior)
         mainFrame = Frame(interior)
 
 
         self.listZone = Pmw.Group(mainFrame,tag_pyclass = None)
         self.listZone = Pmw.Group(mainFrame,tag_pyclass = None)
-        self.listZone.pack(expand=0, fill=Tkinter.X,padx=3,pady=3)
+        self.listZone.pack(expand=0, fill=tkinter.X,padx=3,pady=3)
         listFrame = self.listZone.interior()
         listFrame = self.listZone.interior()
 
 
         self.lightEntry = self.createcomponent(
         self.lightEntry = self.createcomponent(
             'Lights List', (), None,
             'Lights List', (), None,
             Pmw.ComboBox, (listFrame,),label_text='Light :',
             Pmw.ComboBox, (listFrame,),label_text='Light :',
-            labelpos = Tkinter.W, entry_width = 25, selectioncommand = self.selectLight,
+            labelpos = tkinter.W, entry_width = 25, selectioncommand = self.selectLight,
             scrolledlist_items = self.lightList)
             scrolledlist_items = self.lightList)
-        self.lightEntry.pack(side=Tkinter.LEFT)
+        self.lightEntry.pack(side=tkinter.LEFT)
 
 
         self.renameButton = self.createcomponent(
         self.renameButton = self.createcomponent(
             'Rename Light', (), None,
             'Rename Light', (), None,
             Button, (listFrame,),
             Button, (listFrame,),
             text = ' Rename ',
             text = ' Rename ',
             command = self.renameLight)
             command = self.renameLight)
-        self.renameButton.pack(side=Tkinter.LEFT)
+        self.renameButton.pack(side=tkinter.LEFT)
 
 
         self.addLighZone = Pmw.Group(listFrame,tag_pyclass = None)
         self.addLighZone = Pmw.Group(listFrame,tag_pyclass = None)
-        self.addLighZone.pack(side=Tkinter.LEFT)
+        self.addLighZone.pack(side=tkinter.LEFT)
         insideFrame = self.addLighZone.interior()
         insideFrame = self.addLighZone.interior()
         self.lightsButton = Menubutton(insideFrame, text = 'Add light',borderwidth = 3,
         self.lightsButton = Menubutton(insideFrame, text = 'Add light',borderwidth = 3,
                                        activebackground = '#909090')
                                        activebackground = '#909090')
@@ -91,13 +98,13 @@ class lightingPanel(AppShell):
             Button, (listFrame,),
             Button, (listFrame,),
             text = '  Delete  ',
             text = '  Delete  ',
             command = self.deleteLight)
             command = self.deleteLight)
-        self.deleteButton.pack(side=Tkinter.LEFT)
+        self.deleteButton.pack(side=tkinter.LEFT)
 
 
         self.lightColor = seColorEntry(
         self.lightColor = seColorEntry(
             mainFrame, text = 'Light Color', value=self.lightColor)
             mainFrame, text = 'Light Color', value=self.lightColor)
         self.lightColor['command'] = self.setLightingColorVec
         self.lightColor['command'] = self.setLightingColorVec
         self.lightColor['resetValue'] = [0.3*255,0.3*255,0.3*255,0]
         self.lightColor['resetValue'] = [0.3*255,0.3*255,0.3*255,0]
-        self.lightColor.pack(fill=Tkinter.X,expand=0)
+        self.lightColor.pack(fill=tkinter.X,expand=0)
         self.bind(self.lightColor, 'Set light color')
         self.bind(self.lightColor, 'Set light color')
 
 
         # Notebook pages for light specific controls
         # Notebook pages for light specific controls
@@ -114,27 +121,27 @@ class lightingPanel(AppShell):
         self.dSpecularColor = seColorEntry(
         self.dSpecularColor = seColorEntry(
             directionalPage, text = 'Specular Color')
             directionalPage, text = 'Specular Color')
         self.dSpecularColor['command'] = self.setSpecularColor
         self.dSpecularColor['command'] = self.setSpecularColor
-        self.dSpecularColor.pack(fill = Tkinter.X, expand = 0)
+        self.dSpecularColor.pack(fill = tkinter.X, expand = 0)
         self.bind(self.dSpecularColor,
         self.bind(self.dSpecularColor,
                   'Set directional light specular color')
                   'Set directional light specular color')
         self.dPosition = Vector3Entry(
         self.dPosition = Vector3Entry(
             directionalPage, text = 'Position')
             directionalPage, text = 'Position')
         self.dPosition['command'] = self.setPosition
         self.dPosition['command'] = self.setPosition
         self.dPosition['resetValue'] = [0,0,0,0]
         self.dPosition['resetValue'] = [0,0,0,0]
-        self.dPosition.pack(fill = Tkinter.X, expand = 0)
+        self.dPosition.pack(fill = tkinter.X, expand = 0)
         self.bind(self.dPosition, 'Set directional light position')
         self.bind(self.dPosition, 'Set directional light position')
         self.dOrientation = Vector3Entry(
         self.dOrientation = Vector3Entry(
             directionalPage, text = 'Orientation')
             directionalPage, text = 'Orientation')
         self.dOrientation['command'] = self.setOrientation
         self.dOrientation['command'] = self.setOrientation
         self.dOrientation['resetValue'] = [0,0,0,0]
         self.dOrientation['resetValue'] = [0,0,0,0]
-        self.dOrientation.pack(fill = Tkinter.X, expand = 0)
+        self.dOrientation.pack(fill = tkinter.X, expand = 0)
         self.bind(self.dOrientation, 'Set directional light orientation')
         self.bind(self.dOrientation, 'Set directional light orientation')
 
 
         # Point light controls
         # Point light controls
         self.pSpecularColor = seColorEntry(
         self.pSpecularColor = seColorEntry(
             pointPage, text = 'Specular Color')
             pointPage, text = 'Specular Color')
         self.pSpecularColor['command'] = self.setSpecularColor
         self.pSpecularColor['command'] = self.setSpecularColor
-        self.pSpecularColor.pack(fill = Tkinter.X, expand = 0)
+        self.pSpecularColor.pack(fill = tkinter.X, expand = 0)
         self.bind(self.pSpecularColor,
         self.bind(self.pSpecularColor,
                   'Set point light specular color')
                   'Set point light specular color')
 
 
@@ -142,7 +149,7 @@ class lightingPanel(AppShell):
             pointPage, text = 'Position')
             pointPage, text = 'Position')
         self.pPosition['command'] = self.setPosition
         self.pPosition['command'] = self.setPosition
         self.pPosition['resetValue'] = [0,0,0,0]
         self.pPosition['resetValue'] = [0,0,0,0]
-        self.pPosition.pack(fill = Tkinter.X, expand = 0)
+        self.pPosition.pack(fill = tkinter.X, expand = 0)
         self.bind(self.pPosition, 'Set point light position')
         self.bind(self.pPosition, 'Set point light position')
 
 
         self.pConstantAttenuation = Slider(
         self.pConstantAttenuation = Slider(
@@ -152,7 +159,7 @@ class lightingPanel(AppShell):
             resolution = 0.01,
             resolution = 0.01,
             value = 1.0)
             value = 1.0)
         self.pConstantAttenuation['command'] = self.setConstantAttenuation
         self.pConstantAttenuation['command'] = self.setConstantAttenuation
-        self.pConstantAttenuation.pack(fill = Tkinter.X, expand = 0)
+        self.pConstantAttenuation.pack(fill = tkinter.X, expand = 0)
         self.bind(self.pConstantAttenuation,
         self.bind(self.pConstantAttenuation,
                   'Set point light constant attenuation')
                   'Set point light constant attenuation')
 
 
@@ -163,7 +170,7 @@ class lightingPanel(AppShell):
             resolution = 0.01,
             resolution = 0.01,
             value = 0.0)
             value = 0.0)
         self.pLinearAttenuation['command'] = self.setLinearAttenuation
         self.pLinearAttenuation['command'] = self.setLinearAttenuation
-        self.pLinearAttenuation.pack(fill = Tkinter.X, expand = 0)
+        self.pLinearAttenuation.pack(fill = tkinter.X, expand = 0)
         self.bind(self.pLinearAttenuation,
         self.bind(self.pLinearAttenuation,
                   'Set point light linear attenuation')
                   'Set point light linear attenuation')
 
 
@@ -174,7 +181,7 @@ class lightingPanel(AppShell):
             resolution = 0.01,
             resolution = 0.01,
             value = 0.0)
             value = 0.0)
         self.pQuadraticAttenuation['command'] = self.setQuadraticAttenuation
         self.pQuadraticAttenuation['command'] = self.setQuadraticAttenuation
-        self.pQuadraticAttenuation.pack(fill = Tkinter.X, expand = 0)
+        self.pQuadraticAttenuation.pack(fill = tkinter.X, expand = 0)
         self.bind(self.pQuadraticAttenuation,
         self.bind(self.pQuadraticAttenuation,
                   'Set point light quadratic attenuation')
                   'Set point light quadratic attenuation')
 
 
@@ -182,7 +189,7 @@ class lightingPanel(AppShell):
         self.sSpecularColor = seColorEntry(
         self.sSpecularColor = seColorEntry(
             spotPage, text = 'Specular Color')
             spotPage, text = 'Specular Color')
         self.sSpecularColor['command'] = self.setSpecularColor
         self.sSpecularColor['command'] = self.setSpecularColor
-        self.sSpecularColor.pack(fill = Tkinter.X, expand = 0)
+        self.sSpecularColor.pack(fill = tkinter.X, expand = 0)
         self.bind(self.sSpecularColor,
         self.bind(self.sSpecularColor,
                   'Set spot light specular color')
                   'Set spot light specular color')
 
 
@@ -193,7 +200,7 @@ class lightingPanel(AppShell):
             resolution = 0.01,
             resolution = 0.01,
             value = 1.0)
             value = 1.0)
         self.sConstantAttenuation['command'] = self.setConstantAttenuation
         self.sConstantAttenuation['command'] = self.setConstantAttenuation
-        self.sConstantAttenuation.pack(fill = Tkinter.X, expand = 0)
+        self.sConstantAttenuation.pack(fill = tkinter.X, expand = 0)
         self.bind(self.sConstantAttenuation,
         self.bind(self.sConstantAttenuation,
                   'Set spot light constant attenuation')
                   'Set spot light constant attenuation')
 
 
@@ -204,7 +211,7 @@ class lightingPanel(AppShell):
             resolution = 0.01,
             resolution = 0.01,
             value = 0.0)
             value = 0.0)
         self.sLinearAttenuation['command'] = self.setLinearAttenuation
         self.sLinearAttenuation['command'] = self.setLinearAttenuation
-        self.sLinearAttenuation.pack(fill = Tkinter.X, expand = 0)
+        self.sLinearAttenuation.pack(fill = tkinter.X, expand = 0)
         self.bind(self.sLinearAttenuation,
         self.bind(self.sLinearAttenuation,
                   'Set spot light linear attenuation')
                   'Set spot light linear attenuation')
 
 
@@ -215,7 +222,7 @@ class lightingPanel(AppShell):
             resolution = 0.01,
             resolution = 0.01,
             value = 0.0)
             value = 0.0)
         self.sQuadraticAttenuation['command'] = self.setQuadraticAttenuation
         self.sQuadraticAttenuation['command'] = self.setQuadraticAttenuation
-        self.sQuadraticAttenuation.pack(fill = Tkinter.X, expand = 0)
+        self.sQuadraticAttenuation.pack(fill = tkinter.X, expand = 0)
         self.bind(self.sQuadraticAttenuation,
         self.bind(self.sQuadraticAttenuation,
                   'Set spot light quadratic attenuation')
                   'Set spot light quadratic attenuation')
 
 
@@ -226,16 +233,16 @@ class lightingPanel(AppShell):
             resolution = 0.01,
             resolution = 0.01,
             value = 0.0)
             value = 0.0)
         self.sExponent['command'] = self.setExponent
         self.sExponent['command'] = self.setExponent
-        self.sExponent.pack(fill = Tkinter.X, expand = 0)
+        self.sExponent.pack(fill = tkinter.X, expand = 0)
         self.bind(self.sExponent,
         self.bind(self.sExponent,
                   'Set spot light exponent')
                   'Set spot light exponent')
 
 
         # MRM: Add frustum controls
         # MRM: Add frustum controls
 
 
         self.lightNotebook.setnaturalsize()
         self.lightNotebook.setnaturalsize()
-        self.lightNotebook.pack(expand = 1, fill = Tkinter.BOTH)
+        self.lightNotebook.pack(expand = 1, fill = tkinter.BOTH)
 
 
-        mainFrame.pack(expand=1, fill = Tkinter.BOTH)
+        mainFrame.pack(expand=1, fill = tkinter.BOTH)
 
 
     def onDestroy(self, event):
     def onDestroy(self, event):
         messenger.send('LP_close')
         messenger.send('LP_close')

+ 4 - 5
contrib/src/sceneeditor/propertyWindow.py

@@ -11,8 +11,7 @@ from direct.tkwidgets import Floater
 from direct.tkwidgets import Dial
 from direct.tkwidgets import Dial
 from direct.tkwidgets import Slider
 from direct.tkwidgets import Slider
 from direct.tkwidgets import VectorWidgets
 from direct.tkwidgets import VectorWidgets
-from pandac.PandaModules import *
-from Tkinter import *
+from panda3d.core import *
 import Pmw
 import Pmw
 
 
 class propertyWindow(AppShell,Pmw.MegaWidget):
 class propertyWindow(AppShell,Pmw.MegaWidget):
@@ -108,7 +107,7 @@ class propertyWindow(AppShell,Pmw.MegaWidget):
 
 
         self.curveFrame = None
         self.curveFrame = None
         #### If nodePath has been binded with any curves
         #### If nodePath has been binded with any curves
-        if self.info.has_key('curveList'):
+        if 'curveList' in self.info:
             self.createCurveFrame(self.contentFrame)
             self.createCurveFrame(self.contentFrame)
 
 
         ## Set all stuff done
         ## Set all stuff done
@@ -271,7 +270,7 @@ class propertyWindow(AppShell,Pmw.MegaWidget):
         # And, it will set the call back function to setNodeColorVec()
         # And, it will set the call back function to setNodeColorVec()
         #################################################################
         #################################################################
         color = self.nodePath.getColor()
         color = self.nodePath.getColor()
-        print color
+        print(color)
         self.nodeColor = VectorWidgets.ColorEntry(
         self.nodeColor = VectorWidgets.ColorEntry(
             contentFrame, text = 'Node Color', value=[color.getX()*255,
             contentFrame, text = 'Node Color', value=[color.getX()*255,
                                                       color.getY()*255,
                                                       color.getY()*255,
@@ -725,7 +724,7 @@ class propertyWindow(AppShell,Pmw.MegaWidget):
         # But, not directly removed be this function.
         # But, not directly removed be this function.
         # This function will send out a message to notice dataHolder to remove this animation
         # This function will send out a message to notice dataHolder to remove this animation
         #################################################################
         #################################################################
-        print anim
+        print(anim)
         widget = self.widgetsDict[anim]
         widget = self.widgetsDict[anim]
         self.accept('animRemovedFromNode',self.redrawAnimProperty)
         self.accept('animRemovedFromNode',self.redrawAnimProperty)
         messenger.send('PW_removeAnimFromNode',[self.name, anim])
         messenger.send('PW_removeAnimFromNode',[self.name, anim])

+ 6 - 8
contrib/src/sceneeditor/quad.py

@@ -9,10 +9,8 @@
 from direct.showbase.ShowBaseGlobal import *
 from direct.showbase.ShowBaseGlobal import *
 from direct.interval.IntervalGlobal import *
 from direct.interval.IntervalGlobal import *
 from direct.showbase.DirectObject import DirectObject
 from direct.showbase.DirectObject import DirectObject
-from pandac.PandaModules import *
+from panda3d.core import *
 import math
 import math
-#Manakel 2/12/2005: replace from pandac import by from pandac.PandaModules import
-from pandac.PandaModules import MouseWatcher
 
 
 
 
 class ViewPort:
 class ViewPort:
@@ -506,7 +504,7 @@ class QuadView(DirectObject):
             ansY=-1.0+y2
             ansY=-1.0+y2
 
 
         self.xy=[ansX,ansY]
         self.xy=[ansX,ansY]
-        print "Sent X:%f Sent Y:%f"%(ansX,ansY)
+        print("Sent X:%f Sent Y:%f"%(ansX,ansY))
         #SEditor.iRay.pick(render,self.xy)
         #SEditor.iRay.pick(render,self.xy)
         SEditor.manipulationControl.manipulationStop(self.xy)
         SEditor.manipulationControl.manipulationStop(self.xy)
         #print "MouseX " + str(base.mouseWatcherNode.getMouseX()) + "MouseY " + str(base.mouseWatcherNode.getMouseY()) + "\n"
         #print "MouseX " + str(base.mouseWatcherNode.getMouseX()) + "MouseY " + str(base.mouseWatcherNode.getMouseY()) + "\n"
@@ -550,28 +548,28 @@ class QuadView(DirectObject):
             dr.setDimensions(0.5,1,0,0.5)
             dr.setDimensions(0.5,1,0,0.5)
 
 
     def setLeft(self):
     def setLeft(self):
-        print "LEFT"
+        print("LEFT")
         self.CurrentQuad=3
         self.CurrentQuad=3
         self.ChangeBaseDR()
         self.ChangeBaseDR()
         self.Left.setCam()
         self.Left.setCam()
         #self.Left.setDR(self.mouseWatcherNode)
         #self.Left.setDR(self.mouseWatcherNode)
 
 
     def setTop(self):
     def setTop(self):
-        print "TOP"
+        print("TOP")
         self.CurrentQuad=2
         self.CurrentQuad=2
         self.ChangeBaseDR()
         self.ChangeBaseDR()
         self.Top.setCam()
         self.Top.setCam()
         #self.Top.setDR(self.mouseWatcherNode)
         #self.Top.setDR(self.mouseWatcherNode)
 
 
     def setPerspective(self):
     def setPerspective(self):
-        print "PERSPECTIVE"
+        print("PERSPECTIVE")
         self.CurrentQuad=4
         self.CurrentQuad=4
         self.ChangeBaseDR()
         self.ChangeBaseDR()
         self.Perspective.setCam()
         self.Perspective.setCam()
         #self.Perspective.setDR(self.mouseWatcherNode)
         #self.Perspective.setDR(self.mouseWatcherNode)
 
 
     def setFront(self):
     def setFront(self):
-        print "FRONT"
+        print("FRONT")
         self.CurrentQuad=1
         self.CurrentQuad=1
         self.ChangeBaseDR()
         self.ChangeBaseDR()
         self.Front.setCam()
         self.Front.setCam()

+ 48 - 37
contrib/src/sceneeditor/sceneEditor.py

@@ -3,11 +3,19 @@ import sys
 try: import _tkinter
 try: import _tkinter
 except: sys.exit("Please install python module 'Tkinter'")
 except: sys.exit("Please install python module 'Tkinter'")
 
 
-import direct
-from direct.directbase.DirectStart import*
+from direct.showbase.ShowBase import ShowBase
+
+ShowBase()
+
 from direct.showbase.TkGlobal import spawnTkLoop
 from direct.showbase.TkGlobal import spawnTkLoop
-from Tkinter import *
-from tkFileDialog import *
+
+if sys.version_info >= (3, 0):
+    from tkinter import *
+    from tkinter.filedialog import *
+else:
+    from Tkinter import *
+    from tkFileDialog import *
+
 from direct.directtools.DirectGlobals import *
 from direct.directtools.DirectGlobals import *
 from direct.tkwidgets.AppShell import*
 from direct.tkwidgets.AppShell import*
 
 
@@ -251,7 +259,10 @@ class myLevelEditor(AppShell):
         for event in self.actionEvents:
         for event in self.actionEvents:
             self.accept(event[0], event[1], extraArgs = event[2:])
             self.accept(event[0], event[1], extraArgs = event[2:])
 
 
-        camera.toggleVis()
+        if camera.is_hidden():
+            camera.show()
+        else:
+            camera.hide()
         self.selectNode(base.camera) ## Initially, we select camera as the first node...
         self.selectNode(base.camera) ## Initially, we select camera as the first node...
 
 
     def appInit(self):
     def appInit(self):
@@ -386,31 +397,31 @@ class myLevelEditor(AppShell):
             self.showAbout()
             self.showAbout()
             return
             return
         elif buttonIndex==12:
         elif buttonIndex==12:
-            print "You haven't defined the function for this Button, Number %d."%buttonIndex
+            print("You haven't defined the function for this Button, Number %d."%buttonIndex)
             return
             return
         elif buttonIndex==13:
         elif buttonIndex==13:
-            print "You haven't defined the function for this Button, Number %d."%buttonIndex
+            print("You haven't defined the function for this Button, Number %d."%buttonIndex)
             return
             return
         elif buttonIndex==14:
         elif buttonIndex==14:
-            print "You haven't defined the function for this Button, Number %d."%buttonIndex
+            print("You haven't defined the function for this Button, Number %d."%buttonIndex)
             return
             return
         elif buttonIndex==15:
         elif buttonIndex==15:
-            print "You haven't defined the function for this Button, Number %d."%buttonIndex
+            print("You haven't defined the function for this Button, Number %d."%buttonIndex)
             return
             return
         elif buttonIndex==16:
         elif buttonIndex==16:
-            print "Your scene will be eliminated within five seconds, Save your world!!!, Number %d."%buttonIndex
+            print("Your scene will be eliminated within five seconds, Save your world!!!, Number %d."%buttonIndex)
             return
             return
         elif buttonIndex==17:
         elif buttonIndex==17:
-            print "You haven't defined the function for this Button, Number %d."%buttonIndex
+            print("You haven't defined the function for this Button, Number %d."%buttonIndex)
             return
             return
         elif buttonIndex==18:
         elif buttonIndex==18:
-            print "You haven't defined the function for this Button, Number %d."%buttonIndex
+            print("You haven't defined the function for this Button, Number %d."%buttonIndex)
             return
             return
         elif buttonIndex==19:
         elif buttonIndex==19:
-            print "You haven't defined the function for this Button, Number %d."%buttonIndex
+            print("You haven't defined the function for this Button, Number %d."%buttonIndex)
             return
             return
         elif buttonIndex==20:
         elif buttonIndex==20:
-            print "You haven't defined the function for this Button, Number %d."%buttonIndex
+            print("You haven't defined the function for this Button, Number %d."%buttonIndex)
             return
             return
 
 
         return
         return
@@ -666,17 +677,17 @@ class myLevelEditor(AppShell):
         #################################################################
         #################################################################
         type, info = AllScene.getInfoOfThisNode(nodePath)
         type, info = AllScene.getInfoOfThisNode(nodePath)
         name = nodePath.getName()
         name = nodePath.getName()
-        if not self.propertyWindow.has_key(name):
+        if name not in self.propertyWindow:
             self.propertyWindow[name] = propertyWindow(nodePath, type,info )
             self.propertyWindow[name] = propertyWindow(nodePath, type,info )
         pass
         pass
 
 
     def closePropertyWindow(self, name):
     def closePropertyWindow(self, name):
-        if self.propertyWindow.has_key(name):
+        if name in self.propertyWindow:
             del self.propertyWindow[name]
             del self.propertyWindow[name]
         return
         return
 
 
     def openMetadataPanel(self,nodePath=None):
     def openMetadataPanel(self,nodePath=None):
-        print nodePath
+        print(nodePath)
         self.MetadataPanel=MetadataPanel(nodePath)
         self.MetadataPanel=MetadataPanel(nodePath)
         pass
         pass
 
 
@@ -685,7 +696,7 @@ class myLevelEditor(AppShell):
         # duplicate(self, nodePath = None)
         # duplicate(self, nodePath = None)
         # This function will be called when user try to open the duplication window
         # This function will be called when user try to open the duplication window
         #################################################################
         #################################################################
-        print '----Duplication!!'
+        print('----Duplication!!')
         if nodePath != None:
         if nodePath != None:
             self.duplicateWindow = duplicateWindow(nodePath = nodePath)
             self.duplicateWindow = duplicateWindow(nodePath = nodePath)
         pass
         pass
@@ -791,8 +802,8 @@ class myLevelEditor(AppShell):
         #################################################################
         #################################################################
         name = nodePath.getName()
         name = nodePath.getName()
         if AllScene.isActor(name):
         if AllScene.isActor(name):
-            if self.animPanel.has_key(name):
-                print '---- You already have an animation panel for this Actor!'
+            if name in self.animPanel:
+                print('---- You already have an animation panel for this Actor!')
                 return
                 return
             else:
             else:
                 Actor = AllScene.getActor(name)
                 Actor = AllScene.getActor(name)
@@ -842,9 +853,9 @@ class myLevelEditor(AppShell):
             # Let us actually remove the scene from sys modules... this is done because every scene is loaded as a module
             # Let us actually remove the scene from sys modules... this is done because every scene is loaded as a module
             # And if we reload a scene python wont reload since its already in sys.modules... and hence we delete it
             # And if we reload a scene python wont reload since its already in sys.modules... and hence we delete it
             # If there is ever a garbage colleciton bug..this might be a point to look at
             # If there is ever a garbage colleciton bug..this might be a point to look at
-            if sys.modules.has_key(currentModName):
+            if currentModName in sys.modules:
                 del sys.modules[currentModName]
                 del sys.modules[currentModName]
-                print sys.getrefcount(AllScene.theScene)
+                print(sys.getrefcount(AllScene.theScene))
                 del AllScene.theScene
                 del AllScene.theScene
         else:
         else:
             AllScene.resetAll()
             AllScene.resetAll()
@@ -872,9 +883,9 @@ class myLevelEditor(AppShell):
             # Let us actually remove the scene from sys modules... this is done because every scene is loaded as a module
             # Let us actually remove the scene from sys modules... this is done because every scene is loaded as a module
             # And if we reload a scene python wont reload since its already in sys.modules... and hence we delete it
             # And if we reload a scene python wont reload since its already in sys.modules... and hence we delete it
             # If there is ever a garbage colleciton bug..this might be a point to look at
             # If there is ever a garbage colleciton bug..this might be a point to look at
-            if sys.modules.has_key(currentModName):
+            if currentModName in sys.modules:
                 del sys.modules[currentModName]
                 del sys.modules[currentModName]
-                print sys.getrefcount(AllScene.theScene)
+                print(sys.getrefcount(AllScene.theScene))
                 del AllScene.theScene
                 del AllScene.theScene
         else:
         else:
             AllScene.resetAll()
             AllScene.resetAll()
@@ -886,7 +897,7 @@ class myLevelEditor(AppShell):
 
 
         thefile=Filename(self.CurrentFileName)
         thefile=Filename(self.CurrentFileName)
         thedir=thefile.getFullpathWoExtension()
         thedir=thefile.getFullpathWoExtension()
-        print "SCENE EDITOR::" + thedir
+        print("SCENE EDITOR::" + thedir)
         self.CurrentDirName=thedir
         self.CurrentDirName=thedir
         if self.CurrentFileName != None:
         if self.CurrentFileName != None:
             self.parent.title('Scene Editor - '+ Filename.fromOsSpecific(self.CurrentFileName).getBasenameWoExtension())
             self.parent.title('Scene Editor - '+ Filename.fromOsSpecific(self.CurrentFileName).getBasenameWoExtension())
@@ -934,7 +945,7 @@ class myLevelEditor(AppShell):
             theScene.writeBamFile(fileName)
             theScene.writeBamFile(fileName)
         else:
         else:
             render.writeBamFile(fileName+".bad")
             render.writeBamFile(fileName+".bad")
-        print " Scenegraph saved as :" +str(fileName)
+        print(" Scenegraph saved as :" +str(fileName))
 
 
     def loadFromBam(self):
     def loadFromBam(self):
         fileName = tkFileDialog.askopenfilename(filetypes = [("BAM",".bam")],title = "Load Scenegraph from Bam file")
         fileName = tkFileDialog.askopenfilename(filetypes = [("BAM",".bam")],title = "Load Scenegraph from Bam file")
@@ -959,7 +970,7 @@ class myLevelEditor(AppShell):
         ###############################################################################
         ###############################################################################
         # !!!!! See if a module exists by this name... if it does you cannot use this filename !!!!!
         # !!!!! See if a module exists by this name... if it does you cannot use this filename !!!!!
         ###############################################################################
         ###############################################################################
-        if(sys.modules.has_key(fCheck.getBasenameWoExtension())):
+        if(fCheck.getBasenameWoExtension() in sys.modules):
             tkMessageBox.showwarning(
             tkMessageBox.showwarning(
             "Save file",
             "Save file",
             "Cannot save with this name because there is a system module with the same name. Please resave as something else."
             "Cannot save with this name because there is a system module with the same name. Please resave as something else."
@@ -993,7 +1004,7 @@ class myLevelEditor(AppShell):
         if modelFilename:
         if modelFilename:
             self.makeDirty()
             self.makeDirty()
             if not AllScene.loadModel(modelFilename, Filename.fromOsSpecific(modelFilename)):
             if not AllScene.loadModel(modelFilename, Filename.fromOsSpecific(modelFilename)):
-                print '----Error! No Such Model File!'
+                print('----Error! No Such Model File!')
         pass
         pass
 
 
     def loadActor(self):
     def loadActor(self):
@@ -1016,12 +1027,12 @@ class myLevelEditor(AppShell):
         if ActorFilename:
         if ActorFilename:
             self.makeDirty()
             self.makeDirty()
             if not AllScene.loadActor(ActorFilename, Filename.fromOsSpecific(ActorFilename)):
             if not AllScene.loadActor(ActorFilename, Filename.fromOsSpecific(ActorFilename)):
-                print '----Error! No Such Model File!'
+                print('----Error! No Such Model File!')
         pass
         pass
 
 
     def importScene(self):
     def importScene(self):
         self.makeDirty()
         self.makeDirty()
-        print '----God bless you Please Import!'
+        print('----God bless you Please Import!')
         pass
         pass
 
 
 
 
@@ -1495,7 +1506,7 @@ class myLevelEditor(AppShell):
         return
         return
 
 
     def animPanelClose(self, name):
     def animPanelClose(self, name):
-        if self.animPanel.has_key(name):
+        if name in self.animPanel:
             del self.animPanel[name]
             del self.animPanel[name]
         return
         return
 
 
@@ -1508,8 +1519,8 @@ class myLevelEditor(AppShell):
         ################################################################
         ################################################################
         name = nodePath.getName()
         name = nodePath.getName()
         if AllScene.isActor(name):
         if AllScene.isActor(name):
-            if self.animBlendPanel.has_key(name):
-                print '---- You already have an Blend Animation Panel for this Actor!'
+            if name in self.animBlendPanel:
+                print('---- You already have an Blend Animation Panel for this Actor!')
                 return
                 return
             else:
             else:
                 Actor = AllScene.getActor(name)
                 Actor = AllScene.getActor(name)
@@ -1554,7 +1565,7 @@ class myLevelEditor(AppShell):
         # This function will be called when Blend panel has been closed.
         # This function will be called when Blend panel has been closed.
         # Here we will reset the reference dictionary so it can be open again.
         # Here we will reset the reference dictionary so it can be open again.
         ################################################################
         ################################################################
-        if self.animBlendPanel.has_key(name):
+        if name in self.animBlendPanel:
             del self.animBlendPanel[name]
             del self.animBlendPanel[name]
         return
         return
 
 
@@ -1613,7 +1624,7 @@ class myLevelEditor(AppShell):
 
 
     def openAlignPanel(self, nodePath=None):
     def openAlignPanel(self, nodePath=None):
         name = nodePath.getName()
         name = nodePath.getName()
-        if not self.alignPanelDict.has_key(name):
+        if name not in self.alignPanelDict:
             list = AllScene.getAllObjNameAsList()
             list = AllScene.getAllObjNameAsList()
             if name in list:
             if name in list:
                 list.remove(name)
                 list.remove(name)
@@ -1623,7 +1634,7 @@ class myLevelEditor(AppShell):
         return
         return
 
 
     def closeAlignPanel(self, name=None):
     def closeAlignPanel(self, name=None):
-        if self.alignPanelDict.has_key(name):
+        if name in self.alignPanelDict:
             del self.alignPanelDict[name]
             del self.alignPanelDict[name]
 
 
     def alignObject(self, nodePath, name, list):
     def alignObject(self, nodePath, name, list):
@@ -1705,4 +1716,4 @@ class myLevelEditor(AppShell):
 
 
 editor = myLevelEditor(parent = base.tkRoot)
 editor = myLevelEditor(parent = base.tkRoot)
 
 
-run()
+base.run()

+ 9 - 5
contrib/src/sceneeditor/seAnimPanel.py

@@ -5,12 +5,16 @@
 # Import Tkinter, Pmw, and the floater code from this directory tree.
 # Import Tkinter, Pmw, and the floater code from this directory tree.
 from direct.tkwidgets.AppShell import *
 from direct.tkwidgets.AppShell import *
 from direct.showbase.TkGlobal import *
 from direct.showbase.TkGlobal import *
-from tkSimpleDialog import askfloat
 import string
 import string
 import math
 import math
 import types
 import types
 from direct.task import Task
 from direct.task import Task
 
 
+if sys.version_info >= (3, 0):
+    from tkinter.simpledialog import askfloat
+else:
+    from tkSimpleDialog import askfloat
+
 FRAMES = 0
 FRAMES = 0
 SECONDS = 1
 SECONDS = 1
 
 
@@ -112,7 +116,7 @@ class AnimPanel(AppShell):
         self.playRateEntry.selectitem('1.0')
         self.playRateEntry.selectitem('1.0')
 
 
         ### Loop checkbox
         ### Loop checkbox
-        Label(actorFrame, text= "Loop:", font=('MSSansSerif', 12)).place(x=420,y=05,anchor=NW)
+        Label(actorFrame, text= "Loop:", font=('MSSansSerif', 12)).place(x=420,y=5,anchor=NW)
 
 
         self.loopVar = IntVar()
         self.loopVar = IntVar()
         self.loopVar.set(0)
         self.loopVar.set(0)
@@ -250,7 +254,7 @@ class AnimPanel(AppShell):
         self['animList'] = self['actor'].getAnimNames()
         self['animList'] = self['actor'].getAnimNames()
         animL = self['actor'].getAnimNames()
         animL = self['actor'].getAnimNames()
         self.AnimEntry.setlist(animL)
         self.AnimEntry.setlist(animL)
-        print '-----',animL
+        print('-----',animL)
         return
         return
 
 
     def loadAnimation(self):
     def loadAnimation(self):
@@ -278,7 +282,7 @@ class AnimPanel(AppShell):
             taskMgr.add(self.playTask, self.id + '_UpdateTask')
             taskMgr.add(self.playTask, self.id + '_UpdateTask')
             self.stopButton.config(state=NORMAL)
             self.stopButton.config(state=NORMAL)
         else:
         else:
-            print '----Illegal Animaion name!!', self.animName
+            print('----Illegal Animaion name!!', self.animName)
         return
         return
 
 
     def playTask(self, task):
     def playTask(self, task):
@@ -591,7 +595,7 @@ class LoadAnimPanel(AppShell):
         else:
         else:
             self.animList.append(name)
             self.animList.append(name)
         self.AnimName_1.setlist(self.animList)
         self.AnimName_1.setlist(self.animList)
-        print self.animDic
+        print(self.animDic)
         return
         return
 
 
     def ok_press(self):
     def ok_press(self):

+ 9 - 5
contrib/src/sceneeditor/seBlendAnimPanel.py

@@ -5,12 +5,16 @@
 # Import Tkinter, Pmw, and the floater code from this directory tree.
 # Import Tkinter, Pmw, and the floater code from this directory tree.
 from direct.tkwidgets.AppShell import *
 from direct.tkwidgets.AppShell import *
 from direct.showbase.TkGlobal import *
 from direct.showbase.TkGlobal import *
-from tkSimpleDialog import askfloat
 import string
 import string
 import math
 import math
 import types
 import types
 from direct.task import Task
 from direct.task import Task
 
 
+if sys.version_info >= (3, 0):
+    from tkinter.simpledialog import askfloat
+else:
+    from tkSimpleDialog import askfloat
+
 FRAMES = 0
 FRAMES = 0
 SECONDS = 1
 SECONDS = 1
 
 
@@ -304,7 +308,7 @@ class BlendAnimPanel(AppShell):
             taskMgr.add(self.playTask, self.id + '_UpdateTask')
             taskMgr.add(self.playTask, self.id + '_UpdateTask')
             self.stopButton.config(state=NORMAL)
             self.stopButton.config(state=NORMAL)
         else:
         else:
-            print '----Illegal Animaion name!!', self.animNameA +  ',  '+ self.animNameB
+            print('----Illegal Animaion name!!', self.animNameA +  ',  '+ self.animNameB)
         return
         return
 
 
     def playTask(self, task):
     def playTask(self, task):
@@ -348,7 +352,7 @@ class BlendAnimPanel(AppShell):
         # setAnimation(self, animation, AB = 'a')
         # setAnimation(self, animation, AB = 'a')
         # see play(self)
         # see play(self)
         #################################################################
         #################################################################
-        print 'OK!!!'
+        print('OK!!!')
         if AB == 'a':
         if AB == 'a':
             if self.animNameA != None:
             if self.animNameA != None:
                 self['actor'].setControlEffect(self.animNameA, 1.0, 'modelRoot','lodRoot')
                 self['actor'].setControlEffect(self.animNameA, 1.0, 'modelRoot','lodRoot')
@@ -519,7 +523,7 @@ class BlendAnimPanel(AppShell):
         # then this function will set Animation A to "a" and animation B
         # then this function will set Animation A to "a" and animation B
         # to "b" and set the ratio slider to "c" position.
         # to "b" and set the ratio slider to "c" position.
         #################################################################
         #################################################################
-        if self.blendDict.has_key(name):
+        if name in self.blendDict:
             self.currentBlendName = name
             self.currentBlendName = name
             animA = self.blendDict[name][0]
             animA = self.blendDict[name][0]
             animB = self.blendDict[name][1]
             animB = self.blendDict[name][1]
@@ -544,7 +548,7 @@ class BlendAnimPanel(AppShell):
         self.blendDict.clear()
         self.blendDict.clear()
         del self.blendDict
         del self.blendDict
         self.blendDict = dict.copy()
         self.blendDict = dict.copy()
-        print self.blendDict
+        print(self.blendDict)
         if len(self.blendDict)>0:
         if len(self.blendDict)>0:
             self.blendList = self.blendDict.keys()
             self.blendList = self.blendDict.keys()
         else:
         else:

+ 10 - 11
contrib/src/sceneeditor/seCameraControl.py

@@ -55,14 +55,14 @@ class DirectCameraControl(DirectObject):
             ['n', self.pickNextCOA],
             ['n', self.pickNextCOA],
             ['u', self.orbitUprightCam],
             ['u', self.orbitUprightCam],
             ['shift-u', self.uprightCam],
             ['shift-u', self.uprightCam],
-            [`1`, self.spawnMoveToView, 1],
-            [`2`, self.spawnMoveToView, 2],
-            [`3`, self.spawnMoveToView, 3],
-            [`4`, self.spawnMoveToView, 4],
-            [`5`, self.spawnMoveToView, 5],
-            [`6`, self.spawnMoveToView, 6],
-            [`7`, self.spawnMoveToView, 7],
-            [`8`, self.spawnMoveToView, 8],
+            ['1', self.spawnMoveToView, 1],
+            ['2', self.spawnMoveToView, 2],
+            ['3', self.spawnMoveToView, 3],
+            ['4', self.spawnMoveToView, 4],
+            ['5', self.spawnMoveToView, 5],
+            ['6', self.spawnMoveToView, 6],
+            ['7', self.spawnMoveToView, 7],
+            ['8', self.spawnMoveToView, 8],
             ['9', self.swingCamAboutWidget, -90.0, t],
             ['9', self.swingCamAboutWidget, -90.0, t],
             ['0', self.swingCamAboutWidget,  90.0, t],
             ['0', self.swingCamAboutWidget,  90.0, t],
             ['`', self.removeManipulateCameraTask],
             ['`', self.removeManipulateCameraTask],
@@ -351,7 +351,7 @@ class DirectCameraControl(DirectObject):
             # MRM: Would be nice to be able to control this
             # MRM: Would be nice to be able to control this
             # At least display it
             # At least display it
             dist = pow(10.0, self.nullHitPointCount)
             dist = pow(10.0, self.nullHitPointCount)
-            SEditor.message('COA Distance: ' + `dist`)
+            SEditor.message('COA Distance: ' + repr(dist))
             coa.set(0,dist,0)
             coa.set(0,dist,0)
         # Compute COA Dist
         # Compute COA Dist
         coaDist = Vec3(coa - ZERO_POINT).length()
         coaDist = Vec3(coa - ZERO_POINT).length()
@@ -392,8 +392,7 @@ class DirectCameraControl(DirectObject):
             sf = 0.1
             sf = 0.1
         self.coaMarker.setScale(sf)
         self.coaMarker.setScale(sf)
         # Lerp color to fade out
         # Lerp color to fade out
-        self.coaMarker.lerpColor(VBase4(1,0,0,1), VBase4(1,0,0,0), 3.0,
-                                 task = 'fadeAway')
+        self.coaMarker.colorInterval(3.0, VBase4(1, 0, 0, 0), name='fadeAway').start()
 
 
     def homeCam(self):
     def homeCam(self):
         # Record undo point
         # Record undo point

+ 8 - 2
contrib/src/sceneeditor/seColorEntry.py

@@ -12,9 +12,15 @@
 from direct.tkwidgets import Valuator
 from direct.tkwidgets import Valuator
 from direct.tkwidgets import Floater
 from direct.tkwidgets import Floater
 from direct.tkwidgets import Slider
 from direct.tkwidgets import Slider
-import string, Pmw, Tkinter, tkColorChooser
+import sys, Pmw
 from direct.tkwidgets.VectorWidgets import VectorEntry
 from direct.tkwidgets.VectorWidgets import VectorEntry
 
 
+if sys.version_info >= (3, 0):
+    from tkinter.colorchooser import askcolor
+else:
+    from tkColorChooser import askcolor
+
+
 class seColorEntry(VectorEntry):
 class seColorEntry(VectorEntry):
     def __init__(self, parent = None, **kw):
     def __init__(self, parent = None, **kw):
         # Initialize options for the class (overriding some superclass options)
         # Initialize options for the class (overriding some superclass options)
@@ -41,7 +47,7 @@ class seColorEntry(VectorEntry):
 
 
     def popupColorPicker(self):
     def popupColorPicker(self):
         # Can pass in current color with: color = (255, 0, 0)
         # Can pass in current color with: color = (255, 0, 0)
-        color = tkColorChooser.askcolor(
+        color = askcolor(
             parent = self.interior(),
             parent = self.interior(),
             # Initialize it to current color
             # Initialize it to current color
             initialcolor = tuple(self.get()[:3]))[0]
             initialcolor = tuple(self.get()[:3]))[0]

+ 18 - 18
contrib/src/sceneeditor/seFileSaver.py

@@ -3,7 +3,7 @@
 # This code saves the scene out as python code... the scene is stored in the various dictionaries in "dataHolder.py" ...the class "AllScene"
 # This code saves the scene out as python code... the scene is stored in the various dictionaries in "dataHolder.py" ...the class "AllScene"
 #
 #
 ####################################################################################################################################################
 ####################################################################################################################################################
-from pandac.PandaModules import *
+from panda3d.core import *
 
 
 from direct.showbase.ShowBaseGlobal import *
 from direct.showbase.ShowBaseGlobal import *
 import os
 import os
@@ -42,7 +42,7 @@ class FileSaver:
         i1="    " # indentation
         i1="    " # indentation
         i2=i1+i1  # double indentation
         i2=i1+i1  # double indentation
         out_file = open(filename,"w")
         out_file = open(filename,"w")
-        print "dirname:" + dirname
+        print("dirname:" + dirname)
         if( not os.path.isdir(dirname)):
         if( not os.path.isdir(dirname)):
             os.mkdir(dirname)
             os.mkdir(dirname)
         savepathname=Filename(filename)
         savepathname=Filename(filename)
@@ -176,7 +176,7 @@ class FileSaver:
                     newtexpathF=Filename(newtexpath)
                     newtexpathF=Filename(newtexpath)
                     newtexpathSpecific=newtexpathF.toOsSpecific()
                     newtexpathSpecific=newtexpathF.toOsSpecific()
 
 
-                    print "TEXTURE SAVER:: copying" + oldtexpath + " to " + newtexpathSpecific
+                    print("TEXTURE SAVER:: copying" + oldtexpath + " to " + newtexpathSpecific)
                     if(oldtexpath != newtexpathSpecific):
                     if(oldtexpath != newtexpathSpecific):
                         shutil.copyfile(oldtexpath,newtexpathSpecific)
                         shutil.copyfile(oldtexpath,newtexpathSpecific)
 
 
@@ -187,7 +187,7 @@ class FileSaver:
 
 
                 # Copy the file over to the relative directory
                 # Copy the file over to the relative directory
                 oldModelpath=AllScene.ModelRefDic[model].toOsSpecific()
                 oldModelpath=AllScene.ModelRefDic[model].toOsSpecific()
-                print "FILESAVER:: copying from " + AllScene.ModelRefDic[model].toOsSpecific() + "to" + newpathSpecific
+                print("FILESAVER:: copying from " + AllScene.ModelRefDic[model].toOsSpecific() + "to" + newpathSpecific)
                 if(oldModelpath!=newpathSpecific):
                 if(oldModelpath!=newpathSpecific):
                     shutil.copyfile(oldModelpath,newpathSpecific)
                     shutil.copyfile(oldModelpath,newpathSpecific)
 
 
@@ -197,7 +197,7 @@ class FileSaver:
                 etc=EggTextureCollection()
                 etc=EggTextureCollection()
                 etc.extractTextures(e)
                 etc.extractTextures(e)
                 for index in range(len(fnamelist)):
                 for index in range(len(fnamelist)):
-                    print fnamelist[index]
+                    print(fnamelist[index])
                     tex=etc.findFilename(Filename(fnamelist[index]))
                     tex=etc.findFilename(Filename(fnamelist[index]))
                     fn=Filename(tex.getFilename())
                     fn=Filename(tex.getFilename())
                     fn.setDirname("")
                     fn.setDirname("")
@@ -305,14 +305,14 @@ class FileSaver:
                     newtexpath=dirname + "/" + texfilename.getBasename()
                     newtexpath=dirname + "/" + texfilename.getBasename()
                     newtexpathF=Filename(newtexpath)
                     newtexpathF=Filename(newtexpath)
                     newtexpathSpecific=newtexpathF.toOsSpecific()
                     newtexpathSpecific=newtexpathF.toOsSpecific()
-                    print "TEXTURE SAVER:: copying" + oldtexpath + " to " + newtexpathSpecific
+                    print("TEXTURE SAVER:: copying" + oldtexpath + " to " + newtexpathSpecific)
                     if(oldtexpath != newtexpathSpecific):
                     if(oldtexpath != newtexpathSpecific):
                         shutil.copyfile(oldtexpath,newtexpathSpecific)
                         shutil.copyfile(oldtexpath,newtexpathSpecific)
 
 
 
 
                 # Copy the file over to the relative directory
                 # Copy the file over to the relative directory
                 oldActorpath=AllScene.ActorRefDic[actor].toOsSpecific()
                 oldActorpath=AllScene.ActorRefDic[actor].toOsSpecific()
-                print "FILESAVER:: copying from " + AllScene.ActorRefDic[actor].toOsSpecific() + "to" + newpathSpecific
+                print("FILESAVER:: copying from " + AllScene.ActorRefDic[actor].toOsSpecific() + "to" + newpathSpecific)
                 if(oldActorpath!=newpathSpecific):
                 if(oldActorpath!=newpathSpecific):
                     shutil.copyfile(oldActorpath,newpathSpecific)
                     shutil.copyfile(oldActorpath,newpathSpecific)
 
 
@@ -322,7 +322,7 @@ class FileSaver:
                 etc=EggTextureCollection()
                 etc=EggTextureCollection()
                 etc.extractTextures(e)
                 etc.extractTextures(e)
                 for index in range(len(actorfnamelist)):
                 for index in range(len(actorfnamelist)):
-                    print actorfnamelist[index]
+                    print(actorfnamelist[index])
                     tex=etc.findFilename(Filename(actorfnamelist[index]))
                     tex=etc.findFilename(Filename(actorfnamelist[index]))
                     fn=Filename(tex.getFilename())
                     fn=Filename(tex.getFilename())
                     fn.setDirname("")
                     fn.setDirname("")
@@ -362,12 +362,12 @@ class FileSaver:
                         #out_file.write(i2+ "self."+ actorS + ".loadAnims(" + str(ActorAnimations) +")\n") # Old way with absolute paths
                         #out_file.write(i2+ "self."+ actorS + ".loadAnims(" + str(ActorAnimations) +")\n") # Old way with absolute paths
                         #Manakel 2/12/2004: solve the not empty but not defined animation case
                         #Manakel 2/12/2004: solve the not empty but not defined animation case
                         if not animation is None:
                         if not animation is None:
-                            print "ACTOR ANIMATIONS:" + ActorAnimations[animation]
+                            print("ACTOR ANIMATIONS:" + ActorAnimations[animation])
                             oldAnimPath=Filename(ActorAnimations[animation])
                             oldAnimPath=Filename(ActorAnimations[animation])
                             oldAnim=oldAnimPath.toOsSpecific()
                             oldAnim=oldAnimPath.toOsSpecific()
                             dirOS=Filename(dirname)
                             dirOS=Filename(dirname)
                             newAnim=dirOS.toOsSpecific() + "\\" + oldAnimPath.getBasename()
                             newAnim=dirOS.toOsSpecific() + "\\" + oldAnimPath.getBasename()
-                            print "ACTOR ANIM SAVER:: Comparing" + oldAnim +"and" + newAnim
+                            print("ACTOR ANIM SAVER:: Comparing" + oldAnim +"and" + newAnim)
                             if(oldAnim!=newAnim):
                             if(oldAnim!=newAnim):
                                 shutil.copyfile(oldAnim,newAnim)
                                 shutil.copyfile(oldAnim,newAnim)
                             newAnimF=Filename.fromOsSpecific(newAnim)
                             newAnimF=Filename.fromOsSpecific(newAnim)
@@ -379,16 +379,16 @@ class FileSaver:
                 out_file.write(i2+ i1+"self."+ actorS + ".loadAnims(" + str(ActorAnimations) +")\n") # Now with new relative paths
                 out_file.write(i2+ i1+"self."+ actorS + ".loadAnims(" + str(ActorAnimations) +")\n") # Now with new relative paths
                 out_file.write(i2+"else:\n")
                 out_file.write(i2+"else:\n")
                 theloadAnimString=str(ActorAnimationsInvoke)# We hack the "self.executionpath" part into the dictionary as a variable using string replace
                 theloadAnimString=str(ActorAnimationsInvoke)# We hack the "self.executionpath" part into the dictionary as a variable using string replace
-                print "LOAD ANIM STRING BEFORE" + theloadAnimString
+                print("LOAD ANIM STRING BEFORE" + theloadAnimString)
                 theloadAnimString=theloadAnimString.replace('\'self.executionpath +','self.executionpath + \'')
                 theloadAnimString=theloadAnimString.replace('\'self.executionpath +','self.executionpath + \'')
-                print "LOAD ANIM STRING AFTER" + theloadAnimString
+                print("LOAD ANIM STRING AFTER" + theloadAnimString)
                 out_file.write(i2+ i1+"self."+ actorS + ".loadAnims(" + theloadAnimString +")\n") # Now with new relative paths based on editor invocation
                 out_file.write(i2+ i1+"self."+ actorS + ".loadAnims(" + theloadAnimString +")\n") # Now with new relative paths based on editor invocation
 
 
                 out_file.write(i2+ "self.ActorDic[\'" + actorS + "\']=self." + AllScene.ActorDic[actor].getName()+"\n")
                 out_file.write(i2+ "self.ActorDic[\'" + actorS + "\']=self." + AllScene.ActorDic[actor].getName()+"\n")
                 #out_file.write(i2+ "self.ActorRefDic[\'" + actorS + "\']=Filename(\'"+AllScene.ActorRefDic[actor].getFullpath() +"\')\n") # Old way with absolute paths
                 #out_file.write(i2+ "self.ActorRefDic[\'" + actorS + "\']=Filename(\'"+AllScene.ActorRefDic[actor].getFullpath() +"\')\n") # Old way with absolute paths
                 out_file.write(i2+ "self.ActorRefDic[\'" + actorS + "\']=\'"+ AllScene.ActorRefDic[actor].getBasename() +"\'\n")# Relative paths
                 out_file.write(i2+ "self.ActorRefDic[\'" + actorS + "\']=\'"+ AllScene.ActorRefDic[actor].getBasename() +"\'\n")# Relative paths
                 out_file.write(i2+ "self.ActorDic[\'"+ actorS + "\'].setName(\'"+ actorS +"\')\n")
                 out_file.write(i2+ "self.ActorDic[\'"+ actorS + "\'].setName(\'"+ actorS +"\')\n")
-                if(AllScene.blendAnimDict.has_key(actor)): # Check if a dictionary of blended animations exists
+                if(actor in AllScene.blendAnimDict): # Check if a dictionary of blended animations exists
                     out_file.write(i2+ "self.blendAnimDict[\"" + actorS +"\"]=" + str(AllScene.blendAnimDict[actor]) + "\n")
                     out_file.write(i2+ "self.blendAnimDict[\"" + actorS +"\"]=" + str(AllScene.blendAnimDict[actor]) + "\n")
 
 
 
 
@@ -458,7 +458,7 @@ class FileSaver:
 
 
                 pass
                 pass
             else:
             else:
-                 print "Invalid Collision Node: " + nodetype
+                 print("Invalid Collision Node: " + nodetype)
             out_file.write("\n")
             out_file.write("\n")
 
 
 
 
@@ -653,7 +653,7 @@ class FileSaver:
             if(parent=="render" or parent=="camera"):
             if(parent=="render" or parent=="camera"):
                 out_file.write(i2+ "self."+ modelS + ".reparentTo(" + parent + ")\n")
                 out_file.write(i2+ "self."+ modelS + ".reparentTo(" + parent + ")\n")
             else:
             else:
-                if(AllScene.particleDict.has_key(parent)):
+                if(parent in AllScene.particleDict):
                     out_file.write(i2+ "self."+ modelS + ".reparentTo(self." + parent + ".getEffect())\n")
                     out_file.write(i2+ "self."+ modelS + ".reparentTo(self." + parent + ".getEffect())\n")
                 else:
                 else:
                     out_file.write(i2+ "self."+ modelS + ".reparentTo(self." + parent + ")\n")
                     out_file.write(i2+ "self."+ modelS + ".reparentTo(self." + parent + ")\n")
@@ -666,7 +666,7 @@ class FileSaver:
             if(parent=="render" or parent=="camera"):
             if(parent=="render" or parent=="camera"):
                 out_file.write(i2+ "self."+ dummyS + ".reparentTo(" + parent + ")\n")
                 out_file.write(i2+ "self."+ dummyS + ".reparentTo(" + parent + ")\n")
             else:
             else:
-                if(AllScene.particleDict.has_key(parent)):
+                if(parent in AllScene.particleDict):
                     out_file.write(i2+ "self."+ dummyS + ".reparentTo(self." + parent + ".getEffect())\n")
                     out_file.write(i2+ "self."+ dummyS + ".reparentTo(self." + parent + ".getEffect())\n")
                 else:
                 else:
                     out_file.write(i2+ "self."+ dummyS + ".reparentTo(self." + parent + ")\n")
                     out_file.write(i2+ "self."+ dummyS + ".reparentTo(self." + parent + ")\n")
@@ -680,7 +680,7 @@ class FileSaver:
             if(parent=="render" or parent=="camera"):
             if(parent=="render" or parent=="camera"):
                 out_file.write(i2+ "self."+ actorS + ".reparentTo(" + parent + ")\n")
                 out_file.write(i2+ "self."+ actorS + ".reparentTo(" + parent + ")\n")
             else:
             else:
-                if(AllScene.particleDict.has_key(parent)):
+                if(parent in AllScene.particleDict):
                     out_file.write(i2+ "self."+ actorS + ".reparentTo(self." + parent + ".getEffect())\n")
                     out_file.write(i2+ "self."+ actorS + ".reparentTo(self." + parent + ".getEffect())\n")
                 else:
                 else:
                     out_file.write(i2+ "self."+ actorS + ".reparentTo(self." + parent + ")\n")
                     out_file.write(i2+ "self."+ actorS + ".reparentTo(self." + parent + ")\n")
@@ -698,7 +698,7 @@ class FileSaver:
                 out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"]="+ parentname + ".attachNewNode(self." + collnodeS + "_Node)\n")
                 out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"]="+ parentname + ".attachNewNode(self." + collnodeS + "_Node)\n")
             else:
             else:
                 #Manakel 2/12/2005: parent replaced by parent Name but why Parent name in partice and parent for other objects?
                 #Manakel 2/12/2005: parent replaced by parent Name but why Parent name in partice and parent for other objects?
-                if(AllScene.particleDict.has_key(parentname)):
+                if(parentname in AllScene.particleDict):
                     out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"]=self."+ parentname + "getEffect().attachNewNode(self." + collnodeS + "_Node)\n")
                     out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"]=self."+ parentname + "getEffect().attachNewNode(self." + collnodeS + "_Node)\n")
                 else:
                 else:
                     out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"]=self."+ parentname + ".attachNewNode(self." + collnodeS + "_Node)\n")
                     out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"]=self."+ parentname + ".attachNewNode(self." + collnodeS + "_Node)\n")

+ 1 - 3
contrib/src/sceneeditor/seForceGroup.py

@@ -1,8 +1,6 @@
-from pandac.PandaModules import *
+from panda3d.core import *
 from direct.showbase.DirectObject import DirectObject
 from direct.showbase.DirectObject import DirectObject
 from direct.showbase.PhysicsManagerGlobal import *
 from direct.showbase.PhysicsManagerGlobal import *
-#Manakel 2/12/2005: replace from pandac import by from pandac.PandaModules import
-from pandac.PandaModules import ForceNode
 from direct.directnotify import DirectNotifyGlobal
 from direct.directnotify import DirectNotifyGlobal
 import sys
 import sys
 
 

+ 8 - 8
contrib/src/sceneeditor/seGeometry.py

@@ -12,7 +12,7 @@
 #
 #
 #################################################################
 #################################################################
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
 from direct.directtools.DirectGlobals import *
 from direct.directtools.DirectGlobals import *
 from direct.directtools.DirectUtil import *
 from direct.directtools.DirectUtil import *
 import math
 import math
@@ -41,10 +41,10 @@ class LineNodePath(NodePath):
         ls.setColor(colorVec)
         ls.setColor(colorVec)
 
 
     def moveTo( self, *_args ):
     def moveTo( self, *_args ):
-        apply( self.lineSegs.moveTo, _args )
+        self.lineSegs.moveTo(*_args)
 
 
     def drawTo( self, *_args ):
     def drawTo( self, *_args ):
-        apply( self.lineSegs.drawTo, _args )
+        self.lineSegs.drawTo(*_args)
 
 
     def create( self, frameAccurate = 0 ):
     def create( self, frameAccurate = 0 ):
         self.lineSegs.create( self.lineNode, frameAccurate )
         self.lineSegs.create( self.lineNode, frameAccurate )
@@ -60,13 +60,13 @@ class LineNodePath(NodePath):
         self.lineSegs.setThickness( thickness )
         self.lineSegs.setThickness( thickness )
 
 
     def setColor( self, *_args ):
     def setColor( self, *_args ):
-        apply( self.lineSegs.setColor, _args )
+        self.lineSegs.setColor(*_args)
 
 
     def setVertex( self, *_args):
     def setVertex( self, *_args):
-        apply( self.lineSegs.setVertex, _args )
+        self.lineSegs.setVertex(*_args)
 
 
     def setVertexColor( self, vertex, *_args ):
     def setVertexColor( self, vertex, *_args ):
-        apply( self.lineSegs.setVertexColor, (vertex,) + _args )
+        self.lineSegs.setVertexColor(*(vertex,) + _args)
 
 
     def getCurrentPosition( self ):
     def getCurrentPosition( self ):
         return self.lineSegs.getCurrentPosition()
         return self.lineSegs.getCurrentPosition()
@@ -132,9 +132,9 @@ class LineNodePath(NodePath):
         Given a list of lists of points, draw a separate line for each list
         Given a list of lists of points, draw a separate line for each list
         """
         """
         for pointList in lineList:
         for pointList in lineList:
-            apply(self.moveTo, pointList[0])
+            self.moveTo(*pointList[0])
             for point in pointList[1:]:
             for point in pointList[1:]:
-                apply(self.drawTo, point)
+                self.drawTo(*point)
 
 
 ##
 ##
 ## Given a point in space, and a direction, find the point of intersection
 ## Given a point in space, and a direction, find the point of intersection

+ 10 - 11
contrib/src/sceneeditor/seLights.py

@@ -3,9 +3,8 @@
 # Written by Yi-Hong Lin, [email protected], 2004
 # Written by Yi-Hong Lin, [email protected], 2004
 #################################################################
 #################################################################
 from direct.showbase.DirectObject import *
 from direct.showbase.DirectObject import *
-from string import lower
 from direct.directtools import DirectUtil
 from direct.directtools import DirectUtil
-from pandac.PandaModules import *
+from panda3d.core import *
 import string
 import string
 
 
 
 
@@ -341,7 +340,7 @@ class seLightManager(NodePath):
         if type == 'ambient':
         if type == 'ambient':
             self.ambientCount += 1
             self.ambientCount += 1
             if(name=='DEFAULT_NAME'):
             if(name=='DEFAULT_NAME'):
-                light = AmbientLight('ambient_' + `self.ambientCount`)
+                light = AmbientLight('ambient_' + repr(self.ambientCount))
             else:
             else:
                 light = AmbientLight(name)
                 light = AmbientLight(name)
 
 
@@ -350,7 +349,7 @@ class seLightManager(NodePath):
         elif type == 'directional':
         elif type == 'directional':
             self.directionalCount += 1
             self.directionalCount += 1
             if(name=='DEFAULT_NAME'):
             if(name=='DEFAULT_NAME'):
-                light = DirectionalLight('directional_' + `self.directionalCount`)
+                light = DirectionalLight('directional_' + repr(self.directionalCount))
             else:
             else:
                 light = DirectionalLight(name)
                 light = DirectionalLight(name)
 
 
@@ -360,7 +359,7 @@ class seLightManager(NodePath):
         elif type == 'point':
         elif type == 'point':
             self.pointCount += 1
             self.pointCount += 1
             if(name=='DEFAULT_NAME'):
             if(name=='DEFAULT_NAME'):
-                light = PointLight('point_' + `self.pointCount`)
+                light = PointLight('point_' + repr(self.pointCount))
             else:
             else:
                 light = PointLight(name)
                 light = PointLight(name)
 
 
@@ -371,7 +370,7 @@ class seLightManager(NodePath):
         elif type == 'spot':
         elif type == 'spot':
             self.spotCount += 1
             self.spotCount += 1
             if(name=='DEFAULT_NAME'):
             if(name=='DEFAULT_NAME'):
-                light = Spotlight('spot_' + `self.spotCount`)
+                light = Spotlight('spot_' + repr(self.spotCount))
             else:
             else:
                 light = Spotlight(name)
                 light = Spotlight(name)
 
 
@@ -382,7 +381,7 @@ class seLightManager(NodePath):
             light.setAttenuation(Vec3(constant, linear, quadratic))
             light.setAttenuation(Vec3(constant, linear, quadratic))
             light.setExponent(exponent)
             light.setExponent(exponent)
         else:
         else:
-            print 'Invalid light type'
+            print('Invalid light type')
             return None
             return None
 
 
         # Create the seLight objects and put the light object we just created into it.
         # Create the seLight objects and put the light object we just created into it.
@@ -411,7 +410,7 @@ class seLightManager(NodePath):
         # Attention!!
         # Attention!!
         # only Spotlight obj nneds to be specified a lens node first. i.e. setLens() first!
         # only Spotlight obj nneds to be specified a lens node first. i.e. setLens() first!
         #################################################################
         #################################################################
-        type = lower(light.getType().getName())
+        type = light.getType().getName().lower()
 
 
         specularColor = VBase4(1)
         specularColor = VBase4(1)
         position = Point3(0,0,0)
         position = Point3(0,0,0)
@@ -451,7 +450,7 @@ class seLightManager(NodePath):
             quadratic = Attenuation.getZ()
             quadratic = Attenuation.getZ()
             exponent = light.getExponent()
             exponent = light.getExponent()
         else:
         else:
-            print 'Invalid light type'
+            print('Invalid light type')
             return None
             return None
 
 
         lightNode = seLight(light,self,type,
         lightNode = seLight(light,self,type,
@@ -508,7 +507,7 @@ class seLightManager(NodePath):
         # isLight(self.name)
         # isLight(self.name)
         # Use a string as a index to check if there existing a light named "name"
         # Use a string as a index to check if there existing a light named "name"
         #################################################################
         #################################################################
-        return self.lightDict.has_key(name)
+        return name in self.lightDict
 
 
     def rename(self,oName,nName):
     def rename(self,oName,nName):
         #################################################################
         #################################################################
@@ -523,7 +522,7 @@ class seLightManager(NodePath):
             del self.lightDict[oName]
             del self.lightDict[oName]
             return self.lightDict.keys(),lightNode
             return self.lightDict.keys(),lightNode
         else:
         else:
-            print '----Light Mnager: No such Light!'
+            print('----Light Mnager: No such Light!')
 
 
     def getLightNodeList(self):
     def getLightNodeList(self):
         #################################################################
         #################################################################

+ 1 - 1
contrib/src/sceneeditor/seManipulation.py

@@ -520,7 +520,7 @@ class ObjectHandles(NodePath,DirectObject):
         # To avoid recreating a vec every frame
         # To avoid recreating a vec every frame
         self.hitPt = Vec3(0)
         self.hitPt = Vec3(0)
         # Get a handle on the components
         # Get a handle on the components
-        self.xHandles = self.find('**/X')
+        self.xHandles = self.find('**/ohScalingNode')
         self.xPostGroup = self.xHandles.find('**/x-post-group')
         self.xPostGroup = self.xHandles.find('**/x-post-group')
         self.xPostCollision = self.xHandles.find('**/x-post')
         self.xPostCollision = self.xHandles.find('**/x-post')
         self.xRingGroup = self.xHandles.find('**/x-ring-group')
         self.xRingGroup = self.xHandles.find('**/x-ring-group')

+ 153 - 146
contrib/src/sceneeditor/seMopathRecorder.py

@@ -25,10 +25,17 @@ from direct.tkwidgets.Slider import Slider
 from direct.tkwidgets.EntryScale import EntryScale
 from direct.tkwidgets.EntryScale import EntryScale
 from direct.tkwidgets.VectorWidgets import Vector2Entry, Vector3Entry
 from direct.tkwidgets.VectorWidgets import Vector2Entry, Vector3Entry
 from direct.tkwidgets.VectorWidgets import ColorEntry
 from direct.tkwidgets.VectorWidgets import ColorEntry
-from Tkinter import Button, Frame, Radiobutton, Checkbutton, Label
-from Tkinter import StringVar, BooleanVar, Entry, Scale
-import os, string, Tkinter, Pmw
-import __builtin__
+import os, string, sys, Pmw
+
+if sys.version_info >= (3, 0):
+    from tkinter import Button, Frame, Radiobutton, Checkbutton, Label
+    from tkinter import StringVar, BooleanVar, Entry, Scale
+    import tkinter
+else:
+    from Tkinter import Button, Frame, Radiobutton, Checkbutton, Label
+    from Tkinter import StringVar, BooleanVar, Entry, Scale
+    import Tkinter as tkinter
+
 
 
 PRF_UTILITIES = [
 PRF_UTILITIES = [
     'lambda: camera.lookAt(render)',
     'lambda: camera.lookAt(render)',
@@ -123,7 +130,7 @@ class MopathRecorder(AppShell, DirectObject):
         self.postPoints = []
         self.postPoints = []
         self.pointSetDict = {}
         self.pointSetDict = {}
         self.pointSetCount = 0
         self.pointSetCount = 0
-        self.pointSetName = self.name + '-ps-' + `self.pointSetCount`
+        self.pointSetName = self.name + '-ps-' + repr(self.pointSetCount)
         # User callback to call before recording point
         # User callback to call before recording point
         self.samplingMode = 'Continuous'
         self.samplingMode = 'Continuous'
         self.preRecordFunc = None
         self.preRecordFunc = None
@@ -233,7 +240,7 @@ class MopathRecorder(AppShell, DirectObject):
             self.undoButton['state'] = 'normal'
             self.undoButton['state'] = 'normal'
         else:
         else:
             self.undoButton['state'] = 'disabled'
             self.undoButton['state'] = 'disabled'
-        self.undoButton.pack(side = Tkinter.LEFT, expand = 0)
+        self.undoButton.pack(side = tkinter.LEFT, expand = 0)
         self.bind(self.undoButton, 'Undo last operation')
         self.bind(self.undoButton, 'Undo last operation')
 
 
         self.redoButton = Button(self.menuFrame, text = 'Redo',
         self.redoButton = Button(self.menuFrame, text = 'Redo',
@@ -242,19 +249,19 @@ class MopathRecorder(AppShell, DirectObject):
             self.redoButton['state'] = 'normal'
             self.redoButton['state'] = 'normal'
         else:
         else:
             self.redoButton['state'] = 'disabled'
             self.redoButton['state'] = 'disabled'
-        self.redoButton.pack(side = Tkinter.LEFT, expand = 0)
+        self.redoButton.pack(side = tkinter.LEFT, expand = 0)
         self.bind(self.redoButton, 'Redo last operation')
         self.bind(self.redoButton, 'Redo last operation')
 
 
         # Record button
         # Record button
-        mainFrame = Frame(interior, relief = Tkinter.SUNKEN, borderwidth = 2)
+        mainFrame = Frame(interior, relief = tkinter.SUNKEN, borderwidth = 2)
         frame = Frame(mainFrame)
         frame = Frame(mainFrame)
         # Active node path
         # Active node path
         # Button to select active node path
         # Button to select active node path
         widget = self.createButton(frame, 'Recording', 'Node Path:',
         widget = self.createButton(frame, 'Recording', 'Node Path:',
                                    'Select Active Mopath Node Path',
                                    'Select Active Mopath Node Path',
                                    lambda s = self: SEditor.select(s.nodePath),
                                    lambda s = self: SEditor.select(s.nodePath),
-                                   side = Tkinter.LEFT, expand = 0)
-        widget['relief'] = Tkinter.FLAT
+                                   side = tkinter.LEFT, expand = 0)
+        widget['relief'] = tkinter.FLAT
         self.nodePathMenu = Pmw.ComboBox(
         self.nodePathMenu = Pmw.ComboBox(
             frame, entry_width = 20,
             frame, entry_width = 20,
             selectioncommand = self.selectNodePathNamed,
             selectioncommand = self.selectNodePathNamed,
@@ -264,7 +271,7 @@ class MopathRecorder(AppShell, DirectObject):
             self.nodePathMenu.component('entryfield_entry'))
             self.nodePathMenu.component('entryfield_entry'))
         self.nodePathMenuBG = (
         self.nodePathMenuBG = (
             self.nodePathMenuEntry.configure('background')[3])
             self.nodePathMenuEntry.configure('background')[3])
-        self.nodePathMenu.pack(side = Tkinter.LEFT, fill = Tkinter.X, expand = 1)
+        self.nodePathMenu.pack(side = tkinter.LEFT, fill = tkinter.X, expand = 1)
         self.bind(self.nodePathMenu,
         self.bind(self.nodePathMenu,
                   'Select active node path used for recording and playback')
                   'Select active node path used for recording and playback')
         # Recording type
         # Recording type
@@ -285,81 +292,81 @@ class MopathRecorder(AppShell, DirectObject):
             'Recording', 'Extend',
             'Recording', 'Extend',
             ('Next record session extends existing path'),
             ('Next record session extends existing path'),
             self.recordingType, 'Extend', expand = 0)
             self.recordingType, 'Extend', expand = 0)
-        frame.pack(fill = Tkinter.X, expand = 1)
+        frame.pack(fill = tkinter.X, expand = 1)
 
 
         frame = Frame(mainFrame)
         frame = Frame(mainFrame)
         widget = self.createCheckbutton(
         widget = self.createCheckbutton(
             frame, 'Recording', 'Record',
             frame, 'Recording', 'Record',
             'On: path is being recorded', self.toggleRecord, 0,
             'On: path is being recorded', self.toggleRecord, 0,
-            side = Tkinter.LEFT, fill = Tkinter.BOTH, expand = 1)
-        widget.configure(foreground = 'Red', relief = Tkinter.RAISED, borderwidth = 2,
-                         anchor = Tkinter.CENTER, width = 16)
+            side = tkinter.LEFT, fill = tkinter.BOTH, expand = 1)
+        widget.configure(foreground = 'Red', relief = tkinter.RAISED, borderwidth = 2,
+                         anchor = tkinter.CENTER, width = 16)
         widget = self.createButton(frame, 'Recording', 'Add Keyframe',
         widget = self.createButton(frame, 'Recording', 'Add Keyframe',
                                    'Add Keyframe To Current Path',
                                    'Add Keyframe To Current Path',
                                    self.addKeyframe,
                                    self.addKeyframe,
-                                   side = Tkinter.LEFT, expand = 1)
+                                   side = tkinter.LEFT, expand = 1)
 
 
         widget = self.createButton(frame, 'Recording', 'Bind Path to Node',
         widget = self.createButton(frame, 'Recording', 'Bind Path to Node',
                                    'Bind Motion Path to selected Object',
                                    'Bind Motion Path to selected Object',
                                    self.bindMotionPathToNode,
                                    self.bindMotionPathToNode,
-                                   side = Tkinter.LEFT, expand = 1)
+                                   side = tkinter.LEFT, expand = 1)
 
 
 
 
-        frame.pack(fill = Tkinter.X, expand = 1)
+        frame.pack(fill = tkinter.X, expand = 1)
 
 
-        mainFrame.pack(expand = 1, fill = Tkinter.X, pady = 3)
+        mainFrame.pack(expand = 1, fill = tkinter.X, pady = 3)
 
 
         # Playback controls
         # Playback controls
-        playbackFrame = Frame(interior, relief = Tkinter.SUNKEN,
+        playbackFrame = Frame(interior, relief = tkinter.SUNKEN,
                               borderwidth = 2)
                               borderwidth = 2)
         Label(playbackFrame, text = 'PLAYBACK CONTROLS',
         Label(playbackFrame, text = 'PLAYBACK CONTROLS',
-              font=('MSSansSerif', 12, 'bold')).pack(fill = Tkinter.X)
+              font=('MSSansSerif', 12, 'bold')).pack(fill = tkinter.X)
         # Main playback control slider
         # Main playback control slider
         widget = self.createEntryScale(
         widget = self.createEntryScale(
             playbackFrame, 'Playback', 'Time', 'Set current playback time',
             playbackFrame, 'Playback', 'Time', 'Set current playback time',
-            resolution = 0.01, command = self.playbackGoTo, side = Tkinter.TOP)
-        widget.component('hull')['relief'] = Tkinter.RIDGE
+            resolution = 0.01, command = self.playbackGoTo, side = tkinter.TOP)
+        widget.component('hull')['relief'] = tkinter.RIDGE
         # Kill playback task if drag slider
         # Kill playback task if drag slider
         widget['preCallback'] = self.stopPlayback
         widget['preCallback'] = self.stopPlayback
         # Jam duration entry into entry scale
         # Jam duration entry into entry scale
         self.createLabeledEntry(widget.labelFrame, 'Resample', 'Path Duration',
         self.createLabeledEntry(widget.labelFrame, 'Resample', 'Path Duration',
                                 'Set total curve duration',
                                 'Set total curve duration',
                                 command = self.setPathDuration,
                                 command = self.setPathDuration,
-                                side = Tkinter.LEFT, expand = 0)
+                                side = tkinter.LEFT, expand = 0)
         # Start stop buttons
         # Start stop buttons
         frame = Frame(playbackFrame)
         frame = Frame(playbackFrame)
         widget = self.createButton(frame, 'Playback', '<<',
         widget = self.createButton(frame, 'Playback', '<<',
                                    'Jump to start of playback',
                                    'Jump to start of playback',
                                    self.jumpToStartOfPlayback,
                                    self.jumpToStartOfPlayback,
-                                   side = Tkinter.LEFT, expand = 1)
+                                   side = tkinter.LEFT, expand = 1)
         widget['font'] = (('MSSansSerif', 12, 'bold'))
         widget['font'] = (('MSSansSerif', 12, 'bold'))
         widget = self.createCheckbutton(frame, 'Playback', 'Play',
         widget = self.createCheckbutton(frame, 'Playback', 'Play',
                                         'Start/Stop playback',
                                         'Start/Stop playback',
                                         self.startStopPlayback, 0,
                                         self.startStopPlayback, 0,
-                                        side = Tkinter.LEFT, fill = Tkinter.BOTH, expand = 1)
+                                        side = tkinter.LEFT, fill = tkinter.BOTH, expand = 1)
         widget.configure(anchor = 'center', justify = 'center',
         widget.configure(anchor = 'center', justify = 'center',
-                         relief = Tkinter.RAISED, font = ('MSSansSerif', 12, 'bold'))
+                         relief = tkinter.RAISED, font = ('MSSansSerif', 12, 'bold'))
         widget = self.createButton(frame, 'Playback', '>>',
         widget = self.createButton(frame, 'Playback', '>>',
                                    'Jump to end of playback',
                                    'Jump to end of playback',
                                    self.jumpToEndOfPlayback,
                                    self.jumpToEndOfPlayback,
-                                   side = Tkinter.LEFT, expand = 1)
+                                   side = tkinter.LEFT, expand = 1)
         widget['font'] = (('MSSansSerif', 12, 'bold'))
         widget['font'] = (('MSSansSerif', 12, 'bold'))
         self.createCheckbutton(frame, 'Playback', 'Loop',
         self.createCheckbutton(frame, 'Playback', 'Loop',
                                'On: loop playback',
                                'On: loop playback',
                                self.setLoopPlayback, self.loopPlayback,
                                self.setLoopPlayback, self.loopPlayback,
-                               side = Tkinter.LEFT, fill = Tkinter.BOTH, expand = 0)
-        frame.pack(fill = Tkinter.X, expand = 1)
+                               side = tkinter.LEFT, fill = tkinter.BOTH, expand = 0)
+        frame.pack(fill = tkinter.X, expand = 1)
 
 
         # Speed control
         # Speed control
         frame = Frame(playbackFrame)
         frame = Frame(playbackFrame)
-        widget = Button(frame, text = 'PB Speed Vernier', relief = Tkinter.FLAT,
+        widget = Button(frame, text = 'PB Speed Vernier', relief = tkinter.FLAT,
                         command = lambda s = self: s.setSpeedScale(1.0))
                         command = lambda s = self: s.setSpeedScale(1.0))
-        widget.pack(side = Tkinter.LEFT, expand = 0)
+        widget.pack(side = tkinter.LEFT, expand = 0)
         self.speedScale = Scale(frame, from_ = -1, to = 1,
         self.speedScale = Scale(frame, from_ = -1, to = 1,
                                 resolution = 0.01, showvalue = 0,
                                 resolution = 0.01, showvalue = 0,
                                 width = 10, orient = 'horizontal',
                                 width = 10, orient = 'horizontal',
                                 command = self.setPlaybackSF)
                                 command = self.setPlaybackSF)
-        self.speedScale.pack(side = Tkinter.LEFT, fill = Tkinter.X, expand = 1)
+        self.speedScale.pack(side = tkinter.LEFT, fill = tkinter.X, expand = 1)
         self.speedVar = StringVar()
         self.speedVar = StringVar()
         self.speedVar.set("0.00")
         self.speedVar.set("0.00")
         self.speedEntry = Entry(frame, textvariable = self.speedVar,
         self.speedEntry = Entry(frame, textvariable = self.speedVar,
@@ -368,14 +375,14 @@ class MopathRecorder(AppShell, DirectObject):
             '<Return>',
             '<Return>',
             lambda e = None, s = self: s.setSpeedScale(
             lambda e = None, s = self: s.setSpeedScale(
             string.atof(s.speedVar.get())))
             string.atof(s.speedVar.get())))
-        self.speedEntry.pack(side = Tkinter.LEFT, expand = 0)
-        frame.pack(fill = Tkinter.X, expand = 1)
+        self.speedEntry.pack(side = tkinter.LEFT, expand = 0)
+        frame.pack(fill = tkinter.X, expand = 1)
 
 
-        playbackFrame.pack(fill = Tkinter.X, pady = 2)
+        playbackFrame.pack(fill = tkinter.X, pady = 2)
 
 
         # Create notebook pages
         # Create notebook pages
         self.mainNotebook = Pmw.NoteBook(interior)
         self.mainNotebook = Pmw.NoteBook(interior)
-        self.mainNotebook.pack(fill = Tkinter.BOTH, expand = 1)
+        self.mainNotebook.pack(fill = tkinter.BOTH, expand = 1)
         self.resamplePage = self.mainNotebook.add('Resample')
         self.resamplePage = self.mainNotebook.add('Resample')
         self.refinePage = self.mainNotebook.add('Refine')
         self.refinePage = self.mainNotebook.add('Refine')
         self.extendPage = self.mainNotebook.add('Extend')
         self.extendPage = self.mainNotebook.add('Extend')
@@ -386,35 +393,35 @@ class MopathRecorder(AppShell, DirectObject):
         ## RESAMPLE PAGE
         ## RESAMPLE PAGE
         label = Label(self.resamplePage, text = 'RESAMPLE CURVE',
         label = Label(self.resamplePage, text = 'RESAMPLE CURVE',
                       font=('MSSansSerif', 12, 'bold'))
                       font=('MSSansSerif', 12, 'bold'))
-        label.pack(fill = Tkinter.X)
+        label.pack(fill = tkinter.X)
 
 
         # Resample
         # Resample
         resampleFrame = Frame(
         resampleFrame = Frame(
-            self.resamplePage, relief = Tkinter.SUNKEN, borderwidth = 2)
+            self.resamplePage, relief = tkinter.SUNKEN, borderwidth = 2)
         label = Label(resampleFrame, text = 'RESAMPLE CURVE',
         label = Label(resampleFrame, text = 'RESAMPLE CURVE',
                       font=('MSSansSerif', 12, 'bold')).pack()
                       font=('MSSansSerif', 12, 'bold')).pack()
         widget = self.createSlider(
         widget = self.createSlider(
             resampleFrame, 'Resample', 'Num. Samples',
             resampleFrame, 'Resample', 'Num. Samples',
             'Number of samples in resampled curve',
             'Number of samples in resampled curve',
             resolution = 1, min = 2, max = 1000, command = self.setNumSamples)
             resolution = 1, min = 2, max = 1000, command = self.setNumSamples)
-        widget.component('hull')['relief'] = Tkinter.RIDGE
+        widget.component('hull')['relief'] = tkinter.RIDGE
         widget['postCallback'] = self.sampleCurve
         widget['postCallback'] = self.sampleCurve
 
 
         frame = Frame(resampleFrame)
         frame = Frame(resampleFrame)
         self.createButton(
         self.createButton(
             frame, 'Resample', 'Make Even',
             frame, 'Resample', 'Make Even',
             'Apply timewarp so resulting path has constant velocity',
             'Apply timewarp so resulting path has constant velocity',
-            self.makeEven, side = Tkinter.LEFT, fill = Tkinter.X, expand = 1)
+            self.makeEven, side = tkinter.LEFT, fill = tkinter.X, expand = 1)
         self.createButton(
         self.createButton(
             frame, 'Resample', 'Face Forward',
             frame, 'Resample', 'Face Forward',
             'Compute HPR so resulting hpr curve faces along xyz tangent',
             'Compute HPR so resulting hpr curve faces along xyz tangent',
-            self.faceForward, side = Tkinter.LEFT, fill = Tkinter.X, expand = 1)
-        frame.pack(fill = Tkinter.X, expand = 0)
-        resampleFrame.pack(fill = Tkinter.X, expand = 0, pady = 2)
+            self.faceForward, side = tkinter.LEFT, fill = tkinter.X, expand = 1)
+        frame.pack(fill = tkinter.X, expand = 0)
+        resampleFrame.pack(fill = tkinter.X, expand = 0, pady = 2)
 
 
         # Desample
         # Desample
         desampleFrame = Frame(
         desampleFrame = Frame(
-            self.resamplePage, relief = Tkinter.SUNKEN, borderwidth = 2)
+            self.resamplePage, relief = tkinter.SUNKEN, borderwidth = 2)
         Label(desampleFrame, text = 'DESAMPLE CURVE',
         Label(desampleFrame, text = 'DESAMPLE CURVE',
               font=('MSSansSerif', 12, 'bold')).pack()
               font=('MSSansSerif', 12, 'bold')).pack()
         widget = self.createSlider(
         widget = self.createSlider(
@@ -422,16 +429,16 @@ class MopathRecorder(AppShell, DirectObject):
             'Specify number of points to skip between samples',
             'Specify number of points to skip between samples',
             min = 1, max = 100, resolution = 1,
             min = 1, max = 100, resolution = 1,
             command = self.setDesampleFrequency)
             command = self.setDesampleFrequency)
-        widget.component('hull')['relief'] = Tkinter.RIDGE
+        widget.component('hull')['relief'] = tkinter.RIDGE
         widget['postCallback'] = self.desampleCurve
         widget['postCallback'] = self.desampleCurve
-        desampleFrame.pack(fill = Tkinter.X, expand = 0, pady = 2)
+        desampleFrame.pack(fill = tkinter.X, expand = 0, pady = 2)
 
 
         ## REFINE PAGE ##
         ## REFINE PAGE ##
-        refineFrame = Frame(self.refinePage, relief = Tkinter.SUNKEN,
+        refineFrame = Frame(self.refinePage, relief = tkinter.SUNKEN,
                             borderwidth = 2)
                             borderwidth = 2)
         label = Label(refineFrame, text = 'REFINE CURVE',
         label = Label(refineFrame, text = 'REFINE CURVE',
                       font=('MSSansSerif', 12, 'bold'))
                       font=('MSSansSerif', 12, 'bold'))
-        label.pack(fill = Tkinter.X)
+        label.pack(fill = tkinter.X)
 
 
         widget = self.createSlider(refineFrame,
         widget = self.createSlider(refineFrame,
                                        'Refine Page', 'Refine From',
                                        'Refine Page', 'Refine From',
@@ -460,14 +467,14 @@ class MopathRecorder(AppShell, DirectObject):
                                        command = self.setRefineStop)
                                        command = self.setRefineStop)
         widget['preCallback'] = self.setRefineMode
         widget['preCallback'] = self.setRefineMode
         widget['postCallback'] = self.getPostPoints
         widget['postCallback'] = self.getPostPoints
-        refineFrame.pack(fill = Tkinter.X)
+        refineFrame.pack(fill = tkinter.X)
 
 
         ## EXTEND PAGE ##
         ## EXTEND PAGE ##
-        extendFrame = Frame(self.extendPage, relief = Tkinter.SUNKEN,
+        extendFrame = Frame(self.extendPage, relief = tkinter.SUNKEN,
                             borderwidth = 2)
                             borderwidth = 2)
         label = Label(extendFrame, text = 'EXTEND CURVE',
         label = Label(extendFrame, text = 'EXTEND CURVE',
                       font=('MSSansSerif', 12, 'bold'))
                       font=('MSSansSerif', 12, 'bold'))
-        label.pack(fill = Tkinter.X)
+        label.pack(fill = tkinter.X)
 
 
         widget = self.createSlider(extendFrame,
         widget = self.createSlider(extendFrame,
                                        'Extend Page', 'Extend From',
                                        'Extend Page', 'Extend From',
@@ -483,14 +490,14 @@ class MopathRecorder(AppShell, DirectObject):
             resolution = 0.01,
             resolution = 0.01,
             command = self.setControlStart)
             command = self.setControlStart)
         widget['preCallback'] = self.setExtendMode
         widget['preCallback'] = self.setExtendMode
-        extendFrame.pack(fill = Tkinter.X)
+        extendFrame.pack(fill = tkinter.X)
 
 
         ## CROP PAGE ##
         ## CROP PAGE ##
-        cropFrame = Frame(self.cropPage, relief = Tkinter.SUNKEN,
+        cropFrame = Frame(self.cropPage, relief = tkinter.SUNKEN,
                             borderwidth = 2)
                             borderwidth = 2)
         label = Label(cropFrame, text = 'CROP CURVE',
         label = Label(cropFrame, text = 'CROP CURVE',
                       font=('MSSansSerif', 12, 'bold'))
                       font=('MSSansSerif', 12, 'bold'))
-        label.pack(fill = Tkinter.X)
+        label.pack(fill = tkinter.X)
 
 
         widget = self.createSlider(
         widget = self.createSlider(
             cropFrame,
             cropFrame,
@@ -508,11 +515,11 @@ class MopathRecorder(AppShell, DirectObject):
 
 
         self.createButton(cropFrame, 'Crop Page', 'Crop Curve',
         self.createButton(cropFrame, 'Crop Page', 'Crop Curve',
                           'Crop curve to specified from to times',
                           'Crop curve to specified from to times',
-                          self.cropCurve, fill = Tkinter.NONE)
-        cropFrame.pack(fill = Tkinter.X)
+                          self.cropCurve, fill = tkinter.NONE)
+        cropFrame.pack(fill = tkinter.X)
 
 
         ## DRAW PAGE ##
         ## DRAW PAGE ##
-        drawFrame = Frame(self.drawPage, relief = Tkinter.SUNKEN,
+        drawFrame = Frame(self.drawPage, relief = tkinter.SUNKEN,
                            borderwidth = 2)
                            borderwidth = 2)
 
 
         self.sf = Pmw.ScrolledFrame(self.drawPage, horizflex = 'elastic')
         self.sf = Pmw.ScrolledFrame(self.drawPage, horizflex = 'elastic')
@@ -521,57 +528,57 @@ class MopathRecorder(AppShell, DirectObject):
 
 
         label = Label(sfFrame, text = 'CURVE RENDERING STYLE',
         label = Label(sfFrame, text = 'CURVE RENDERING STYLE',
                       font=('MSSansSerif', 12, 'bold'))
                       font=('MSSansSerif', 12, 'bold'))
-        label.pack(fill = Tkinter.X)
+        label.pack(fill = tkinter.X)
 
 
         frame = Frame(sfFrame)
         frame = Frame(sfFrame)
-        Label(frame, text = 'SHOW:').pack(side = Tkinter.LEFT, expand = 0)
+        Label(frame, text = 'SHOW:').pack(side = tkinter.LEFT, expand = 0)
         widget = self.createCheckbutton(
         widget = self.createCheckbutton(
             frame, 'Style', 'Path',
             frame, 'Style', 'Path',
             'On: path is visible', self.setPathVis, 1,
             'On: path is visible', self.setPathVis, 1,
-            side = Tkinter.LEFT, fill = Tkinter.X, expand = 1)
+            side = tkinter.LEFT, fill = tkinter.X, expand = 1)
         widget = self.createCheckbutton(
         widget = self.createCheckbutton(
             frame, 'Style', 'Knots',
             frame, 'Style', 'Knots',
             'On: path knots are visible', self.setKnotVis, 1,
             'On: path knots are visible', self.setKnotVis, 1,
-            side = Tkinter.LEFT, fill = Tkinter.X, expand = 1)
+            side = tkinter.LEFT, fill = tkinter.X, expand = 1)
         widget = self.createCheckbutton(
         widget = self.createCheckbutton(
             frame, 'Style', 'CVs',
             frame, 'Style', 'CVs',
             'On: path CVs are visible', self.setCvVis, 0,
             'On: path CVs are visible', self.setCvVis, 0,
-            side = Tkinter.LEFT, fill = Tkinter.X, expand = 1)
+            side = tkinter.LEFT, fill = tkinter.X, expand = 1)
         widget = self.createCheckbutton(
         widget = self.createCheckbutton(
             frame, 'Style', 'Hull',
             frame, 'Style', 'Hull',
             'On: path hull is visible', self.setHullVis, 0,
             'On: path hull is visible', self.setHullVis, 0,
-            side = Tkinter.LEFT, fill = Tkinter.X, expand = 1)
+            side = tkinter.LEFT, fill = tkinter.X, expand = 1)
         widget = self.createCheckbutton(
         widget = self.createCheckbutton(
             frame, 'Style', 'Trace',
             frame, 'Style', 'Trace',
             'On: record is visible', self.setTraceVis, 0,
             'On: record is visible', self.setTraceVis, 0,
-            side = Tkinter.LEFT, fill = Tkinter.X, expand = 1)
+            side = tkinter.LEFT, fill = tkinter.X, expand = 1)
         widget = self.createCheckbutton(
         widget = self.createCheckbutton(
             frame, 'Style', 'Marker',
             frame, 'Style', 'Marker',
             'On: playback marker is visible', self.setMarkerVis, 0,
             'On: playback marker is visible', self.setMarkerVis, 0,
-            side = Tkinter.LEFT, fill = Tkinter.X, expand = 1)
-        frame.pack(fill = Tkinter.X, expand = 1)
+            side = tkinter.LEFT, fill = tkinter.X, expand = 1)
+        frame.pack(fill = tkinter.X, expand = 1)
         # Sliders
         # Sliders
         widget = self.createSlider(
         widget = self.createSlider(
             sfFrame, 'Style', 'Num Segs',
             sfFrame, 'Style', 'Num Segs',
             'Set number of segments used to approximate each parametric unit',
             'Set number of segments used to approximate each parametric unit',
             min = 1.0, max = 400, resolution = 1.0,
             min = 1.0, max = 400, resolution = 1.0,
             value = 40,
             value = 40,
-            command = self.setNumSegs, side = Tkinter.TOP)
-        widget.component('hull')['relief'] = Tkinter.RIDGE
+            command = self.setNumSegs, side = tkinter.TOP)
+        widget.component('hull')['relief'] = tkinter.RIDGE
         widget = self.createSlider(
         widget = self.createSlider(
             sfFrame, 'Style', 'Num Ticks',
             sfFrame, 'Style', 'Num Ticks',
             'Set number of tick marks drawn for each unit of time',
             'Set number of tick marks drawn for each unit of time',
             min = 0.0, max = 10.0, resolution = 1.0,
             min = 0.0, max = 10.0, resolution = 1.0,
             value = 0.0,
             value = 0.0,
-            command = self.setNumTicks, side = Tkinter.TOP)
-        widget.component('hull')['relief'] = Tkinter.RIDGE
+            command = self.setNumTicks, side = tkinter.TOP)
+        widget.component('hull')['relief'] = tkinter.RIDGE
         widget = self.createSlider(
         widget = self.createSlider(
             sfFrame, 'Style', 'Tick Scale',
             sfFrame, 'Style', 'Tick Scale',
             'Set visible size of time tick marks',
             'Set visible size of time tick marks',
             min = 0.01, max = 100.0, resolution = 0.01,
             min = 0.01, max = 100.0, resolution = 0.01,
             value = 5.0,
             value = 5.0,
-            command = self.setTickScale, side = Tkinter.TOP)
-        widget.component('hull')['relief'] = Tkinter.RIDGE
+            command = self.setTickScale, side = tkinter.TOP)
+        widget.component('hull')['relief'] = tkinter.RIDGE
         self.createColorEntry(
         self.createColorEntry(
             sfFrame, 'Style', 'Path Color',
             sfFrame, 'Style', 'Path Color',
             'Color of curve',
             'Color of curve',
@@ -598,14 +605,14 @@ class MopathRecorder(AppShell, DirectObject):
             command = self.setHullColor,
             command = self.setHullColor,
             value = [255.0,128.0,128.0,255.0])
             value = [255.0,128.0,128.0,255.0])
 
 
-        #drawFrame.pack(fill = Tkinter.X)
+        #drawFrame.pack(fill = tkinter.X)
 
 
         ## OPTIONS PAGE ##
         ## OPTIONS PAGE ##
-        optionsFrame = Frame(self.optionsPage, relief = Tkinter.SUNKEN,
+        optionsFrame = Frame(self.optionsPage, relief = tkinter.SUNKEN,
                             borderwidth = 2)
                             borderwidth = 2)
         label = Label(optionsFrame, text = 'RECORDING OPTIONS',
         label = Label(optionsFrame, text = 'RECORDING OPTIONS',
                       font=('MSSansSerif', 12, 'bold'))
                       font=('MSSansSerif', 12, 'bold'))
-        label.pack(fill = Tkinter.X)
+        label.pack(fill = tkinter.X)
         # Hooks
         # Hooks
         frame = Frame(optionsFrame)
         frame = Frame(optionsFrame)
         widget = self.createLabeledEntry(
         widget = self.createLabeledEntry(
@@ -614,7 +621,7 @@ class MopathRecorder(AppShell, DirectObject):
             value = self.startStopHook,
             value = self.startStopHook,
             command = self.setStartStopHook)[0]
             command = self.setStartStopHook)[0]
         label = self.getWidget('Recording', 'Record Hook-Label')
         label = self.getWidget('Recording', 'Record Hook-Label')
-        label.configure(width = 16, anchor = Tkinter.W)
+        label.configure(width = 16, anchor = tkinter.W)
         self.setStartStopHook()
         self.setStartStopHook()
         widget = self.createLabeledEntry(
         widget = self.createLabeledEntry(
             frame, 'Recording', 'Keyframe Hook',
             frame, 'Recording', 'Keyframe Hook',
@@ -622,9 +629,9 @@ class MopathRecorder(AppShell, DirectObject):
             value = self.keyframeHook,
             value = self.keyframeHook,
             command = self.setKeyframeHook)[0]
             command = self.setKeyframeHook)[0]
         label = self.getWidget('Recording', 'Keyframe Hook-Label')
         label = self.getWidget('Recording', 'Keyframe Hook-Label')
-        label.configure(width = 16, anchor = Tkinter.W)
+        label.configure(width = 16, anchor = tkinter.W)
         self.setKeyframeHook()
         self.setKeyframeHook()
-        frame.pack(expand = 1, fill = Tkinter.X)
+        frame.pack(expand = 1, fill = tkinter.X)
         # PreRecordFunc
         # PreRecordFunc
         frame = Frame(optionsFrame)
         frame = Frame(optionsFrame)
         widget = self.createComboBox(
         widget = self.createComboBox(
@@ -632,17 +639,17 @@ class MopathRecorder(AppShell, DirectObject):
             'Function called before sampling each point',
             'Function called before sampling each point',
             PRF_UTILITIES, self.setPreRecordFunc,
             PRF_UTILITIES, self.setPreRecordFunc,
             history = 1, expand = 1)
             history = 1, expand = 1)
-        widget.configure(label_width = 16, label_anchor = Tkinter.W)
+        widget.configure(label_width = 16, label_anchor = tkinter.W)
         widget.configure(entryfield_entry_state = 'normal')
         widget.configure(entryfield_entry_state = 'normal')
         # Initialize preRecordFunc
         # Initialize preRecordFunc
         self.preRecordFunc = eval(PRF_UTILITIES[0])
         self.preRecordFunc = eval(PRF_UTILITIES[0])
         self.createCheckbutton(frame, 'Recording', 'PRF Active',
         self.createCheckbutton(frame, 'Recording', 'PRF Active',
                                'On: Pre Record Func enabled',
                                'On: Pre Record Func enabled',
                                None, 0,
                                None, 0,
-                               side = Tkinter.LEFT, fill = Tkinter.BOTH, expand = 0)
-        frame.pack(expand = 1, fill = Tkinter.X)
+                               side = tkinter.LEFT, fill = tkinter.BOTH, expand = 0)
+        frame.pack(expand = 1, fill = tkinter.X)
         # Pack record frame
         # Pack record frame
-        optionsFrame.pack(fill = Tkinter.X, pady = 2)
+        optionsFrame.pack(fill = tkinter.X, pady = 2)
 
 
         self.mainNotebook.setnaturalsize()
         self.mainNotebook.setnaturalsize()
 
 
@@ -682,16 +689,16 @@ class MopathRecorder(AppShell, DirectObject):
         marker if subnode selected
         marker if subnode selected
         """
         """
         taskMgr.remove(self.name + '-curveEditTask')
         taskMgr.remove(self.name + '-curveEditTask')
-        print nodePath.id()
-        if nodePath.id() in self.playbackMarkerIds:
+        print(nodePath.get_key())
+        if nodePath.get_key() in self.playbackMarkerIds:
             SEditor.select(self.playbackMarker)
             SEditor.select(self.playbackMarker)
-        elif nodePath.id() in self.tangentMarkerIds:
+        elif nodePath.get_key() in self.tangentMarkerIds:
             SEditor.select(self.tangentMarker)
             SEditor.select(self.tangentMarker)
-        elif nodePath.id() == self.playbackMarker.id():
+        elif nodePath.get_key() == self.playbackMarker.get_key():
             self.tangentGroup.show()
             self.tangentGroup.show()
             taskMgr.add(self.curveEditTask,
             taskMgr.add(self.curveEditTask,
                                      self.name + '-curveEditTask')
                                      self.name + '-curveEditTask')
-        elif nodePath.id() == self.tangentMarker.id():
+        elif nodePath.get_key() == self.tangentMarker.get_key():
             self.tangentGroup.show()
             self.tangentGroup.show()
             taskMgr.add(self.curveEditTask,
             taskMgr.add(self.curveEditTask,
                                      self.name + '-curveEditTask')
                                      self.name + '-curveEditTask')
@@ -699,7 +706,7 @@ class MopathRecorder(AppShell, DirectObject):
             self.tangentGroup.hide()
             self.tangentGroup.hide()
 
 
     def getChildIds(self, nodePath):
     def getChildIds(self, nodePath):
-        ids = [nodePath.id()]
+        ids = [nodePath.get_key()]
         kids = nodePath.getChildren()
         kids = nodePath.getChildren()
         for kid in kids:
         for kid in kids:
             ids += self.getChildIds(kid)
             ids += self.getChildIds(kid)
@@ -710,14 +717,14 @@ class MopathRecorder(AppShell, DirectObject):
         Hook called upon deselection of a node path used to select playback
         Hook called upon deselection of a node path used to select playback
         marker if subnode selected
         marker if subnode selected
         """
         """
-        if ((nodePath.id() == self.playbackMarker.id()) or
-            (nodePath.id() == self.tangentMarker.id())):
+        if ((nodePath.get_key() == self.playbackMarker.get_key()) or
+            (nodePath.get_key() == self.tangentMarker.get_key())):
             self.tangentGroup.hide()
             self.tangentGroup.hide()
 
 
     def curveEditTask(self,state):
     def curveEditTask(self,state):
         if self.curveCollection != None:
         if self.curveCollection != None:
             # Update curve position
             # Update curve position
-            if self.manipulandumId == self.playbackMarker.id():
+            if self.manipulandumId == self.playbackMarker.get_key():
                 # Show playback marker
                 # Show playback marker
                 self.playbackMarker.getChild(0).show()
                 self.playbackMarker.getChild(0).show()
                 pos = Point3(0)
                 pos = Point3(0)
@@ -731,7 +738,7 @@ class MopathRecorder(AppShell, DirectObject):
                 # Note: this calls recompute on the curves
                 # Note: this calls recompute on the curves
                 self.nurbsCurveDrawer.draw()
                 self.nurbsCurveDrawer.draw()
             # Update tangent
             # Update tangent
-            if self.manipulandumId == self.tangentMarker.id():
+            if self.manipulandumId == self.tangentMarker.get_key():
                 # If manipulating marker, update tangent
                 # If manipulating marker, update tangent
                 # Hide playback marker
                 # Hide playback marker
                 self.playbackMarker.getChild(0).hide()
                 self.playbackMarker.getChild(0).hide()
@@ -766,10 +773,10 @@ class MopathRecorder(AppShell, DirectObject):
     def manipulateObjectStartHook(self):
     def manipulateObjectStartHook(self):
         self.manipulandumId = None
         self.manipulandumId = None
         if SEditor.selected.last:
         if SEditor.selected.last:
-            if SEditor.selected.last.id() == self.playbackMarker.id():
-                self.manipulandumId = self.playbackMarker.id()
-            elif SEditor.selected.last.id() == self.tangentMarker.id():
-                self.manipulandumId = self.tangentMarker.id()
+            if SEditor.selected.last.get_key() == self.playbackMarker.get_key():
+                self.manipulandumId = self.playbackMarker.get_key()
+            elif SEditor.selected.last.get_key() == self.tangentMarker.get_key():
+                self.manipulandumId = self.tangentMarker.get_key()
 
 
     def manipulateObjectCleanupHook(self):
     def manipulateObjectCleanupHook(self):
         # Clear flag
         # Clear flag
@@ -799,7 +806,7 @@ class MopathRecorder(AppShell, DirectObject):
 
 
     def createNewPointSet(self, curveName = None):
     def createNewPointSet(self, curveName = None):
         if curveName == None:
         if curveName == None:
-            self.pointSetName = self.name + '-ps-' + `self.pointSetCount`
+            self.pointSetName = self.name + '-ps-' + repr(self.pointSetCount)
         else:
         else:
             self.pointSetName = curveName
             self.pointSetName = curveName
         # Update dictionary and record pointer to new point set
         # Update dictionary and record pointer to new point set
@@ -1137,7 +1144,7 @@ class MopathRecorder(AppShell, DirectObject):
     def computeCurves(self):
     def computeCurves(self):
         # Check to make sure curve fitters have points
         # Check to make sure curve fitters have points
         if (self.curveFitter.getNumSamples() == 0):
         if (self.curveFitter.getNumSamples() == 0):
-            print 'MopathRecorder.computeCurves: Must define curve first'
+            print('MopathRecorder.computeCurves: Must define curve first')
             return
             return
         # Create curves
         # Create curves
         # XYZ
         # XYZ
@@ -1282,8 +1289,8 @@ class MopathRecorder(AppShell, DirectObject):
             dictName = name
             dictName = name
         else:
         else:
             # Generate a unique name for the dict
             # Generate a unique name for the dict
-            dictName = name # + '-' + `nodePath.id()`
-        if not dict.has_key(dictName):
+            dictName = name # + '-' + repr(nodePath.get_key())
+        if dictName not in dict:
             # Update combo box to include new item
             # Update combo box to include new item
             names.append(dictName)
             names.append(dictName)
             listbox = menu.component('scrolledlist')
             listbox = menu.component('scrolledlist')
@@ -1386,7 +1393,7 @@ class MopathRecorder(AppShell, DirectObject):
 
 
     def desampleCurve(self):
     def desampleCurve(self):
         if (self.curveFitter.getNumSamples() == 0):
         if (self.curveFitter.getNumSamples() == 0):
-            print 'MopathRecorder.desampleCurve: Must define curve first'
+            print('MopathRecorder.desampleCurve: Must define curve first')
             return
             return
         # NOTE: This is destructive, points will be deleted from curve fitter
         # NOTE: This is destructive, points will be deleted from curve fitter
         self.curveFitter.desample(self.desampleFrequency)
         self.curveFitter.desample(self.desampleFrequency)
@@ -1400,7 +1407,7 @@ class MopathRecorder(AppShell, DirectObject):
 
 
     def sampleCurve(self, fCompute = 1, curveName = None):
     def sampleCurve(self, fCompute = 1, curveName = None):
         if self.curveCollection == None:
         if self.curveCollection == None:
-            print 'MopathRecorder.sampleCurve: Must define curve first'
+            print('MopathRecorder.sampleCurve: Must define curve first')
             return
             return
         # Reset curve fitters
         # Reset curve fitters
         self.curveFitter.reset()
         self.curveFitter.reset()
@@ -1617,7 +1624,7 @@ class MopathRecorder(AppShell, DirectObject):
 
 
     def cropCurve(self):
     def cropCurve(self):
         if self.pointSet == None:
         if self.pointSet == None:
-            print 'Empty Point Set'
+            print('Empty Point Set')
             return
             return
         # Keep handle on old points
         # Keep handle on old points
         oldPoints = self.pointSet
         oldPoints = self.pointSet
@@ -1653,15 +1660,15 @@ class MopathRecorder(AppShell, DirectObject):
         # Use first directory in model path
         # Use first directory in model path
         mPath = getModelPath()
         mPath = getModelPath()
         if mPath.getNumDirectories() > 0:
         if mPath.getNumDirectories() > 0:
-            if `mPath.getDirectory(0)` == '.':
+            if repr(mPath.getDirectory(0)) == '.':
                 path = '.'
                 path = '.'
             else:
             else:
                 path = mPath.getDirectory(0).toOsSpecific()
                 path = mPath.getDirectory(0).toOsSpecific()
         else:
         else:
             path = '.'
             path = '.'
         if not os.path.isdir(path):
         if not os.path.isdir(path):
-            print 'MopathRecorder Info: Empty Model Path!'
-            print 'Using current directory'
+            print('MopathRecorder Info: Empty Model Path!')
+            print('Using current directory')
             path = '.'
             path = '.'
         mopathFilename = askopenfilename(
         mopathFilename = askopenfilename(
             defaultextension = '.egg',
             defaultextension = '.egg',
@@ -1692,15 +1699,15 @@ class MopathRecorder(AppShell, DirectObject):
         # Use first directory in model path
         # Use first directory in model path
         mPath = getModelPath()
         mPath = getModelPath()
         if mPath.getNumDirectories() > 0:
         if mPath.getNumDirectories() > 0:
-            if `mPath.getDirectory(0)` == '.':
+            if repr(mPath.getDirectory(0)) == '.':
                 path = '.'
                 path = '.'
             else:
             else:
                 path = mPath.getDirectory(0).toOsSpecific()
                 path = mPath.getDirectory(0).toOsSpecific()
         else:
         else:
             path = '.'
             path = '.'
         if not os.path.isdir(path):
         if not os.path.isdir(path):
-            print 'MopathRecorder Info: Empty Model Path!'
-            print 'Using current directory'
+            print('MopathRecorder Info: Empty Model Path!')
+            print('Using current directory')
             path = '.'
             path = '.'
         mopathFilename = asksaveasfilename(
         mopathFilename = asksaveasfilename(
             defaultextension = '.egg',
             defaultextension = '.egg',
@@ -1734,28 +1741,28 @@ class MopathRecorder(AppShell, DirectObject):
 
 
     def createLabeledEntry(self, parent, category, text, balloonHelp,
     def createLabeledEntry(self, parent, category, text, balloonHelp,
                            value = '', command = None,
                            value = '', command = None,
-                           relief = 'sunken', side = Tkinter.LEFT,
+                           relief = 'sunken', side = tkinter.LEFT,
                            expand = 1, width = 12):
                            expand = 1, width = 12):
         frame = Frame(parent)
         frame = Frame(parent)
         variable = StringVar()
         variable = StringVar()
         variable.set(value)
         variable.set(value)
         label = Label(frame, text = text)
         label = Label(frame, text = text)
-        label.pack(side = Tkinter.LEFT, fill = Tkinter.X)
+        label.pack(side = tkinter.LEFT, fill = tkinter.X)
         self.bind(label, balloonHelp)
         self.bind(label, balloonHelp)
         self.widgetDict[category + '-' + text + '-Label'] = label
         self.widgetDict[category + '-' + text + '-Label'] = label
         entry = Entry(frame, width = width, relief = relief,
         entry = Entry(frame, width = width, relief = relief,
                       textvariable = variable)
                       textvariable = variable)
-        entry.pack(side = Tkinter.LEFT, fill = Tkinter.X, expand = expand)
+        entry.pack(side = tkinter.LEFT, fill = tkinter.X, expand = expand)
         self.bind(entry, balloonHelp)
         self.bind(entry, balloonHelp)
         self.widgetDict[category + '-' + text] = entry
         self.widgetDict[category + '-' + text] = entry
         self.variableDict[category + '-' + text] = variable
         self.variableDict[category + '-' + text] = variable
         if command:
         if command:
             entry.bind('<Return>', command)
             entry.bind('<Return>', command)
-        frame.pack(side = side, fill = Tkinter.X, expand = expand)
+        frame.pack(side = side, fill = tkinter.X, expand = expand)
         return (frame, label, entry)
         return (frame, label, entry)
 
 
     def createButton(self, parent, category, text, balloonHelp, command,
     def createButton(self, parent, category, text, balloonHelp, command,
-                     side = 'top', expand = 0, fill = Tkinter.X):
+                     side = 'top', expand = 0, fill = tkinter.X):
         widget = Button(parent, text = text)
         widget = Button(parent, text = text)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
@@ -1766,10 +1773,10 @@ class MopathRecorder(AppShell, DirectObject):
 
 
     def createCheckbutton(self, parent, category, text,
     def createCheckbutton(self, parent, category, text,
                           balloonHelp, command, initialState,
                           balloonHelp, command, initialState,
-                          side = 'top', fill = Tkinter.X, expand = 0):
+                          side = 'top', fill = tkinter.X, expand = 0):
         bool = BooleanVar()
         bool = BooleanVar()
         bool.set(initialState)
         bool.set(initialState)
-        widget = Checkbutton(parent, text = text, anchor = Tkinter.W,
+        widget = Checkbutton(parent, text = text, anchor = tkinter.W,
                          variable = bool)
                          variable = bool)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
@@ -1781,8 +1788,8 @@ class MopathRecorder(AppShell, DirectObject):
 
 
     def createRadiobutton(self, parent, side, category, text,
     def createRadiobutton(self, parent, side, category, text,
                           balloonHelp, variable, value,
                           balloonHelp, variable, value,
-                          command = None, fill = Tkinter.X, expand = 0):
-        widget = Radiobutton(parent, text = text, anchor = Tkinter.W,
+                          command = None, fill = tkinter.X, expand = 0):
+        widget = Radiobutton(parent, text = text, anchor = tkinter.W,
                              variable = variable, value = value)
                              variable = variable, value = value)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
@@ -1798,10 +1805,10 @@ class MopathRecorder(AppShell, DirectObject):
         kw['min'] = min
         kw['min'] = min
         kw['maxVelocity'] = maxVelocity
         kw['maxVelocity'] = maxVelocity
         kw['resolution'] = resolution
         kw['resolution'] = resolution
-        widget = apply(Floater, (parent,), kw)
+        widget = Floater(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
-        widget.pack(fill = Tkinter.X)
+        widget.pack(fill = tkinter.X)
         self.bind(widget, balloonHelp)
         self.bind(widget, balloonHelp)
         self.widgetDict[category + '-' + text] = widget
         self.widgetDict[category + '-' + text] = widget
         return widget
         return widget
@@ -1809,10 +1816,10 @@ class MopathRecorder(AppShell, DirectObject):
     def createAngleDial(self, parent, category, text, balloonHelp,
     def createAngleDial(self, parent, category, text, balloonHelp,
                         command = None, **kw):
                         command = None, **kw):
         kw['text'] = text
         kw['text'] = text
-        widget = apply(AngleDial,(parent,), kw)
+        widget = AngleDial(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
-        widget.pack(fill = Tkinter.X)
+        widget.pack(fill = tkinter.X)
         self.bind(widget, balloonHelp)
         self.bind(widget, balloonHelp)
         self.widgetDict[category + '-' + text] = widget
         self.widgetDict[category + '-' + text] = widget
         return widget
         return widget
@@ -1820,13 +1827,13 @@ class MopathRecorder(AppShell, DirectObject):
     def createSlider(self, parent, category, text, balloonHelp,
     def createSlider(self, parent, category, text, balloonHelp,
                          command = None, min = 0.0, max = 1.0,
                          command = None, min = 0.0, max = 1.0,
                          resolution = None,
                          resolution = None,
-                         side = Tkinter.TOP, fill = Tkinter.X, expand = 1, **kw):
+                         side = tkinter.TOP, fill = tkinter.X, expand = 1, **kw):
         kw['text'] = text
         kw['text'] = text
         kw['min'] = min
         kw['min'] = min
         kw['max'] = max
         kw['max'] = max
         kw['resolution'] = resolution
         kw['resolution'] = resolution
         #widget = apply(EntryScale, (parent,), kw)
         #widget = apply(EntryScale, (parent,), kw)
-        widget = apply(Slider, (parent,), kw)
+        widget = Slider(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
         widget.pack(side = side, fill = fill, expand = expand)
         widget.pack(side = side, fill = fill, expand = expand)
@@ -1837,12 +1844,12 @@ class MopathRecorder(AppShell, DirectObject):
     def createEntryScale(self, parent, category, text, balloonHelp,
     def createEntryScale(self, parent, category, text, balloonHelp,
                          command = None, min = 0.0, max = 1.0,
                          command = None, min = 0.0, max = 1.0,
                          resolution = None,
                          resolution = None,
-                         side = Tkinter.TOP, fill = Tkinter.X, expand = 1, **kw):
+                         side = tkinter.TOP, fill = tkinter.X, expand = 1, **kw):
         kw['text'] = text
         kw['text'] = text
         kw['min'] = min
         kw['min'] = min
         kw['max'] = max
         kw['max'] = max
         kw['resolution'] = resolution
         kw['resolution'] = resolution
-        widget = apply(EntryScale, (parent,), kw)
+        widget = EntryScale(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
         widget.pack(side = side, fill = fill, expand = expand)
         widget.pack(side = side, fill = fill, expand = expand)
@@ -1854,10 +1861,10 @@ class MopathRecorder(AppShell, DirectObject):
                            command = None, **kw):
                            command = None, **kw):
         # Set label's text
         # Set label's text
         kw['text'] = text
         kw['text'] = text
-        widget = apply(Vector2Entry, (parent,), kw)
+        widget = Vector2Entry(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
-        widget.pack(fill = Tkinter.X)
+        widget.pack(fill = tkinter.X)
         self.bind(widget, balloonHelp)
         self.bind(widget, balloonHelp)
         self.widgetDict[category + '-' + text] = widget
         self.widgetDict[category + '-' + text] = widget
         return widget
         return widget
@@ -1866,10 +1873,10 @@ class MopathRecorder(AppShell, DirectObject):
                            command = None, **kw):
                            command = None, **kw):
         # Set label's text
         # Set label's text
         kw['text'] = text
         kw['text'] = text
-        widget = apply(Vector3Entry, (parent,), kw)
+        widget = Vector3Entry(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
-        widget.pack(fill = Tkinter.X)
+        widget.pack(fill = tkinter.X)
         self.bind(widget, balloonHelp)
         self.bind(widget, balloonHelp)
         self.widgetDict[category + '-' + text] = widget
         self.widgetDict[category + '-' + text] = widget
         return widget
         return widget
@@ -1878,10 +1885,10 @@ class MopathRecorder(AppShell, DirectObject):
                          command = None, **kw):
                          command = None, **kw):
         # Set label's text
         # Set label's text
         kw['text'] = text
         kw['text'] = text
-        widget = apply(ColorEntry, (parent,) ,kw)
+        widget = ColorEntry(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
-        widget.pack(fill = Tkinter.X)
+        widget.pack(fill = tkinter.X)
         self.bind(widget, balloonHelp)
         self.bind(widget, balloonHelp)
         self.widgetDict[category + '-' + text] = widget
         self.widgetDict[category + '-' + text] = widget
         return widget
         return widget
@@ -1891,13 +1898,13 @@ class MopathRecorder(AppShell, DirectObject):
         optionVar = StringVar()
         optionVar = StringVar()
         if len(items) > 0:
         if len(items) > 0:
             optionVar.set(items[0])
             optionVar.set(items[0])
-        widget = Pmw.OptionMenu(parent, labelpos = Tkinter.W, label_text = text,
+        widget = Pmw.OptionMenu(parent, labelpos = tkinter.W, label_text = text,
                                 label_width = 12, menu_tearoff = 1,
                                 label_width = 12, menu_tearoff = 1,
                                 menubutton_textvariable = optionVar,
                                 menubutton_textvariable = optionVar,
                                 items = items)
                                 items = items)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
-        widget.pack(fill = Tkinter.X)
+        widget.pack(fill = tkinter.X)
         self.bind(widget.component('menubutton'), balloonHelp)
         self.bind(widget.component('menubutton'), balloonHelp)
         self.widgetDict[category + '-' + text] = widget
         self.widgetDict[category + '-' + text] = widget
         self.variableDict[category + '-' + text] = optionVar
         self.variableDict[category + '-' + text] = optionVar
@@ -1905,9 +1912,9 @@ class MopathRecorder(AppShell, DirectObject):
 
 
     def createComboBox(self, parent, category, text, balloonHelp,
     def createComboBox(self, parent, category, text, balloonHelp,
                        items, command, history = 0,
                        items, command, history = 0,
-                       side = Tkinter.LEFT, expand = 0, fill = Tkinter.X):
+                       side = tkinter.LEFT, expand = 0, fill = tkinter.X):
         widget = Pmw.ComboBox(parent,
         widget = Pmw.ComboBox(parent,
-                              labelpos = Tkinter.W,
+                              labelpos = tkinter.W,
                               label_text = text,
                               label_text = text,
                               label_anchor = 'e',
                               label_anchor = 'e',
                               label_width = 12,
                               label_width = 12,
@@ -1959,14 +1966,14 @@ class MopathRecorder(AppShell, DirectObject):
 
 
     def bindMotionPathToNode(self):
     def bindMotionPathToNode(self):
         if self.curveCollection == None:
         if self.curveCollection == None:
-            print '----Error: you need to select or create a curve first!'
+            print('----Error: you need to select or create a curve first!')
             return
             return
         self.accept('MP_checkName', self.bindMotionPath)
         self.accept('MP_checkName', self.bindMotionPath)
         self.askName = namePathPanel(MopathRecorder.count)
         self.askName = namePathPanel(MopathRecorder.count)
         return
         return
 
 
     def bindMotionPath(self,name=None,test=None):
     def bindMotionPath(self,name=None,test=None):
-        print test
+        print(test)
         self.ignore('MP_checkName')
         self.ignore('MP_checkName')
         del self.askName
         del self.askName
         self.curveCollection.getCurve(0).setName(name)
         self.curveCollection.getCurve(0).setName(name)
@@ -1993,7 +2000,7 @@ class MopathRecorder(AppShell, DirectObject):
         If the list is not None, it will put the vurve back into the curve list.
         If the list is not None, it will put the vurve back into the curve list.
         else, do nothing.
         else, do nothing.
         '''
         '''
-        print curveList
+        print(curveList)
         self.ignore('curveListFor'+self.name)
         self.ignore('curveListFor'+self.name)
         if curveList != None:
         if curveList != None:
             for collection in curveList:
             for collection in curveList:
@@ -2037,8 +2044,8 @@ class namePathPanel(AppShell):
 
 
         dataFrame = Frame(mainFrame)
         dataFrame = Frame(mainFrame)
         label = Label(dataFrame, text='This name will be used as a reference for this Path.',font=('MSSansSerif', 10))
         label = Label(dataFrame, text='This name will be used as a reference for this Path.',font=('MSSansSerif', 10))
-        label.pack(side = Tkinter.TOP, expand = 0, fill = Tkinter.X)
-        dataFrame.pack(side = Tkinter.TOP, expand = 0, fill = Tkinter.X, padx=5, pady=10)
+        label.pack(side = tkinter.TOP, expand = 0, fill = tkinter.X)
+        dataFrame.pack(side = tkinter.TOP, expand = 0, fill = tkinter.X, padx=5, pady=10)
 
 
         dataFrame = Frame(mainFrame)
         dataFrame = Frame(mainFrame)
         self.inputZone = Pmw.EntryField(dataFrame, labelpos='w', label_text = 'Name Selected Path: ',
         self.inputZone = Pmw.EntryField(dataFrame, labelpos='w', label_text = 'Name Selected Path: ',
@@ -2046,14 +2053,14 @@ class namePathPanel(AppShell):
                                         label_font=('MSSansSerif', 10),
                                         label_font=('MSSansSerif', 10),
                                         validate = None,
                                         validate = None,
                                         entry_width = 20)
                                         entry_width = 20)
-        self.inputZone.pack(side = Tkinter.LEFT, fill=Tkinter.X,expand=0)
+        self.inputZone.pack(side = tkinter.LEFT, fill=tkinter.X,expand=0)
 
 
         self.button_ok = Button(dataFrame, text="OK", command=self.ok_press,width=10)
         self.button_ok = Button(dataFrame, text="OK", command=self.ok_press,width=10)
-        self.button_ok.pack(fill=Tkinter.X,expand=0,side=Tkinter.LEFT, padx = 3)
+        self.button_ok.pack(fill=tkinter.X,expand=0,side=tkinter.LEFT, padx = 3)
 
 
-        dataFrame.pack(side = Tkinter.TOP, expand = 0, fill = Tkinter.X, padx=10, pady=10)
+        dataFrame.pack(side = tkinter.TOP, expand = 0, fill = tkinter.X, padx=10, pady=10)
 
 
-        mainFrame.pack(expand = 1, fill = Tkinter.BOTH)
+        mainFrame.pack(expand = 1, fill = tkinter.BOTH)
 
 
 
 
 
 

+ 4 - 4
contrib/src/sceneeditor/seParticleEffect.py

@@ -1,4 +1,4 @@
-from pandac.PandaModules import *
+from panda3d.core import *
 import seParticles
 import seParticles
 import seForceGroup
 import seForceGroup
 from direct.directnotify import DirectNotifyGlobal
 from direct.directnotify import DirectNotifyGlobal
@@ -209,9 +209,9 @@ class ParticleEffect(NodePath):
         """loadConfig(filename)"""
         """loadConfig(filename)"""
         #try:
         #try:
         #    if vfs:
         #    if vfs:
-        print vfs.readFile(filename)
-        exec vfs.readFile(filename)
-        print "Particle Effect Reading using VFS"
+        print(vfs.readFile(filename))
+        exec(vfs.readFile(filename))
+        print("Particle Effect Reading using VFS")
         #    else:
         #    else:
         #       execfile(filename.toOsSpecific())
         #       execfile(filename.toOsSpecific())
         #       print "Shouldnt be wrong"
         #       print "Shouldnt be wrong"

+ 29 - 22
contrib/src/sceneeditor/seParticlePanel.py

@@ -2,9 +2,7 @@
 
 
 # Import Tkinter, Pmw, and the floater code from this directory tree.
 # Import Tkinter, Pmw, and the floater code from this directory tree.
 from direct.tkwidgets.AppShell import AppShell
 from direct.tkwidgets.AppShell import AppShell
-from tkFileDialog import *
-from tkSimpleDialog import askstring
-import os, Pmw, Tkinter
+import os, Pmw, sys
 from direct.tkwidgets.Dial import AngleDial
 from direct.tkwidgets.Dial import AngleDial
 from direct.tkwidgets.Floater import Floater
 from direct.tkwidgets.Floater import Floater
 from direct.tkwidgets.Slider import Slider
 from direct.tkwidgets.Slider import Slider
@@ -15,6 +13,15 @@ import seForceGroup
 import seParticles
 import seParticles
 import seParticleEffect
 import seParticleEffect
 
 
+
+if sys.version_info >= (3, 0):
+    from tkinter.filedialog import *
+    from tkinter.simpledialog import askstring
+else:
+    from tkFileDialog import *
+    from tkSimpleDialog import askstring
+
+
 class ParticlePanel(AppShell):
 class ParticlePanel(AppShell):
     # Override class variables
     # Override class variables
     appname = 'Particle Panel'
     appname = 'Particle Panel'
@@ -774,7 +781,7 @@ class ParticlePanel(AppShell):
         kw['min'] = min
         kw['min'] = min
         kw['resolution'] = resolution
         kw['resolution'] = resolution
         kw['numDigits'] = numDigits
         kw['numDigits'] = numDigits
-        widget = apply(Floater, (parent,), kw)
+        widget = Floater(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
         widget.pack(fill = X)
         widget.pack(fill = X)
@@ -786,7 +793,7 @@ class ParticlePanel(AppShell):
                         command = None, **kw):
                         command = None, **kw):
         kw['text'] = text
         kw['text'] = text
         kw['style'] = 'mini'
         kw['style'] = 'mini'
-        widget = apply(AngleDial,(parent,), kw)
+        widget = AngleDial(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
         widget.pack(fill = X)
         widget.pack(fill = X)
@@ -801,7 +808,7 @@ class ParticlePanel(AppShell):
         kw['min'] = min
         kw['min'] = min
         kw['max'] = max
         kw['max'] = max
         kw['resolution'] = resolution
         kw['resolution'] = resolution
-        widget = apply(Slider, (parent,), kw)
+        widget = Slider(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
         widget.pack(fill = X)
         widget.pack(fill = X)
@@ -813,7 +820,7 @@ class ParticlePanel(AppShell):
                            command = None, **kw):
                            command = None, **kw):
         # Set label's text
         # Set label's text
         kw['text'] = text
         kw['text'] = text
-        widget = apply(Vector2Entry, (parent,), kw)
+        widget = Vector2Entry(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
         widget.pack(fill = X)
         widget.pack(fill = X)
@@ -825,7 +832,7 @@ class ParticlePanel(AppShell):
                            command = None, **kw):
                            command = None, **kw):
         # Set label's text
         # Set label's text
         kw['text'] = text
         kw['text'] = text
-        widget = apply(Vector3Entry, (parent,), kw)
+        widget = Vector3Entry(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
         widget.pack(fill = X)
         widget.pack(fill = X)
@@ -837,7 +844,7 @@ class ParticlePanel(AppShell):
                          command = None, **kw):
                          command = None, **kw):
         # Set label's text
         # Set label's text
         kw['text'] = text
         kw['text'] = text
-        widget = apply(ColorEntry, (parent,) ,kw)
+        widget = ColorEntry(parent, **kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
         widget.pack(fill = X)
         widget.pack(fill = X)
@@ -992,7 +999,7 @@ class ParticlePanel(AppShell):
             self.mainNotebook.selectpage('System')
             self.mainNotebook.selectpage('System')
             self.updateInfo('System')
             self.updateInfo('System')
         else:
         else:
-            print 'ParticlePanel: No effect named ' + name
+            print('ParticlePanel: No effect named ' + name)
 
 
     def toggleEffect(self, effect, var):
     def toggleEffect(self, effect, var):
         if var.get():
         if var.get():
@@ -1041,15 +1048,15 @@ class ParticlePanel(AppShell):
         # Find path to particle directory
         # Find path to particle directory
         pPath = getParticlePath()
         pPath = getParticlePath()
         if pPath.getNumDirectories() > 0:
         if pPath.getNumDirectories() > 0:
-            if `pPath.getDirectory(0)` == '.':
+            if repr(pPath.getDirectory(0)) == '.':
                 path = '.'
                 path = '.'
             else:
             else:
                 path = pPath.getDirectory(0).toOsSpecific()
                 path = pPath.getDirectory(0).toOsSpecific()
         else:
         else:
             path = '.'
             path = '.'
         if not os.path.isdir(path):
         if not os.path.isdir(path):
-            print 'ParticlePanel Warning: Invalid default DNA directory!'
-            print 'Using current directory'
+            print('ParticlePanel Warning: Invalid default DNA directory!')
+            print('Using current directory')
             path = '.'
             path = '.'
         particleFilename = askopenfilename(
         particleFilename = askopenfilename(
             defaultextension = '.ptf',
             defaultextension = '.ptf',
@@ -1070,15 +1077,15 @@ class ParticlePanel(AppShell):
         # Find path to particle directory
         # Find path to particle directory
         pPath = getParticlePath()
         pPath = getParticlePath()
         if pPath.getNumDirectories() > 0:
         if pPath.getNumDirectories() > 0:
-            if `pPath.getDirectory(0)` == '.':
+            if repr(pPath.getDirectory(0)) == '.':
                 path = '.'
                 path = '.'
             else:
             else:
                 path = pPath.getDirectory(0).toOsSpecific()
                 path = pPath.getDirectory(0).toOsSpecific()
         else:
         else:
             path = '.'
             path = '.'
         if not os.path.isdir(path):
         if not os.path.isdir(path):
-            print 'ParticlePanel Warning: Invalid default DNA directory!'
-            print 'Using current directory'
+            print('ParticlePanel Warning: Invalid default DNA directory!')
+            print('Using current directory')
             path = '.'
             path = '.'
         particleFilename = asksaveasfilename(
         particleFilename = asksaveasfilename(
             defaultextension = '.ptf',
             defaultextension = '.ptf',
@@ -1654,7 +1661,7 @@ class ParticlePanel(AppShell):
     def setRendererSpriteNonAnimatedTheta(self, theta):
     def setRendererSpriteNonAnimatedTheta(self, theta):
         self.particles.renderer.setNonanimatedTheta(theta)
         self.particles.renderer.setNonanimatedTheta(theta)
     def setRendererSpriteBlendMethod(self, blendMethod):
     def setRendererSpriteBlendMethod(self, blendMethod):
-        print blendMethod
+        print(blendMethod)
         if blendMethod == 'PP_NO_BLEND':
         if blendMethod == 'PP_NO_BLEND':
             bMethod = BaseParticleRenderer.PPNOBLEND
             bMethod = BaseParticleRenderer.PPNOBLEND
         elif blendMethod == 'PP_BLEND_LINEAR':
         elif blendMethod == 'PP_BLEND_LINEAR':
@@ -1863,7 +1870,7 @@ class ParticlePanel(AppShell):
                                       count, force):
                                       count, force):
         def setVec(vec, f = force):
         def setVec(vec, f = force):
             f.setVector(vec[0], vec[1], vec[2])
             f.setVector(vec[0], vec[1], vec[2])
-        forceName = 'Vector Force-' + `count`
+        forceName = 'Vector Force-' + repr(count)
         frame = self.createForceFrame(forcePage, forceName, force)
         frame = self.createForceFrame(forcePage, forceName, force)
         self.createLinearForceWidgets(frame, pageName, forceName, force)
         self.createLinearForceWidgets(frame, pageName, forceName, force)
         vec = force.getLocalVector()
         vec = force.getLocalVector()
@@ -1875,7 +1882,7 @@ class ParticlePanel(AppShell):
 
 
     def createLinearRandomForceWidget(self, forcePage, pageName, count,
     def createLinearRandomForceWidget(self, forcePage, pageName, count,
                                 force, type):
                                 force, type):
-        forceName = type + ' Force-' + `count`
+        forceName = type + ' Force-' + repr(count)
         frame = self.createForceFrame(forcePage, forceName, force)
         frame = self.createForceFrame(forcePage, forceName, force)
         self.createLinearForceWidgets(frame, pageName, forceName, force)
         self.createLinearForceWidgets(frame, pageName, forceName, force)
         self.createForceActiveWidget(frame, pageName, forceName, force)
         self.createForceActiveWidget(frame, pageName, forceName, force)
@@ -1884,7 +1891,7 @@ class ParticlePanel(AppShell):
                                         count, force):
                                         count, force):
         def setCoef(coef, f = force):
         def setCoef(coef, f = force):
             f.setCoef(coef)
             f.setCoef(coef)
-        forceName = 'Friction Force-' + `count`
+        forceName = 'Friction Force-' + repr(count)
         frame = self.createForceFrame(forcePage, forceName, force)
         frame = self.createForceFrame(forcePage, forceName, force)
         self.createLinearForceWidgets(frame, pageName, forceName, force)
         self.createLinearForceWidgets(frame, pageName, forceName, force)
         self.createFloater(frame, pageName, forceName + ' Coef',
         self.createFloater(frame, pageName, forceName + ' Coef',
@@ -1895,7 +1902,7 @@ class ParticlePanel(AppShell):
 
 
     def createLinearCylinderVortexForceWidget(self, forcePage, pageName,
     def createLinearCylinderVortexForceWidget(self, forcePage, pageName,
                                               count, force):
                                               count, force):
-        forceName = 'Vortex Force-' + `count`
+        forceName = 'Vortex Force-' + repr(count)
         def setCoef(coef, f = force):
         def setCoef(coef, f = force):
             f.setCoef(coef)
             f.setCoef(coef)
         def setLength(length, f = force):
         def setLength(length, f = force):
@@ -1934,7 +1941,7 @@ class ParticlePanel(AppShell):
             f.setForceCenter(Point3(vec[0], vec[1], vec[2]))
             f.setForceCenter(Point3(vec[0], vec[1], vec[2]))
         def setRadius(radius, f = force):
         def setRadius(radius, f = force):
             f.setRadius(radius)
             f.setRadius(radius)
-        forceName = type + ' Force-' + `count`
+        forceName = type + ' Force-' + repr(count)
         frame = self.createForceFrame(forcePage, forceName, force)
         frame = self.createForceFrame(forcePage, forceName, force)
         self.createLinearForceWidgets(frame, pageName, forceName, force)
         self.createLinearForceWidgets(frame, pageName, forceName, force)
         var = self.createOptionMenu(
         var = self.createOptionMenu(

+ 5 - 25
contrib/src/sceneeditor/seParticles.py

@@ -1,28 +1,8 @@
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.physics import *
 from direct.particles.ParticleManagerGlobal import *
 from direct.particles.ParticleManagerGlobal import *
 from direct.showbase.PhysicsManagerGlobal import *
 from direct.showbase.PhysicsManagerGlobal import *
-#Manakel 2/12/2005: replace from pandac import by from pandac.PandaModules import
-from pandac.PandaModules import ParticleSystem
-from pandac.PandaModules import BaseParticleFactory
-from pandac.PandaModules import PointParticleFactory
-from pandac.PandaModules import ZSpinParticleFactory
 #import OrientedParticleFactory
 #import OrientedParticleFactory
-from pandac.PandaModules import BaseParticleRenderer
-from pandac.PandaModules import PointParticleRenderer
-from pandac.PandaModules import LineParticleRenderer
-from pandac.PandaModules import GeomParticleRenderer
-from pandac.PandaModules import SparkleParticleRenderer
-from pandac.PandaModules import SpriteParticleRenderer
-from pandac.PandaModules import BaseParticleEmitter
-from pandac.PandaModules import BoxEmitter
-from pandac.PandaModules import DiscEmitter
-from pandac.PandaModules import LineEmitter
-from pandac.PandaModules import PointEmitter
-from pandac.PandaModules import RectangleEmitter
-from pandac.PandaModules import RingEmitter
-from pandac.PandaModules import SphereSurfaceEmitter
-from pandac.PandaModules import SphereVolumeEmitter
-from pandac.PandaModules import TangentRingEmitter
 import string
 import string
 import os
 import os
 from direct.directnotify import DirectNotifyGlobal
 from direct.directnotify import DirectNotifyGlobal
@@ -113,7 +93,7 @@ class Particles(ParticleSystem):
         elif (type == "OrientedParticleFactory"):
         elif (type == "OrientedParticleFactory"):
             self.factory = OrientedParticleFactory.OrientedParticleFactory()
             self.factory = OrientedParticleFactory.OrientedParticleFactory()
         else:
         else:
-            print "unknown factory type: %s" % type
+            print("unknown factory type: %s" % type)
             return None
             return None
         self.factory.setLifespanBase(0.5)
         self.factory.setLifespanBase(0.5)
         ParticleSystem.ParticleSystem.setFactory(self, self.factory)
         ParticleSystem.ParticleSystem.setFactory(self, self.factory)
@@ -152,7 +132,7 @@ class Particles(ParticleSystem):
                 # See sourceFileName and sourceNodeName in SpriteParticleRenderer-extensions.py
                 # See sourceFileName and sourceNodeName in SpriteParticleRenderer-extensions.py
                 self.renderer.setTextureFromNode()
                 self.renderer.setTextureFromNode()
         else:
         else:
-            print "unknown renderer type: %s" % type
+            print("unknown renderer type: %s" % type)
             return None
             return None
         ParticleSystem.ParticleSystem.setRenderer(self, self.renderer)
         ParticleSystem.ParticleSystem.setRenderer(self, self.renderer)
 
 
@@ -183,7 +163,7 @@ class Particles(ParticleSystem):
         elif (type == "TangentRingEmitter"):
         elif (type == "TangentRingEmitter"):
             self.emitter = TangentRingEmitter.TangentRingEmitter()
             self.emitter = TangentRingEmitter.TangentRingEmitter()
         else:
         else:
-            print "unknown emitter type: %s" % type
+            print("unknown emitter type: %s" % type)
             return None
             return None
         ParticleSystem.ParticleSystem.setEmitter(self, self.emitter)
         ParticleSystem.ParticleSystem.setEmitter(self, self.emitter)
 
 

+ 34 - 27
contrib/src/sceneeditor/sePlacer.py

@@ -5,9 +5,16 @@ from direct.directtools.DirectGlobals import *
 from direct.tkwidgets.AppShell import AppShell
 from direct.tkwidgets.AppShell import AppShell
 from direct.tkwidgets.Dial import AngleDial
 from direct.tkwidgets.Dial import AngleDial
 from direct.tkwidgets.Floater import Floater
 from direct.tkwidgets.Floater import Floater
-from Tkinter import Button, Menubutton, Menu, StringVar
-from pandac.PandaModules import *
-import Tkinter, Pmw
+from panda3d.core import *
+import sys, Pmw
+
+if sys.version_info >= (3, 0):
+    from tkinter import Button, Menubutton, Menu, StringVar
+    import tkinter
+else:
+    from Tkinter import Button, Menubutton, Menu, StringVar
+    import Tkinter as tkinter
+
 """
 """
 TODO:
 TODO:
 Task to monitor pose
 Task to monitor pose
@@ -84,7 +91,7 @@ class Placer(AppShell):
     def createInterface(self):
     def createInterface(self):
         # The interior of the toplevel panel
         # The interior of the toplevel panel
         interior = self.interior()
         interior = self.interior()
-        interior['relief'] = Tkinter.FLAT
+        interior['relief'] = tkinter.FLAT
         # Add placer commands to menubar
         # Add placer commands to menubar
         self.menuBar.addmenu('Placer', 'Placer Panel Operations')
         self.menuBar.addmenu('Placer', 'Placer Panel Operations')
         self.menuBar.addmenuitem('Placer', 'command',
         self.menuBar.addmenuitem('Placer', 'command',
@@ -113,7 +120,7 @@ class Placer(AppShell):
         # Get a handle to the menu frame
         # Get a handle to the menu frame
         menuFrame = self.menuFrame
         menuFrame = self.menuFrame
         self.nodePathMenu = Pmw.ComboBox(
         self.nodePathMenu = Pmw.ComboBox(
-            menuFrame, labelpos = Tkinter.W, label_text = 'Node Path:',
+            menuFrame, labelpos = tkinter.W, label_text = 'Node Path:',
             entry_width = 20,
             entry_width = 20,
             selectioncommand = self.selectNodePathNamed,
             selectioncommand = self.selectNodePathNamed,
             scrolledlist_items = self.nodePathNames)
             scrolledlist_items = self.nodePathNames)
@@ -168,7 +175,7 @@ class Placer(AppShell):
                              tag_text = 'Position',
                              tag_text = 'Position',
                              tag_font=('MSSansSerif', 14),
                              tag_font=('MSSansSerif', 14),
                              tag_activebackground = '#909090',
                              tag_activebackground = '#909090',
-                             ring_relief = Tkinter.RIDGE)
+                             ring_relief = tkinter.RIDGE)
         posMenubutton = posGroup.component('tag')
         posMenubutton = posGroup.component('tag')
         self.bind(posMenubutton, 'Position menu operations')
         self.bind(posMenubutton, 'Position menu operations')
         posMenu = Menu(posMenubutton, tearoff = 0)
         posMenu = Menu(posMenubutton, tearoff = 0)
@@ -182,7 +189,7 @@ class Placer(AppShell):
         # Create the dials
         # Create the dials
         self.posX = self.createcomponent('posX', (), None,
         self.posX = self.createcomponent('posX', (), None,
                                          Floater, (posInterior,),
                                          Floater, (posInterior,),
-                                         text = 'X', relief = Tkinter.FLAT,
+                                         text = 'X', relief = tkinter.FLAT,
                                          value = 0.0,
                                          value = 0.0,
                                          label_foreground = 'Red')
                                          label_foreground = 'Red')
         self.posX['commandData'] = ['x']
         self.posX['commandData'] = ['x']
@@ -193,7 +200,7 @@ class Placer(AppShell):
 
 
         self.posY = self.createcomponent('posY', (), None,
         self.posY = self.createcomponent('posY', (), None,
                                          Floater, (posInterior,),
                                          Floater, (posInterior,),
-                                         text = 'Y', relief = Tkinter.FLAT,
+                                         text = 'Y', relief = tkinter.FLAT,
                                          value = 0.0,
                                          value = 0.0,
                                          label_foreground = '#00A000')
                                          label_foreground = '#00A000')
         self.posY['commandData'] = ['y']
         self.posY['commandData'] = ['y']
@@ -204,7 +211,7 @@ class Placer(AppShell):
 
 
         self.posZ = self.createcomponent('posZ', (), None,
         self.posZ = self.createcomponent('posZ', (), None,
                                          Floater, (posInterior,),
                                          Floater, (posInterior,),
-                                         text = 'Z', relief = Tkinter.FLAT,
+                                         text = 'Z', relief = tkinter.FLAT,
                                          value = 0.0,
                                          value = 0.0,
                                          label_foreground = 'Blue')
                                          label_foreground = 'Blue')
         self.posZ['commandData'] = ['z']
         self.posZ['commandData'] = ['z']
@@ -219,7 +226,7 @@ class Placer(AppShell):
                              tag_text = 'Orientation',
                              tag_text = 'Orientation',
                              tag_font=('MSSansSerif', 14),
                              tag_font=('MSSansSerif', 14),
                              tag_activebackground = '#909090',
                              tag_activebackground = '#909090',
-                             ring_relief = Tkinter.RIDGE)
+                             ring_relief = tkinter.RIDGE)
         hprMenubutton = hprGroup.component('tag')
         hprMenubutton = hprGroup.component('tag')
         self.bind(hprMenubutton, 'Orientation menu operations')
         self.bind(hprMenubutton, 'Orientation menu operations')
         hprMenu = Menu(hprMenubutton, tearoff = 0)
         hprMenu = Menu(hprMenubutton, tearoff = 0)
@@ -234,7 +241,7 @@ class Placer(AppShell):
                                          AngleDial, (hprInterior,),
                                          AngleDial, (hprInterior,),
                                          style = 'mini',
                                          style = 'mini',
                                          text = 'H', value = 0.0,
                                          text = 'H', value = 0.0,
-                                         relief = Tkinter.FLAT,
+                                         relief = tkinter.FLAT,
                                          label_foreground = 'blue')
                                          label_foreground = 'blue')
         self.hprH['commandData'] = ['h']
         self.hprH['commandData'] = ['h']
         self.hprH['preCallback'] = self.xformStart
         self.hprH['preCallback'] = self.xformStart
@@ -246,7 +253,7 @@ class Placer(AppShell):
                                          AngleDial, (hprInterior,),
                                          AngleDial, (hprInterior,),
                                          style = 'mini',
                                          style = 'mini',
                                          text = 'P', value = 0.0,
                                          text = 'P', value = 0.0,
-                                         relief = Tkinter.FLAT,
+                                         relief = tkinter.FLAT,
                                          label_foreground = 'red')
                                          label_foreground = 'red')
         self.hprP['commandData'] = ['p']
         self.hprP['commandData'] = ['p']
         self.hprP['preCallback'] = self.xformStart
         self.hprP['preCallback'] = self.xformStart
@@ -258,7 +265,7 @@ class Placer(AppShell):
                                          AngleDial, (hprInterior,),
                                          AngleDial, (hprInterior,),
                                          style = 'mini',
                                          style = 'mini',
                                          text = 'R', value = 0.0,
                                          text = 'R', value = 0.0,
-                                         relief = Tkinter.FLAT,
+                                         relief = tkinter.FLAT,
                                          label_foreground = '#00A000')
                                          label_foreground = '#00A000')
         self.hprR['commandData'] = ['r']
         self.hprR['commandData'] = ['r']
         self.hprR['preCallback'] = self.xformStart
         self.hprR['preCallback'] = self.xformStart
@@ -276,7 +283,7 @@ class Placer(AppShell):
                                tag_pyclass = Menubutton,
                                tag_pyclass = Menubutton,
                                tag_font=('MSSansSerif', 14),
                                tag_font=('MSSansSerif', 14),
                                tag_activebackground = '#909090',
                                tag_activebackground = '#909090',
-                               ring_relief = Tkinter.RIDGE)
+                               ring_relief = tkinter.RIDGE)
         self.scaleMenubutton = scaleGroup.component('tag')
         self.scaleMenubutton = scaleGroup.component('tag')
         self.bind(self.scaleMenubutton, 'Scale menu operations')
         self.bind(self.scaleMenubutton, 'Scale menu operations')
         self.scaleMenubutton['textvariable'] = self.scalingMode
         self.scaleMenubutton['textvariable'] = self.scalingMode
@@ -302,7 +309,7 @@ class Placer(AppShell):
         self.scaleX = self.createcomponent('scaleX', (), None,
         self.scaleX = self.createcomponent('scaleX', (), None,
                                            Floater, (scaleInterior,),
                                            Floater, (scaleInterior,),
                                            text = 'X Scale',
                                            text = 'X Scale',
-                                           relief = Tkinter.FLAT,
+                                           relief = tkinter.FLAT,
                                            min = 0.0001, value = 1.0,
                                            min = 0.0001, value = 1.0,
                                            resetValue = 1.0,
                                            resetValue = 1.0,
                                            label_foreground = 'Red')
                                            label_foreground = 'Red')
@@ -315,7 +322,7 @@ class Placer(AppShell):
         self.scaleY = self.createcomponent('scaleY', (), None,
         self.scaleY = self.createcomponent('scaleY', (), None,
                                            Floater, (scaleInterior,),
                                            Floater, (scaleInterior,),
                                            text = 'Y Scale',
                                            text = 'Y Scale',
-                                           relief = Tkinter.FLAT,
+                                           relief = tkinter.FLAT,
                                            min = 0.0001, value = 1.0,
                                            min = 0.0001, value = 1.0,
                                            resetValue = 1.0,
                                            resetValue = 1.0,
                                            label_foreground = '#00A000')
                                            label_foreground = '#00A000')
@@ -328,7 +335,7 @@ class Placer(AppShell):
         self.scaleZ = self.createcomponent('scaleZ', (), None,
         self.scaleZ = self.createcomponent('scaleZ', (), None,
                                            Floater, (scaleInterior,),
                                            Floater, (scaleInterior,),
                                            text = 'Z Scale',
                                            text = 'Z Scale',
-                                           relief = Tkinter.FLAT,
+                                           relief = tkinter.FLAT,
                                            min = 0.0001, value = 1.0,
                                            min = 0.0001, value = 1.0,
                                            resetValue = 1.0,
                                            resetValue = 1.0,
                                            label_foreground = 'Blue')
                                            label_foreground = 'Blue')
@@ -428,7 +435,7 @@ class Placer(AppShell):
                 background = self.nodePathMenuBG)
                 background = self.nodePathMenuBG)
             # Check to see if node path and ref node path are the same
             # Check to see if node path and ref node path are the same
             if ((self.refCS != None) and
             if ((self.refCS != None) and
-                (self.refCS.id() == self['nodePath'].id())):
+                (self.refCS.get_key() == self['nodePath'].get_key())):
                 # Yes they are, use temp CS as ref
                 # Yes they are, use temp CS as ref
                 # This calls updatePlacer
                 # This calls updatePlacer
                 self.setReferenceNodePath(self.tempCS)
                 self.setReferenceNodePath(self.tempCS)
@@ -473,7 +480,7 @@ class Placer(AppShell):
                     listbox = self.refNodePathMenu.component('scrolledlist')
                     listbox = self.refNodePathMenu.component('scrolledlist')
                     listbox.setlist(self.refNodePathNames)
                     listbox.setlist(self.refNodePathNames)
         # Check to see if node path and ref node path are the same
         # Check to see if node path and ref node path are the same
-        if (nodePath != None) and (nodePath.id() == self['nodePath'].id()):
+        if (nodePath != None) and (nodePath.get_key() == self['nodePath'].get_key()):
             # Yes they are, use temp CS and update listbox accordingly
             # Yes they are, use temp CS and update listbox accordingly
             nodePath = self.tempCS
             nodePath = self.tempCS
             self.refNodePathMenu.selectitem('parent')
             self.refNodePathMenu.selectitem('parent')
@@ -508,8 +515,8 @@ class Placer(AppShell):
             dictName = name
             dictName = name
         else:
         else:
             # Generate a unique name for the dict
             # Generate a unique name for the dict
-            dictName = name + '-' + `nodePath.id()`
-        if not dict.has_key(dictName):
+            dictName = name + '-' + repr(nodePath.get_key())
+        if dictName not in dict:
             # Update combo box to include new item
             # Update combo box to include new item
             names.append(dictName)
             names.append(dictName)
             listbox = menu.component('scrolledlist')
             listbox = menu.component('scrolledlist')
@@ -769,12 +776,12 @@ class Placer(AppShell):
             posString = '%.2f, %.2f, %.2f' % (pos[0], pos[1], pos[2])
             posString = '%.2f, %.2f, %.2f' % (pos[0], pos[1], pos[2])
             hprString = '%.2f, %.2f, %.2f' % (hpr[0], hpr[1], hpr[2])
             hprString = '%.2f, %.2f, %.2f' % (hpr[0], hpr[1], hpr[2])
             scaleString = '%.2f, %.2f, %.2f' % (scale[0], scale[1], scale[2])
             scaleString = '%.2f, %.2f, %.2f' % (scale[0], scale[1], scale[2])
-            print 'NodePath: %s' % name
-            print 'Pos: %s' % posString
-            print 'Hpr: %s' % hprString
-            print 'Scale: %s' % scaleString
-            print ('%s.setPosHprScale(%s, %s, %s)' %
-                   (name, posString, hprString, scaleString))
+            print('NodePath: %s' % name)
+            print('Pos: %s' % posString)
+            print('Hpr: %s' % hprString)
+            print('Scale: %s' % scaleString)
+            print(('%s.setPosHprScale(%s, %s, %s)' %
+                   (name, posString, hprString, scaleString)))
 
 
     def onDestroy(self, event):
     def onDestroy(self, event):
         # Remove hooks
         # Remove hooks

+ 16 - 9
contrib/src/sceneeditor/seSceneGraphExplorer.py

@@ -9,9 +9,16 @@
 #
 #
 #################################################################
 #################################################################
 from direct.showbase.DirectObject import DirectObject
 from direct.showbase.DirectObject import DirectObject
-from Tkinter import IntVar, Frame, Label
 from seTree import TreeNode, TreeItem
 from seTree import TreeNode, TreeItem
-import Pmw, Tkinter
+
+import Pmw, sys
+
+if sys.version_info >= (3, 0):
+    from tkinter import IntVar, Frame, Label
+    import tkinter
+else:
+    from Tkinter import IntVar, Frame, Label
+    import Tkinter as tkinter
 
 
 # changing these strings requires changing sceneEditor.py SGE_ strs too!
 # changing these strings requires changing sceneEditor.py SGE_ strs too!
 # This list of items will be showed on the pop out window when user right click on
 # This list of items will be showed on the pop out window when user right click on
@@ -57,7 +64,7 @@ class seSceneGraphExplorer(Pmw.MegaWidget, DirectObject):
 
 
         # Setup up container
         # Setup up container
         interior = self.interior()
         interior = self.interior()
-        interior.configure(relief = Tkinter.GROOVE, borderwidth = 2)
+        interior.configure(relief = tkinter.GROOVE, borderwidth = 2)
 
 
         # Create a label and an entry
         # Create a label and an entry
         self._scrolledCanvas = self.createcomponent(
         self._scrolledCanvas = self.createcomponent(
@@ -69,7 +76,7 @@ class seSceneGraphExplorer(Pmw.MegaWidget, DirectObject):
         self._canvas = self._scrolledCanvas.component('canvas')
         self._canvas = self._scrolledCanvas.component('canvas')
         self._canvas['scrollregion'] = ('0i', '0i', '2i', '4i')
         self._canvas['scrollregion'] = ('0i', '0i', '2i', '4i')
         self._scrolledCanvas.resizescrollregion()
         self._scrolledCanvas.resizescrollregion()
-        self._scrolledCanvas.pack(padx = 3, pady = 3, expand=1, fill = Tkinter.BOTH)
+        self._scrolledCanvas.pack(padx = 3, pady = 3, expand=1, fill = tkinter.BOTH)
 
 
         self._canvas.bind('<ButtonPress-2>', self.mouse2Down)
         self._canvas.bind('<ButtonPress-2>', self.mouse2Down)
         self._canvas.bind('<B2-Motion>', self.mouse2Motion)
         self._canvas.bind('<B2-Motion>', self.mouse2Motion)
@@ -91,8 +98,8 @@ class seSceneGraphExplorer(Pmw.MegaWidget, DirectObject):
             (), None,
             (), None,
             Label, (interior,),
             Label, (interior,),
             text = 'Active Reparent Target: ',
             text = 'Active Reparent Target: ',
-            anchor = Tkinter.W, justify = Tkinter.LEFT)
-        self._label.pack(fill = Tkinter.X)
+            anchor = tkinter.W, justify = tkinter.LEFT)
+        self._label.pack(fill = tkinter.X)
 
 
         # Add update parent label
         # Add update parent label
         def updateLabel(nodePath = None, s = self):
         def updateLabel(nodePath = None, s = self):
@@ -141,11 +148,11 @@ class seSceneGraphExplorer(Pmw.MegaWidget, DirectObject):
         self._node.deselecttree()
         self._node.deselecttree()
 
 
     def selectNodePath(self,nodePath, callBack=True):
     def selectNodePath(self,nodePath, callBack=True):
-        item = self._node.find(nodePath.id())
+        item = self._node.find(nodePath.get_key())
         if item!= None:
         if item!= None:
             item.select(callBack)
             item.select(callBack)
         else:
         else:
-            print '----SGE: Error Selection'
+            print('----SGE: Error Selection')
 
 
 class SceneGraphExplorerItem(TreeItem):
 class SceneGraphExplorerItem(TreeItem):
 
 
@@ -164,7 +171,7 @@ class SceneGraphExplorerItem(TreeItem):
         return name
         return name
 
 
     def GetKey(self):
     def GetKey(self):
-        return self.nodePath.id()
+        return self.nodePath.get_key()
 
 
     def IsEditable(self):
     def IsEditable(self):
         # All nodes' names can be edited nowadays.
         # All nodes' names can be edited nowadays.

+ 20 - 11
contrib/src/sceneeditor/seSelection.py

@@ -11,7 +11,7 @@
 # (If we do change original directools, it will force user has to install the latest version of OUR Panda)
 # (If we do change original directools, it will force user has to install the latest version of OUR Panda)
 #
 #
 #################################################################
 #################################################################
-from pandac.PandaModules import GeomNode
+from panda3d.core import GeomNode
 from direct.directtools.DirectGlobals import *
 from direct.directtools.DirectGlobals import *
 from direct.directtools.DirectUtil import *
 from direct.directtools.DirectUtil import *
 from seGeometry import *
 from seGeometry import *
@@ -70,7 +70,7 @@ class SelectedNodePaths(DirectObject):
         """ Select the specified node path.  Multiselect as required """
         """ Select the specified node path.  Multiselect as required """
         # Do nothing if nothing selected
         # Do nothing if nothing selected
         if not nodePath:
         if not nodePath:
-            print 'Nothing selected!!'
+            print('Nothing selected!!')
             return None
             return None
 
 
         # Reset selected objects and highlight if multiSelect is false
         # Reset selected objects and highlight if multiSelect is false
@@ -78,7 +78,7 @@ class SelectedNodePaths(DirectObject):
             self.deselectAll()
             self.deselectAll()
 
 
         # Get this pointer
         # Get this pointer
-        id = nodePath.id()
+        id = nodePath.get_key()
         # First see if its already in the selected dictionary
         # First see if its already in the selected dictionary
         dnp = self.getSelectedDict(id)
         dnp = self.getSelectedDict(id)
         # If so, we're done
         # If so, we're done
@@ -96,7 +96,7 @@ class SelectedNodePaths(DirectObject):
                 # Show its bounding box
                 # Show its bounding box
                 dnp.highlight()
                 dnp.highlight()
             # Add it to the selected dictionary
             # Add it to the selected dictionary
-            self.selectedDict[dnp.id()] = dnp
+            self.selectedDict[dnp.get_key()] = dnp
         # And update last
         # And update last
         __builtins__["last"] = self.last = dnp
         __builtins__["last"] = self.last = dnp
         return dnp
         return dnp
@@ -104,7 +104,7 @@ class SelectedNodePaths(DirectObject):
     def deselect(self, nodePath):
     def deselect(self, nodePath):
         """ Deselect the specified node path """
         """ Deselect the specified node path """
         # Get this pointer
         # Get this pointer
-        id = nodePath.id()
+        id = nodePath.get_key()
         # See if it is in the selected dictionary
         # See if it is in the selected dictionary
         dnp = self.getSelectedDict(id)
         dnp = self.getSelectedDict(id)
         if dnp:
         if dnp:
@@ -124,7 +124,7 @@ class SelectedNodePaths(DirectObject):
         Return a list of all selected node paths.  No verification of
         Return a list of all selected node paths.  No verification of
         connectivity is performed on the members of the list
         connectivity is performed on the members of the list
         """
         """
-        return self.selectedDict.values()[:]
+        return list(self.selectedDict.values())
 
 
     def __getitem__(self,index):
     def __getitem__(self,index):
         return self.getSelectedAsList()[index]
         return self.getSelectedAsList()[index]
@@ -141,7 +141,7 @@ class SelectedNodePaths(DirectObject):
             return None
             return None
 
 
     def getDeselectedAsList(self):
     def getDeselectedAsList(self):
-        return self.deselectedDict.values()[:]
+        return list(self.deselectedDict.values())
 
 
     def getDeselectedDict(self, id):
     def getDeselectedDict(self, id):
         """
         """
@@ -204,15 +204,24 @@ class SelectedNodePaths(DirectObject):
         # Remove all selected nodePaths from the Scene Graph
         # Remove all selected nodePaths from the Scene Graph
         self.forEachSelectedNodePathDo(NodePath.remove)
         self.forEachSelectedNodePathDo(NodePath.remove)
 
 
+    def toggleVis(self, nodePath):
+        if nodePath.is_hidden():
+            nodePath.show()
+        else:
+            nodePath.hide()
+
     def toggleVisSelected(self):
     def toggleVisSelected(self):
         selected = self.last
         selected = self.last
         # Toggle visibility of selected node paths
         # Toggle visibility of selected node paths
         if selected:
         if selected:
-            selected.toggleVis()
+            if selected.is_hidden():
+                selected.show()
+            else:
+                selected.hide()
 
 
     def toggleVisAll(self):
     def toggleVisAll(self):
         # Toggle viz for all selected node paths
         # Toggle viz for all selected node paths
-        self.forEachSelectedNodePathDo(NodePath.toggleVis)
+        self.forEachSelectedNodePathDo(self.toggleVis)
 
 
     def isolateSelected(self):
     def isolateSelected(self):
         selected = self.last
         selected = self.last
@@ -221,7 +230,7 @@ class SelectedNodePaths(DirectObject):
 
 
     def getDirectNodePath(self, nodePath):
     def getDirectNodePath(self, nodePath):
         # Get this pointer
         # Get this pointer
-        id = nodePath.id()
+        id = nodePath.get_key()
         # First check selected dict
         # First check selected dict
         dnp = self.getSelectedDict(id)
         dnp = self.getSelectedDict(id)
         if dnp:
         if dnp:
@@ -376,7 +385,7 @@ class DirectBoundingBox:
         return '%.2f %.2f %.2f' % (vec[0], vec[1], vec[2])
         return '%.2f %.2f %.2f' % (vec[0], vec[1], vec[2])
 
 
     def __repr__(self):
     def __repr__(self):
-        return (`self.__class__` +
+        return (repr(self.__class__) +
                 '\nNodePath:\t%s\n' % self.nodePath.getName() +
                 '\nNodePath:\t%s\n' % self.nodePath.getName() +
                 'Min:\t\t%s\n' % self.vecAsString(self.min) +
                 'Min:\t\t%s\n' % self.vecAsString(self.min) +
                 'Max:\t\t%s\n' % self.vecAsString(self.max) +
                 'Max:\t\t%s\n' % self.vecAsString(self.max) +

+ 9 - 6
contrib/src/sceneeditor/seSession.py

@@ -388,7 +388,7 @@ class SeSession(DirectObject):  ### Customized DirectSession
             messenger.send('DIRECT_preSelectNodePath', [dnp])
             messenger.send('DIRECT_preSelectNodePath', [dnp])
             if fResetAncestry:
             if fResetAncestry:
                 # Update ancestry
                 # Update ancestry
-                self.ancestry = dnp.getAncestors()
+                self.ancestry = list(dnp.getAncestors())
                 self.ancestry.reverse()
                 self.ancestry.reverse()
                 self.ancestryIndex = 0
                 self.ancestryIndex = 0
             # Update the selectedNPReadout
             # Update the selectedNPReadout
@@ -479,8 +479,8 @@ class SeSession(DirectObject):  ### Customized DirectSession
 
 
 
 
     def isNotCycle(self, nodePath, parent):
     def isNotCycle(self, nodePath, parent):
-        if nodePath.id() == parent.id():
-            print 'DIRECT.reparent: Invalid parent'
+        if nodePath.get_key() == parent.get_key():
+            print('DIRECT.reparent: Invalid parent')
             return 0
             return 0
         elif parent.hasParent():
         elif parent.hasParent():
             return self.isNotCycle(nodePath, parent.getParent())
             return self.isNotCycle(nodePath, parent.getParent())
@@ -520,7 +520,10 @@ class SeSession(DirectObject):  ### Customized DirectSession
             nodePath = self.selected.last
             nodePath = self.selected.last
         if nodePath:
         if nodePath:
             # Now toggle node path's visibility state
             # Now toggle node path's visibility state
-            nodePath.toggleVis()
+            if nodePath.is_hidden():
+                nodePath.show()
+            else:
+                nodePath.hide()
 
 
     def removeNodePath(self, nodePath = 'None Given'):
     def removeNodePath(self, nodePath = 'None Given'):
         if nodePath == 'None Given':
         if nodePath == 'None Given':
@@ -732,8 +735,8 @@ class SeSession(DirectObject):  ### Customized DirectSession
         hprB = base.camera.getHpr()
         hprB = base.camera.getHpr()
         posE = Point3((radius*-1.41)+center.getX(), (radius*-1.41)+center.getY(), (radius*1.41)+center.getZ())
         posE = Point3((radius*-1.41)+center.getX(), (radius*-1.41)+center.getY(), (radius*1.41)+center.getZ())
         hprE = Point3(-45, -38, 0)
         hprE = Point3(-45, -38, 0)
-        print posB, hprB
-        print posE, hprE
+        print(posB, hprB)
+        print(posE, hprE)
         posInterval1 = base.camera.posInterval(time, posE, bakeInStart = 1)
         posInterval1 = base.camera.posInterval(time, posE, bakeInStart = 1)
         posInterval2 = base.camera.posInterval(time, posB, bakeInStart = 1)
         posInterval2 = base.camera.posInterval(time, posB, bakeInStart = 1)
 
 

+ 15 - 9
contrib/src/sceneeditor/seTree.py

@@ -12,15 +12,21 @@
 #
 #
 #################################################################
 #################################################################
 
 
-import os, sys, string, Pmw, Tkinter
+import os, sys, string, Pmw
 from direct.showbase.DirectObject import DirectObject
 from direct.showbase.DirectObject import DirectObject
-from Tkinter import IntVar, Menu, PhotoImage, Label, Frame, Entry
-from pandac.PandaModules import *
+from panda3d.core import *
+
+if sys.version_info >= (3, 0):
+    import tkinter
+    from tkinter import IntVar, Menu, PhotoImage, Label, Frame, Entry
+else:
+    import Tkinter as tkinter
+    from Tkinter import IntVar, Menu, PhotoImage, Label, Frame, Entry
 
 
 # Initialize icon directory
 # Initialize icon directory
 ICONDIR = getModelPath().findFile(Filename('icons')).toOsSpecific()
 ICONDIR = getModelPath().findFile(Filename('icons')).toOsSpecific()
 if not os.path.isdir(ICONDIR):
 if not os.path.isdir(ICONDIR):
-    raise RuntimeError, "can't find DIRECT icon directory (%s)" % `ICONDIR`
+    raise RuntimeError("can't find DIRECT icon directory (%r)" % ICONDIR)
 
 
 class TreeNode:
 class TreeNode:
 
 
@@ -187,9 +193,9 @@ class TreeNode:
             oldcursor = self.canvas['cursor']
             oldcursor = self.canvas['cursor']
             self.canvas['cursor'] = "watch"
             self.canvas['cursor'] = "watch"
             self.canvas.update()
             self.canvas.update()
-            self.canvas.delete(Tkinter.ALL)     # XXX could be more subtle
+            self.canvas.delete(tkinter.ALL)     # XXX could be more subtle
             self.draw(7, 2)
             self.draw(7, 2)
-            x0, y0, x1, y1 = self.canvas.bbox(Tkinter.ALL)
+            x0, y0, x1, y1 = self.canvas.bbox(tkinter.ALL)
             self.canvas.configure(scrollregion=(0, 0, x1, y1))
             self.canvas.configure(scrollregion=(0, 0, x1, y1))
             self.canvas['cursor'] = oldcursor
             self.canvas['cursor'] = oldcursor
 
 
@@ -208,7 +214,7 @@ class TreeNode:
         self.kidKeys = []
         self.kidKeys = []
         for item in sublist:
         for item in sublist:
             key = item.GetKey()
             key = item.GetKey()
-            if self.children.has_key(key):
+            if key in self.children:
                 child = self.children[key]
                 child = self.children[key]
             else:
             else:
                 child = TreeNode(self.canvas, self, item, self.menuList)
                 child = TreeNode(self.canvas, self, item, self.menuList)
@@ -309,7 +315,7 @@ class TreeNode:
     def edit(self, event=None):
     def edit(self, event=None):
         self.entry = Entry(self.label, bd=0, highlightthickness=1, width=0)
         self.entry = Entry(self.label, bd=0, highlightthickness=1, width=0)
         self.entry.insert(0, self.label['text'])
         self.entry.insert(0, self.label['text'])
-        self.entry.selection_range(0, Tkinter.END)
+        self.entry.selection_range(0, tkinter.END)
         self.entry.pack(ipadx=5)
         self.entry.pack(ipadx=5)
         self.entry.focus_set()
         self.entry.focus_set()
         self.entry.bind("<Return>", self.edit_finish)
         self.entry.bind("<Return>", self.edit_finish)
@@ -344,7 +350,7 @@ class TreeNode:
         for item in sublist:
         for item in sublist:
             key = item.GetKey()
             key = item.GetKey()
             # Use existing child or create new TreeNode if none exists
             # Use existing child or create new TreeNode if none exists
-            if self.children.has_key(key):
+            if key in self.children:
                 child = self.children[key]
                 child = self.children[key]
             else:
             else:
                 child = TreeNode(self.canvas, self, item, self.menuList)
                 child = TreeNode(self.canvas, self, item, self.menuList)

+ 17 - 1
direct/src/interval/MetaInterval.py

@@ -573,7 +573,23 @@ class MetaInterval(CMetaInterval):
             out = ostream
             out = ostream
         CMetaInterval.timeline(self, out)
         CMetaInterval.timeline(self, out)
 
 
-
+    add_sequence = addSequence
+    add_parallel = addParallel
+    add_parallel_end_together = addParallelEndTogether
+    add_track = addTrack
+    add_interval = addInterval
+    set_manager = setManager
+    get_manager = getManager
+    set_t = setT
+    resume_until = resumeUntil
+    clear_to_initial = clearToInitial
+    clear_intervals = clearIntervals
+    set_play_rate = setPlayRate
+    priv_do_event = privDoEvent
+    priv_post_event = privPostEvent
+    set_interval_start_time = setIntervalStartTime
+    get_interval_start_time = getIntervalStartTime
+    get_duration = getDuration
 
 
 
 
 class Sequence(MetaInterval):
 class Sequence(MetaInterval):

+ 2 - 2
direct/src/interval/cMetaInterval.cxx

@@ -679,7 +679,7 @@ write(std::ostream &out, int indent_level) const {
   int total_digits = num_decimals + 4;
   int total_digits = num_decimals + 4;
   static const int max_digits = 32;  // totally arbitrary
   static const int max_digits = 32;  // totally arbitrary
   nassertv(total_digits <= max_digits);
   nassertv(total_digits <= max_digits);
-  char format_str[12];
+  char format_str[16];
   sprintf(format_str, "%%%d.%df", total_digits, num_decimals);
   sprintf(format_str, "%%%d.%df", total_digits, num_decimals);
 
 
   indent(out, indent_level) << get_name() << ":\n";
   indent(out, indent_level) << get_name() << ":\n";
@@ -708,7 +708,7 @@ timeline(std::ostream &out) const {
   int total_digits = num_decimals + 4;
   int total_digits = num_decimals + 4;
   static const int max_digits = 32;  // totally arbitrary
   static const int max_digits = 32;  // totally arbitrary
   nassertv(total_digits <= max_digits);
   nassertv(total_digits <= max_digits);
-  char format_str[12];
+  char format_str[16];
   sprintf(format_str, "%%%d.%df", total_digits, num_decimals);
   sprintf(format_str, "%%%d.%df", total_digits, num_decimals);
 
 
   int extra_indent_level = 0;
   int extra_indent_level = 0;

+ 20 - 12
direct/src/showbase/Transitions.py

@@ -89,7 +89,7 @@ class Transitions:
             self.fade.setBin('unsorted', 0)
             self.fade.setBin('unsorted', 0)
             self.fade.setColor(0,0,0,0)
             self.fade.setColor(0,0,0,0)
 
 
-    def getFadeInIval(self, t=0.5, finishIval=None):
+    def getFadeInIval(self, t=0.5, finishIval=None, blendType='noBlend'):
         """
         """
         Returns an interval without starting it.  This is particularly useful in
         Returns an interval without starting it.  This is particularly useful in
         cutscenes, so when the cutsceneIval is escaped out of we can finish the fade immediately
         cutscenes, so when the cutsceneIval is escaped out of we can finish the fade immediately
@@ -103,6 +103,7 @@ class Transitions:
                                   self.lerpFunc(self.fade, t,
                                   self.lerpFunc(self.fade, t,
                                                 self.alphaOff,
                                                 self.alphaOff,
                                                 # self.alphaOn,
                                                 # self.alphaOn,
+                                                blendType=blendType
                                                 ),
                                                 ),
                                   Func(self.fade.detachNode),
                                   Func(self.fade.detachNode),
                                   name = self.fadeTaskName,
                                   name = self.fadeTaskName,
@@ -111,7 +112,7 @@ class Transitions:
             transitionIval.append(finishIval)
             transitionIval.append(finishIval)
         return transitionIval
         return transitionIval
 
 
-    def getFadeOutIval(self, t=0.5, finishIval=None):
+    def getFadeOutIval(self, t=0.5, finishIval=None, blendType='noBlend'):
         """
         """
         Create a sequence that lerps the color out, then
         Create a sequence that lerps the color out, then
         parents the fade to hidden
         parents the fade to hidden
@@ -125,6 +126,7 @@ class Transitions:
                                   self.lerpFunc(self.fade, t,
                                   self.lerpFunc(self.fade, t,
                                                 self.alphaOn,
                                                 self.alphaOn,
                                                 # self.alphaOff,
                                                 # self.alphaOff,
+                                                blendType=blendType
                                                 ),
                                                 ),
                                   name = self.fadeTaskName,
                                   name = self.fadeTaskName,
                                   )
                                   )
@@ -132,7 +134,7 @@ class Transitions:
             transitionIval.append(finishIval)
             transitionIval.append(finishIval)
         return transitionIval
         return transitionIval
 
 
-    def fadeIn(self, t=0.5, finishIval=None):
+    def fadeIn(self, t=0.5, finishIval=None, blendType='noBlend'):
         """
         """
         Play a fade in transition over t seconds.
         Play a fade in transition over t seconds.
         Places a polygon on the aspect2d plane then lerps the color
         Places a polygon on the aspect2d plane then lerps the color
@@ -159,13 +161,13 @@ class Transitions:
         else:
         else:
             # Create a sequence that lerps the color out, then
             # Create a sequence that lerps the color out, then
             # parents the fade to hidden
             # parents the fade to hidden
-            self.transitionIval = self.getFadeInIval(t, finishIval)
+            self.transitionIval = self.getFadeInIval(t, finishIval, blendType)
             self.transitionIval.append(Func(self.__finishTransition))
             self.transitionIval.append(Func(self.__finishTransition))
             self.__transitionFuture = AsyncFuture()
             self.__transitionFuture = AsyncFuture()
             self.transitionIval.start()
             self.transitionIval.start()
             return self.__transitionFuture
             return self.__transitionFuture
 
 
-    def fadeOut(self, t=0.5, finishIval=None):
+    def fadeOut(self, t=0.5, finishIval=None, blendType='noBlend'):
         """
         """
         Play a fade out transition over t seconds.
         Play a fade out transition over t seconds.
         Places a polygon on the aspect2d plane then lerps the color
         Places a polygon on the aspect2d plane then lerps the color
@@ -189,7 +191,7 @@ class Transitions:
         else:
         else:
             # Create a sequence that lerps the color out, then
             # Create a sequence that lerps the color out, then
             # parents the fade to hidden
             # parents the fade to hidden
-            self.transitionIval = self.getFadeOutIval(t, finishIval)
+            self.transitionIval = self.getFadeOutIval(t, finishIval, blendType)
             self.transitionIval.append(Func(self.__finishTransition))
             self.transitionIval.append(Func(self.__finishTransition))
             self.__transitionFuture = AsyncFuture()
             self.__transitionFuture = AsyncFuture()
             self.transitionIval.start()
             self.transitionIval.start()
@@ -264,7 +266,7 @@ class Transitions:
             self.iris = loader.loadModel(self.IrisModelName)
             self.iris = loader.loadModel(self.IrisModelName)
             self.iris.setPos(0, 0, 0)
             self.iris.setPos(0, 0, 0)
 
 
-    def irisIn(self, t=0.5, finishIval=None):
+    def irisIn(self, t=0.5, finishIval=None, blendType = 'noBlend'):
         """
         """
         Play an iris in transition over t seconds.
         Play an iris in transition over t seconds.
         Places a polygon on the aspect2d plane then lerps the scale
         Places a polygon on the aspect2d plane then lerps the scale
@@ -284,7 +286,8 @@ class Transitions:
             scale = 0.18 * max(base.a2dRight, base.a2dTop)
             scale = 0.18 * max(base.a2dRight, base.a2dTop)
             self.transitionIval = Sequence(LerpScaleInterval(self.iris, t,
             self.transitionIval = Sequence(LerpScaleInterval(self.iris, t,
                                                    scale = scale,
                                                    scale = scale,
-                                                   startScale = 0.01),
+                                                   startScale = 0.01,
+                                                   blendType=blendType),
                                  Func(self.iris.detachNode),
                                  Func(self.iris.detachNode),
                                  Func(self.__finishTransition),
                                  Func(self.__finishTransition),
                                  name = self.irisTaskName,
                                  name = self.irisTaskName,
@@ -295,7 +298,7 @@ class Transitions:
             self.transitionIval.start()
             self.transitionIval.start()
             return self.__transitionFuture
             return self.__transitionFuture
 
 
-    def irisOut(self, t=0.5, finishIval=None):
+    def irisOut(self, t=0.5, finishIval=None, blendType='noBlend'):
         """
         """
         Play an iris out transition over t seconds.
         Play an iris out transition over t seconds.
         Places a polygon on the aspect2d plane then lerps the scale
         Places a polygon on the aspect2d plane then lerps the scale
@@ -318,7 +321,8 @@ class Transitions:
             scale = 0.18 * max(base.a2dRight, base.a2dTop)
             scale = 0.18 * max(base.a2dRight, base.a2dTop)
             self.transitionIval = Sequence(LerpScaleInterval(self.iris, t,
             self.transitionIval = Sequence(LerpScaleInterval(self.iris, t,
                                                    scale = 0.01,
                                                    scale = 0.01,
-                                                   startScale = scale),
+                                                   startScale = scale,
+                                                   blendType=blendType),
                                  Func(self.iris.detachNode),
                                  Func(self.iris.detachNode),
                                  # Use the fade to cover up the hole that the iris would leave
                                  # Use the fade to cover up the hole that the iris would leave
                                  Func(self.fadeOut, 0),
                                  Func(self.fadeOut, 0),
@@ -441,7 +445,7 @@ class Transitions:
             self.__letterboxFuture.setResult(None)
             self.__letterboxFuture.setResult(None)
             self.__letterboxFuture = None
             self.__letterboxFuture = None
 
 
-    def letterboxOn(self, t=0.25, finishIval=None):
+    def letterboxOn(self, t=0.25, finishIval=None, blendType='noBlend'):
         """
         """
         Move black bars in over t seconds.
         Move black bars in over t seconds.
         """
         """
@@ -461,11 +465,13 @@ class Transitions:
                                 t,
                                 t,
                                 pos = Vec3(0, 0, -1),
                                 pos = Vec3(0, 0, -1),
                                 #startPos = Vec3(0, 0, -1.2),
                                 #startPos = Vec3(0, 0, -1.2),
+                                blendType=blendType
                                 ),
                                 ),
                 LerpPosInterval(self.letterboxTop,
                 LerpPosInterval(self.letterboxTop,
                                 t,
                                 t,
                                 pos = Vec3(0, 0, 0.8),
                                 pos = Vec3(0, 0, 0.8),
                                 # startPos = Vec3(0, 0, 1),
                                 # startPos = Vec3(0, 0, 1),
+                                blendType=blendType
                                 ),
                                 ),
                 ),
                 ),
                                           Func(self.__finishLetterbox),
                                           Func(self.__finishLetterbox),
@@ -476,7 +482,7 @@ class Transitions:
             self.letterboxIval.start()
             self.letterboxIval.start()
             return self.__letterboxFuture
             return self.__letterboxFuture
 
 
-    def letterboxOff(self, t=0.25, finishIval=None):
+    def letterboxOff(self, t=0.25, finishIval=None, blendType='noBlend'):
         """
         """
         Move black bars away over t seconds.
         Move black bars away over t seconds.
         """
         """
@@ -495,11 +501,13 @@ class Transitions:
                                 t,
                                 t,
                                 pos = Vec3(0, 0, -1.2),
                                 pos = Vec3(0, 0, -1.2),
                                 # startPos = Vec3(0, 0, -1),
                                 # startPos = Vec3(0, 0, -1),
+                                blendType=blendType
                                 ),
                                 ),
                 LerpPosInterval(self.letterboxTop,
                 LerpPosInterval(self.letterboxTop,
                                 t,
                                 t,
                                 pos = Vec3(0, 0, 1),
                                 pos = Vec3(0, 0, 1),
                                 # startPos = Vec3(0, 0, 0.8),
                                 # startPos = Vec3(0, 0, 0.8),
+                                blendType=blendType
                                 ),
                                 ),
                 ),
                 ),
                                           Func(self.letterbox.stash),
                                           Func(self.letterbox.stash),

+ 2 - 2
direct/src/stdpy/threading.py

@@ -312,7 +312,7 @@ class Event:
     object. """
     object. """
 
 
     def __init__(self):
     def __init__(self):
-        self.__lock = core.Lock("Python Event")
+        self.__lock = core.Mutex("Python Event")
         self.__cvar = core.ConditionVarFull(self.__lock)
         self.__cvar = core.ConditionVarFull(self.__lock)
         self.__flag = False
         self.__flag = False
 
 
@@ -325,7 +325,7 @@ class Event:
         self.__lock.acquire()
         self.__lock.acquire()
         try:
         try:
             self.__flag = True
             self.__flag = True
-            self.__cvar.signalAll()
+            self.__cvar.notifyAll()
 
 
         finally:
         finally:
             self.__lock.release()
             self.__lock.release()

+ 2 - 1
direct/src/tkpanels/ParticlePanel.py

@@ -263,7 +263,8 @@ class ParticlePanel(AppShell):
             'Factory', 'Factory Type',
             'Factory', 'Factory Type',
             'Select type of particle factory',
             'Select type of particle factory',
             ('PointParticleFactory', 'ZSpinParticleFactory',
             ('PointParticleFactory', 'ZSpinParticleFactory',
-             'OrientedParticleFactory'),
+             #'OrientedParticleFactory'
+             ),
             self.selectFactoryType)
             self.selectFactoryType)
         factoryWidgets = (
         factoryWidgets = (
             ('Factory', 'Life Span',
             ('Factory', 'Life Span',

File diff suppressed because it is too large
+ 224 - 222
dtool/src/cppparser/cppBison.cxx.prebuilt


+ 2 - 2
dtool/src/cppparser/cppBison.h.prebuilt

@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.0.4.  */
+/* A Bison parser, made by GNU Bison 3.0.5.  */
 
 
 /* Bison interface for Yacc-like parsers in C
 /* Bison interface for Yacc-like parsers in C
 
 
-   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc.
 
 
    This program is free software: you can redistribute it and/or modify
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    it under the terms of the GNU General Public License as published by

+ 27 - 5
dtool/src/cppparser/cppBison.yxx

@@ -1185,14 +1185,27 @@ constructor_prototype:
 /* Functions with implicit return types, and constructors */
 /* Functions with implicit return types, and constructors */
         IDENTIFIER '('
         IDENTIFIER '('
 {
 {
-  push_scope($1->get_scope(current_scope, global_scope));
+  // Create a scope for this function.
+  CPPScope *scope = new CPPScope($1->get_scope(current_scope, global_scope),
+                                 $1->_names.back(), V_private);
+
+  // It still needs to be able to pick up any template arguments, if this is
+  // a definition for a method template.  Add a fake "using" declaration to
+  // accomplish this.
+  scope->_using.insert(current_scope);
+
+  push_scope(scope);
 }
 }
         function_parameter_list ')' function_post
         function_parameter_list ')' function_post
 {
 {
+  CPPScope *scope = $1->get_scope(current_scope, global_scope);
   CPPType *type;
   CPPType *type;
-  if ($1->get_simple_name() == current_scope->get_simple_name() ||
-      $1->get_simple_name() == string("~") + current_scope->get_simple_name()) {
-    // This is a constructor, and has no return.
+  std::string simple_name = $1->get_simple_name();
+  if (!simple_name.empty() && simple_name[0] == '~') {
+    // A destructor has no return type.
+    type = new CPPSimpleType(CPPSimpleType::T_void);
+  } else if (scope != nullptr && simple_name == scope->get_simple_name()) {
+    // Neither does a constructor.
     type = new CPPSimpleType(CPPSimpleType::T_void);
     type = new CPPSimpleType(CPPSimpleType::T_void);
   } else {
   } else {
     // This isn't a constructor, so it has an implicit return type of
     // This isn't a constructor, so it has an implicit return type of
@@ -1209,7 +1222,16 @@ constructor_prototype:
 }
 }
         | TYPENAME_IDENTIFIER '('
         | TYPENAME_IDENTIFIER '('
 {
 {
-  push_scope($1->get_scope(current_scope, global_scope));
+  // Create a scope for this function.
+  CPPScope *scope = new CPPScope($1->get_scope(current_scope, global_scope),
+                                 $1->_names.back(), V_private);
+
+  // It still needs to be able to pick up any template arguments, if this is
+  // a definition for a method template.  Add a fake "using" declaration to
+  // accomplish this.
+  scope->_using.insert(current_scope);
+
+  push_scope(scope);
 }
 }
         function_parameter_list ')' function_post
         function_parameter_list ')' function_post
 {
 {

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

@@ -97,10 +97,12 @@ typedef std::ios::seekdir ios_seekdir;
 // in some important missing functions.
 // in some important missing functions.
 #if defined(__GLIBCXX__) && __GLIBCXX__ <= 20070719
 #if defined(__GLIBCXX__) && __GLIBCXX__ <= 20070719
 #include <tr1/tuple>
 #include <tr1/tuple>
+#include <tr1/cmath>
 
 
 namespace std {
 namespace std {
   using std::tr1::tuple;
   using std::tr1::tuple;
   using std::tr1::tie;
   using std::tr1::tie;
+  using std::tr1::copysign;
 
 
   typedef decltype(nullptr) nullptr_t;
   typedef decltype(nullptr) nullptr_t;
 
 
@@ -111,6 +113,8 @@ namespace std {
   template<class T> typename remove_reference<T>::type &&move(T &&t) {
   template<class T> typename remove_reference<T>::type &&move(T &&t) {
     return static_cast<typename remove_reference<T>::type&&>(t);
     return static_cast<typename remove_reference<T>::type&&>(t);
   }
   }
+
+  template<class T> struct owner_less;
 };
 };
 #endif
 #endif
 
 

+ 7 - 0
dtool/src/parser-inc/time.h

@@ -1 +1,8 @@
+#pragma once
+
 #include <stdtypedefs.h>
 #include <stdtypedefs.h>
+
+struct timespec {
+  time_t tv_sec;
+  long tv_nsec;
+};

+ 1 - 1
dtool/src/parser-inc/ws2tcpip.h

@@ -1 +1 @@
-typedef DWORD socklen_t;
+typedef int socklen_t;

+ 18 - 19
dtool/src/pystub/pystub.cxx

@@ -36,7 +36,6 @@ extern "C" {
   EXPCL_PYSTUB int PyDict_SetItem(...);
   EXPCL_PYSTUB int PyDict_SetItem(...);
   EXPCL_PYSTUB int PyDict_SetItemString(...);
   EXPCL_PYSTUB int PyDict_SetItemString(...);
   EXPCL_PYSTUB int PyDict_Size(...);
   EXPCL_PYSTUB int PyDict_Size(...);
-  EXPCL_PYSTUB int PyDict_Type(...);
   EXPCL_PYSTUB int PyErr_Clear(...);
   EXPCL_PYSTUB int PyErr_Clear(...);
   EXPCL_PYSTUB int PyErr_ExceptionMatches(...);
   EXPCL_PYSTUB int PyErr_ExceptionMatches(...);
   EXPCL_PYSTUB int PyErr_Fetch(...);
   EXPCL_PYSTUB int PyErr_Fetch(...);
@@ -54,9 +53,7 @@ extern "C" {
   EXPCL_PYSTUB int PyEval_SaveThread(...);
   EXPCL_PYSTUB int PyEval_SaveThread(...);
   EXPCL_PYSTUB int PyFloat_AsDouble(...);
   EXPCL_PYSTUB int PyFloat_AsDouble(...);
   EXPCL_PYSTUB int PyFloat_FromDouble(...);
   EXPCL_PYSTUB int PyFloat_FromDouble(...);
-  EXPCL_PYSTUB int PyFloat_Type(...);
   EXPCL_PYSTUB int PyGen_Check(...);
   EXPCL_PYSTUB int PyGen_Check(...);
-  EXPCL_PYSTUB int PyGen_Type(...);
   EXPCL_PYSTUB int PyGILState_Ensure(...);
   EXPCL_PYSTUB int PyGILState_Ensure(...);
   EXPCL_PYSTUB int PyGILState_Release(...);
   EXPCL_PYSTUB int PyGILState_Release(...);
   EXPCL_PYSTUB int PyImport_GetModuleDict(...);
   EXPCL_PYSTUB int PyImport_GetModuleDict(...);
@@ -65,14 +62,12 @@ extern "C" {
   EXPCL_PYSTUB int PyInt_AsSsize_t(...);
   EXPCL_PYSTUB int PyInt_AsSsize_t(...);
   EXPCL_PYSTUB int PyInt_FromLong(...);
   EXPCL_PYSTUB int PyInt_FromLong(...);
   EXPCL_PYSTUB int PyInt_FromSize_t(...);
   EXPCL_PYSTUB int PyInt_FromSize_t(...);
-  EXPCL_PYSTUB int PyInt_Type(...);
   EXPCL_PYSTUB int PyIter_Next(...);
   EXPCL_PYSTUB int PyIter_Next(...);
   EXPCL_PYSTUB int PyList_Append(...);
   EXPCL_PYSTUB int PyList_Append(...);
   EXPCL_PYSTUB int PyList_AsTuple(...);
   EXPCL_PYSTUB int PyList_AsTuple(...);
   EXPCL_PYSTUB int PyList_GetItem(...);
   EXPCL_PYSTUB int PyList_GetItem(...);
   EXPCL_PYSTUB int PyList_New(...);
   EXPCL_PYSTUB int PyList_New(...);
   EXPCL_PYSTUB int PyList_SetItem(...);
   EXPCL_PYSTUB int PyList_SetItem(...);
-  EXPCL_PYSTUB int PyList_Type(...);
   EXPCL_PYSTUB int PyLong_AsLong(...);
   EXPCL_PYSTUB int PyLong_AsLong(...);
   EXPCL_PYSTUB int PyLong_AsLongLong(...);
   EXPCL_PYSTUB int PyLong_AsLongLong(...);
   EXPCL_PYSTUB int PyLong_AsSsize_t(...);
   EXPCL_PYSTUB int PyLong_AsSsize_t(...);
@@ -83,7 +78,6 @@ extern "C" {
   EXPCL_PYSTUB int PyLong_FromSize_t(...);
   EXPCL_PYSTUB int PyLong_FromSize_t(...);
   EXPCL_PYSTUB int PyLong_FromUnsignedLong(...);
   EXPCL_PYSTUB int PyLong_FromUnsignedLong(...);
   EXPCL_PYSTUB int PyLong_FromUnsignedLongLong(...);
   EXPCL_PYSTUB int PyLong_FromUnsignedLongLong(...);
-  EXPCL_PYSTUB int PyLong_Type(...);
   EXPCL_PYSTUB int PyMapping_GetItemString(...);
   EXPCL_PYSTUB int PyMapping_GetItemString(...);
   EXPCL_PYSTUB int PyMem_Free(...);
   EXPCL_PYSTUB int PyMem_Free(...);
   EXPCL_PYSTUB int PyMemoryView_FromObject(...);
   EXPCL_PYSTUB int PyMemoryView_FromObject(...);
@@ -124,7 +118,6 @@ extern "C" {
   EXPCL_PYSTUB int PyObject_SetAttr(...);
   EXPCL_PYSTUB int PyObject_SetAttr(...);
   EXPCL_PYSTUB int PyObject_SetAttrString(...);
   EXPCL_PYSTUB int PyObject_SetAttrString(...);
   EXPCL_PYSTUB int PyObject_Str(...);
   EXPCL_PYSTUB int PyObject_Str(...);
-  EXPCL_PYSTUB int PyObject_Type(...);
   EXPCL_PYSTUB int PySeqIter_New(...);
   EXPCL_PYSTUB int PySeqIter_New(...);
   EXPCL_PYSTUB int PySequence_Check(...);
   EXPCL_PYSTUB int PySequence_Check(...);
   EXPCL_PYSTUB int PySequence_Fast(...);
   EXPCL_PYSTUB int PySequence_Fast(...);
@@ -139,7 +132,6 @@ extern "C" {
   EXPCL_PYSTUB int PyString_InternFromString(...);
   EXPCL_PYSTUB int PyString_InternFromString(...);
   EXPCL_PYSTUB int PyString_InternInPlace(...);
   EXPCL_PYSTUB int PyString_InternInPlace(...);
   EXPCL_PYSTUB int PyString_Size(...);
   EXPCL_PYSTUB int PyString_Size(...);
-  EXPCL_PYSTUB int PyString_Type(...);
   EXPCL_PYSTUB int PySys_GetObject(...);
   EXPCL_PYSTUB int PySys_GetObject(...);
   EXPCL_PYSTUB int PyThreadState_Clear(...);
   EXPCL_PYSTUB int PyThreadState_Clear(...);
   EXPCL_PYSTUB int PyThreadState_Delete(...);
   EXPCL_PYSTUB int PyThreadState_Delete(...);
@@ -181,7 +173,6 @@ extern "C" {
   EXPCL_PYSTUB int PyUnicode_GetSize(...);
   EXPCL_PYSTUB int PyUnicode_GetSize(...);
   EXPCL_PYSTUB int PyUnicode_InternFromString(...);
   EXPCL_PYSTUB int PyUnicode_InternFromString(...);
   EXPCL_PYSTUB int PyUnicode_InternInPlace(...);
   EXPCL_PYSTUB int PyUnicode_InternInPlace(...);
-  EXPCL_PYSTUB int PyUnicode_Type(...);
   EXPCL_PYSTUB int Py_BuildValue(...);
   EXPCL_PYSTUB int Py_BuildValue(...);
   EXPCL_PYSTUB int Py_GetVersion(...);
   EXPCL_PYSTUB int Py_GetVersion(...);
   EXPCL_PYSTUB int Py_InitModule4(...);
   EXPCL_PYSTUB int Py_InitModule4(...);
@@ -233,8 +224,17 @@ extern "C" {
   EXPCL_PYSTUB extern void *PyExc_SystemExit;
   EXPCL_PYSTUB extern void *PyExc_SystemExit;
   EXPCL_PYSTUB extern void *PyExc_TypeError;
   EXPCL_PYSTUB extern void *PyExc_TypeError;
   EXPCL_PYSTUB extern void *PyExc_ValueError;
   EXPCL_PYSTUB extern void *PyExc_ValueError;
+  EXPCL_PYSTUB extern void *PyDict_Type;
+  EXPCL_PYSTUB extern void *PyFloat_Type;
+  EXPCL_PYSTUB extern void *PyGen_Type;
+  EXPCL_PYSTUB extern void *PyInt_Type;
+  EXPCL_PYSTUB extern void *PyList_Type;
+  EXPCL_PYSTUB extern void *PyLong_Type;
+  EXPCL_PYSTUB extern void *PyObject_Type;
+  EXPCL_PYSTUB extern void *PyString_Type;
   EXPCL_PYSTUB extern void *PyTuple_Type;
   EXPCL_PYSTUB extern void *PyTuple_Type;
   EXPCL_PYSTUB extern void *PyType_Type;
   EXPCL_PYSTUB extern void *PyType_Type;
+  EXPCL_PYSTUB extern void *PyUnicode_Type;
   EXPCL_PYSTUB extern void *_PyThreadState_Current;
   EXPCL_PYSTUB extern void *_PyThreadState_Current;
   EXPCL_PYSTUB extern void *_Py_FalseStruct;
   EXPCL_PYSTUB extern void *_Py_FalseStruct;
   EXPCL_PYSTUB extern void *_Py_NoneStruct;
   EXPCL_PYSTUB extern void *_Py_NoneStruct;
@@ -266,7 +266,6 @@ int PyDict_Next(...) { return 0; };
 int PyDict_SetItem(...) { return 0; };
 int PyDict_SetItem(...) { return 0; };
 int PyDict_SetItemString(...) { return 0; };
 int PyDict_SetItemString(...) { return 0; };
 int PyDict_Size(...){ return 0; }
 int PyDict_Size(...){ return 0; }
-int PyDict_Type(...) { return 0; };
 int PyErr_Clear(...) { return 0; };
 int PyErr_Clear(...) { return 0; };
 int PyErr_ExceptionMatches(...) { return 0; };
 int PyErr_ExceptionMatches(...) { return 0; };
 int PyErr_Fetch(...) { return 0; }
 int PyErr_Fetch(...) { return 0; }
@@ -285,9 +284,7 @@ int PyEval_RestoreThread(...) { return 0; }
 int PyEval_SaveThread(...) { return 0; }
 int PyEval_SaveThread(...) { return 0; }
 int PyFloat_AsDouble(...) { return 0; }
 int PyFloat_AsDouble(...) { return 0; }
 int PyFloat_FromDouble(...) { return 0; }
 int PyFloat_FromDouble(...) { return 0; }
-int PyFloat_Type(...) { return 0; }
 int PyGen_Check(...) { return 0; }
 int PyGen_Check(...) { return 0; }
-int PyGen_Type(...) { return 0; }
 int PyGILState_Ensure(...) { return 0; }
 int PyGILState_Ensure(...) { return 0; }
 int PyGILState_Release(...) { return 0; }
 int PyGILState_Release(...) { return 0; }
 int PyImport_GetModuleDict(...) { return 0; }
 int PyImport_GetModuleDict(...) { return 0; }
@@ -296,14 +293,12 @@ int PyInt_AsLong(...) { return 0; }
 int PyInt_AsSsize_t(...) { return 0; }
 int PyInt_AsSsize_t(...) { return 0; }
 int PyInt_FromLong(...) { return 0; }
 int PyInt_FromLong(...) { return 0; }
 int PyInt_FromSize_t(...) { return 0; }
 int PyInt_FromSize_t(...) { return 0; }
-int PyInt_Type(...) { return 0; }
 int PyIter_Next(...) { return 0; }
 int PyIter_Next(...) { return 0; }
 int PyList_Append(...) { return 0; }
 int PyList_Append(...) { return 0; }
 int PyList_AsTuple(...) { return 0; }
 int PyList_AsTuple(...) { return 0; }
 int PyList_GetItem(...) { return 0; }
 int PyList_GetItem(...) { return 0; }
 int PyList_New(...) { return 0; }
 int PyList_New(...) { return 0; }
 int PyList_SetItem(...) { return 0; }
 int PyList_SetItem(...) { return 0; }
-int PyList_Type(...) { return 0; }
 int PyLong_AsLong(...) { return 0; }
 int PyLong_AsLong(...) { return 0; }
 int PyLong_AsLongLong(...) { return 0; }
 int PyLong_AsLongLong(...) { return 0; }
 int PyLong_AsSsize_t(...) { return 0; }
 int PyLong_AsSsize_t(...) { return 0; }
@@ -314,7 +309,6 @@ int PyLong_FromLongLong(...) { return 0; }
 int PyLong_FromSize_t(...) { return 0; }
 int PyLong_FromSize_t(...) { return 0; }
 int PyLong_FromUnsignedLong(...) { return 0; }
 int PyLong_FromUnsignedLong(...) { return 0; }
 int PyLong_FromUnsignedLongLong(...) { return 0; }
 int PyLong_FromUnsignedLongLong(...) { return 0; }
-int PyLong_Type(...) { return 0; }
 int PyMapping_GetItemString(...) { return 0; }
 int PyMapping_GetItemString(...) { return 0; }
 int PyMem_Free(...) { return 0; }
 int PyMem_Free(...) { return 0; }
 int PyMemoryView_FromObject(...) { return 0; }
 int PyMemoryView_FromObject(...) { return 0; }
@@ -355,7 +349,6 @@ int PyObject_SelfIter(...) { return 0; }
 int PyObject_SetAttr(...) { return 0; }
 int PyObject_SetAttr(...) { return 0; }
 int PyObject_SetAttrString(...) { return 0; }
 int PyObject_SetAttrString(...) { return 0; }
 int PyObject_Str(...) { return 0; }
 int PyObject_Str(...) { return 0; }
-int PyObject_Type(...) { return 0; }
 int PySeqIter_New(...) { return 0; }
 int PySeqIter_New(...) { return 0; }
 int PySequence_Check(...) { return 0; }
 int PySequence_Check(...) { return 0; }
 int PySequence_Fast(...) { return 0; }
 int PySequence_Fast(...) { return 0; }
@@ -369,8 +362,6 @@ int PyString_FromString(...) { return 0; }
 int PyString_FromStringAndSize(...) { return 0; }
 int PyString_FromStringAndSize(...) { return 0; }
 int PyString_InternFromString(...) { return 0; }
 int PyString_InternFromString(...) { return 0; }
 int PyString_InternInPlace(...) { return 0; }
 int PyString_InternInPlace(...) { return 0; }
-int PyString_Size(...) { return 0; }
-int PyString_Type(...) { return 0; }
 int PySys_GetObject(...) { return 0; }
 int PySys_GetObject(...) { return 0; }
 int PyThreadState_Clear(...) { return 0; }
 int PyThreadState_Clear(...) { return 0; }
 int PyThreadState_Delete(...) { return 0; }
 int PyThreadState_Delete(...) { return 0; }
@@ -412,7 +403,6 @@ int PyUnicode_FromWideChar(...) { return 0; }
 int PyUnicode_GetSize(...) { return 0; }
 int PyUnicode_GetSize(...) { return 0; }
 int PyUnicode_InternFromString(...) { return 0; }
 int PyUnicode_InternFromString(...) { return 0; }
 int PyUnicode_InternInPlace(...) { return 0; }
 int PyUnicode_InternInPlace(...) { return 0; }
-int PyUnicode_Type(...) { return 0; }
 int Py_GetVersion(...) { return 0; }
 int Py_GetVersion(...) { return 0; }
 int Py_BuildValue(...) { return 0; }
 int Py_BuildValue(...) { return 0; }
 int Py_InitModule4(...) { return 0; }
 int Py_InitModule4(...) { return 0; }
@@ -470,8 +460,17 @@ void *PyExc_StopIteration = nullptr;
 void *PyExc_SystemExit = nullptr;
 void *PyExc_SystemExit = nullptr;
 void *PyExc_TypeError = nullptr;
 void *PyExc_TypeError = nullptr;
 void *PyExc_ValueError = nullptr;
 void *PyExc_ValueError = nullptr;
+void *PyDict_Type = nullptr;
+void *PyFloat_Type = nullptr;
+void *PyGen_Type = nullptr;
+void *PyInt_Type = nullptr;
+void *PyList_Type = nullptr;
+void *PyLong_Type = nullptr;
+void *PyObject_Type = nullptr;
+void *PyString_Type = nullptr;
 void *PyTuple_Type = nullptr;
 void *PyTuple_Type = nullptr;
 void *PyType_Type = nullptr;
 void *PyType_Type = nullptr;
+void *PyUnicode_Type = nullptr;
 void *_PyThreadState_Current = nullptr;
 void *_PyThreadState_Current = nullptr;
 void *_Py_FalseStruct = nullptr;
 void *_Py_FalseStruct = nullptr;
 void *_Py_NoneStruct = nullptr;
 void *_Py_NoneStruct = nullptr;

+ 3 - 0
makepanda/makepanda.py

@@ -1415,6 +1415,9 @@ def CompileCxx(obj,src,opts):
             # Fast math is nice, but we'd like to see NaN in dev builds.
             # Fast math is nice, but we'd like to see NaN in dev builds.
             cmd += " -fno-finite-math-only"
             cmd += " -fno-finite-math-only"
 
 
+        # Make sure this is off to avoid GCC/Eigen bug (see GitHub #228)
+        cmd += " -fno-unsafe-math-optimizations"
+
         if (optlevel==1): cmd += " -ggdb -D_DEBUG"
         if (optlevel==1): cmd += " -ggdb -D_DEBUG"
         if (optlevel==2): cmd += " -O1 -D_DEBUG"
         if (optlevel==2): cmd += " -O1 -D_DEBUG"
         if (optlevel==3): cmd += " -O2"
         if (optlevel==3): cmd += " -O2"

+ 0 - 4
makepanda/makepanda.vcproj

@@ -760,7 +760,6 @@
 				<File RelativePath="..\panda\src\gobj\bufferContext.cxx"></File>
 				<File RelativePath="..\panda\src\gobj\bufferContext.cxx"></File>
 				<File RelativePath="..\panda\src\gobj\textureContext.I"></File>
 				<File RelativePath="..\panda\src\gobj\textureContext.I"></File>
 				<File RelativePath="..\panda\src\gobj\internalName.h"></File>
 				<File RelativePath="..\panda\src\gobj\internalName.h"></File>
-				<File RelativePath="..\panda\src\gobj\test_gobj.cxx"></File>
 				<File RelativePath="..\panda\src\gobj\geomTristrips.h"></File>
 				<File RelativePath="..\panda\src\gobj\geomTristrips.h"></File>
 				<File RelativePath="..\panda\src\gobj\textureContext.h"></File>
 				<File RelativePath="..\panda\src\gobj\textureContext.h"></File>
 				<File RelativePath="..\panda\src\gobj\config_gobj.cxx"></File>
 				<File RelativePath="..\panda\src\gobj\config_gobj.cxx"></File>
@@ -1114,7 +1113,6 @@
 				<File RelativePath="..\panda\src\collide\collisionHandlerGravity.I"></File>
 				<File RelativePath="..\panda\src\collide\collisionHandlerGravity.I"></File>
 				<File RelativePath="..\panda\src\collide\collisionLine.h"></File>
 				<File RelativePath="..\panda\src\collide\collisionLine.h"></File>
 				<File RelativePath="..\panda\src\collide\collisionHandlerPhysical.I"></File>
 				<File RelativePath="..\panda\src\collide\collisionHandlerPhysical.I"></File>
-				<File RelativePath="..\panda\src\collide\test_collide.cxx"></File>
 				<File RelativePath="..\panda\src\collide\collisionFloorMesh.cxx"></File>
 				<File RelativePath="..\panda\src\collide\collisionFloorMesh.cxx"></File>
 				<File RelativePath="..\panda\src\collide\collisionPolygon.h"></File>
 				<File RelativePath="..\panda\src\collide\collisionPolygon.h"></File>
 				<File RelativePath="..\panda\src\collide\collisionGeom.cxx"></File>
 				<File RelativePath="..\panda\src\collide\collisionGeom.cxx"></File>
@@ -1379,7 +1377,6 @@
 				<File RelativePath="..\panda\src\display\windowHandle.h"></File>
 				<File RelativePath="..\panda\src\display\windowHandle.h"></File>
 				<File RelativePath="..\panda\src\display\displayRegionCullCallbackData.cxx"></File>
 				<File RelativePath="..\panda\src\display\displayRegionCullCallbackData.cxx"></File>
 				<File RelativePath="..\panda\src\display\graphicsOutput.cxx"></File>
 				<File RelativePath="..\panda\src\display\graphicsOutput.cxx"></File>
-				<File RelativePath="..\panda\src\display\test_display.cxx"></File>
 				<File RelativePath="..\panda\src\display\graphicsBuffer.I"></File>
 				<File RelativePath="..\panda\src\display\graphicsBuffer.I"></File>
 				<File RelativePath="..\panda\src\display\stencilRenderStates.cxx"></File>
 				<File RelativePath="..\panda\src\display\stencilRenderStates.cxx"></File>
 				<File RelativePath="..\panda\src\display\stereoDisplayRegion.I"></File>
 				<File RelativePath="..\panda\src\display\stereoDisplayRegion.I"></File>
@@ -3706,7 +3703,6 @@
 				<File RelativePath="..\panda\src\testbed\test_map.cxx"></File>
 				<File RelativePath="..\panda\src\testbed\test_map.cxx"></File>
 				<File RelativePath="..\panda\src\testbed\pgrid.cxx"></File>
 				<File RelativePath="..\panda\src\testbed\pgrid.cxx"></File>
 				<File RelativePath="..\panda\src\testbed\pview.cxx"></File>
 				<File RelativePath="..\panda\src\testbed\pview.cxx"></File>
-				<File RelativePath="..\panda\src\testbed\text_test.cxx"></File>
 			</Filter>
 			</Filter>
 			<Filter Name="cull">
 			<Filter Name="cull">
 				<File RelativePath="..\panda\src\cull\config_cull.cxx"></File>
 				<File RelativePath="..\panda\src\cull\config_cull.cxx"></File>

+ 2 - 1
makepanda/makepandacore.py

@@ -102,7 +102,8 @@ MAYAVERSIONINFO = [("MAYA6",   "6.0"),
                    ("MAYA2015","2015"),
                    ("MAYA2015","2015"),
                    ("MAYA2016","2016"),
                    ("MAYA2016","2016"),
                    ("MAYA20165","2016.5"),
                    ("MAYA20165","2016.5"),
-                   ("MAYA2017","2017")
+                   ("MAYA2017","2017"),
+                   ("MAYA2018","2018"),
 ]
 ]
 
 
 MAXVERSIONINFO = [("MAX6", "SOFTWARE\\Autodesk\\3DSMAX\\6.0", "installdir", "maxsdk\\cssdk\\include"),
 MAXVERSIONINFO = [("MAX6", "SOFTWARE\\Autodesk\\3DSMAX\\6.0", "installdir", "maxsdk\\cssdk\\include"),

+ 4 - 1
makepanda/makewheel.py

@@ -514,7 +514,10 @@ def makewheel(version, output_dir, platform=None):
 
 
     # Write the panda3d tree.  We use a custom empty __init__ since the
     # Write the panda3d tree.  We use a custom empty __init__ since the
     # default one adds the bin directory to the PATH, which we don't have.
     # default one adds the bin directory to the PATH, which we don't have.
-    whl.write_file_data('panda3d/__init__.py', '')
+    whl.write_file_data('panda3d/__init__.py', """"Python bindings for the Panda3D libraries"
+
+__version__ = '{0}'
+""".format(version))
 
 
     ext_suffix = '.pyd' if sys.platform in ('win32', 'cygwin') else '.so'
     ext_suffix = '.pyd' if sys.platform in ('win32', 'cygwin') else '.so'
 
 

+ 1 - 1
panda/src/chan/partBundle.h

@@ -172,7 +172,7 @@ private:
   typedef pvector<PartBundleNode *> Nodes;
   typedef pvector<PartBundleNode *> Nodes;
   Nodes _nodes;
   Nodes _nodes;
 
 
-  typedef pmap<WCPT(TransformState), WPT(PartBundle) > AppliedTransforms;
+  typedef pmap<WCPT(TransformState), WPT(PartBundle), std::owner_less<WCPT(TransformState)> > AppliedTransforms;
   AppliedTransforms _applied_transforms;
   AppliedTransforms _applied_transforms;
 
 
   double _update_delay;
   double _update_delay;

+ 5 - 1
panda/src/char/characterJointEffect.I

@@ -35,5 +35,9 @@ get_character() const {
  */
  */
 INLINE bool CharacterJointEffect::
 INLINE bool CharacterJointEffect::
 matches_character(Character *character) const {
 matches_character(Character *character) const {
-  return _character == character;
+  // This works because while the Character is destructing, the ref count will
+  // be 0 but was_deleted() will still return false.  We cannot construct a
+  // PointerTo to the character (via lock() or otherwise) when the reference
+  // count is 0 since that will cause double deletion.
+  return _character.get_orig() == character && !_character.was_deleted();
 }
 }

+ 274 - 100
panda/src/collide/collisionBox.cxx

@@ -398,6 +398,49 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   return new_entry;
   return new_entry;
 }
 }
 
 
+/**
+ *
+ */
+PT(CollisionEntry) CollisionBox::
+test_intersection_from_line(const CollisionEntry &entry) const {
+  const CollisionLine *line;
+  DCAST_INTO_R(line, entry.get_from(), nullptr);
+
+  const LMatrix4 &wrt_mat = entry.get_wrt_mat();
+
+  LPoint3 from_origin = line->get_origin() * wrt_mat;
+  LVector3 from_direction = line->get_direction() * wrt_mat;
+
+  double t1, t2;
+  if (!intersects_line(t1, t2, from_origin, from_direction)) {
+    // No intersection.
+    return nullptr;
+  }
+
+  if (collide_cat.is_debug()) {
+    collide_cat.debug()
+      << "intersection detected from " << entry.get_from_node_path()
+      << " into " << entry.get_into_node_path() << "\n";
+  }
+  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
+
+  LPoint3 point = from_origin + t1 * from_direction;
+  new_entry->set_surface_point(point);
+
+  if (has_effective_normal() && line->get_respect_effective_normal()) {
+    new_entry->set_surface_normal(get_effective_normal());
+  } else {
+    LVector3 normal(
+      IS_NEARLY_EQUAL(point[0], _max[0]) - IS_NEARLY_EQUAL(point[0], _min[0]),
+      IS_NEARLY_EQUAL(point[1], _max[1]) - IS_NEARLY_EQUAL(point[1], _min[1]),
+      IS_NEARLY_EQUAL(point[2], _max[2]) - IS_NEARLY_EQUAL(point[2], _min[2])
+    );
+    normal.normalize();
+    new_entry->set_surface_normal(normal);
+  }
+
+  return new_entry;
+}
 
 
 /**
 /**
  * Double dispatch point for ray as a FROM object
  * Double dispatch point for ray as a FROM object
@@ -411,51 +454,9 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
   LPoint3 from_origin = ray->get_origin() * wrt_mat;
   LPoint3 from_origin = ray->get_origin() * wrt_mat;
   LVector3 from_direction = ray->get_direction() * wrt_mat;
   LVector3 from_direction = ray->get_direction() * wrt_mat;
 
 
-  int i, j;
-  PN_stdfloat t;
-  PN_stdfloat near_t = 0.0;
-  bool intersect;
-  LPlane plane;
-  LPlane near_plane;
-
-  // Returns the details about the first plane of the box that the ray
-  // intersects.
-  for (i = 0, intersect = false, t = 0, j = 0; i < 6 && j < 2; i++) {
-    plane = get_plane(i);
-
-    if (!plane.intersects_line(t, from_origin, from_direction)) {
-      // No intersection.  The ray is parallel to the plane.
-      continue;
-    }
-
-    if (t < 0.0f) {
-      // The intersection point is before the start of the ray, and so the ray
-      // is entirely in front of the plane.
-      continue;
-    }
-    LPoint3 plane_point = from_origin + t * from_direction;
-    LPoint2 p = to_2d(plane_point, i);
-
-    if (!point_is_inside(p, _points[i])){
-      continue;
-    }
-    intersect = true;
-    if (j) {
-      if(t < near_t) {
-        near_plane = plane;
-        near_t = t;
-      }
-    }
-    else {
-      near_plane = plane;
-      near_t = t;
-    }
-    ++j;
-  }
-
-
-  if(!intersect) {
-    // No intersection with ANY of the box's planes has been detected
+  double t1, t2;
+  if (!intersects_line(t1, t2, from_origin, from_direction) || (t1 < 0.0 && t2 < 0.0)) {
+    // No intersection.
     return nullptr;
     return nullptr;
   }
   }
 
 
@@ -464,22 +465,32 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
       << "intersection detected from " << entry.get_from_node_path()
       << "intersection detected from " << entry.get_from_node_path()
       << " into " << entry.get_into_node_path() << "\n";
       << " into " << entry.get_into_node_path() << "\n";
   }
   }
-
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
 
-  LPoint3 into_intersection_point = from_origin + near_t * from_direction;
+  if (t1 < 0.0) {
+    // The origin is inside the box, so we take the exit as our surface point.
+    new_entry->set_interior_point(from_origin);
+    t1 = t2;
+  }
 
 
-  LVector3 normal =
-    (has_effective_normal() && ray->get_respect_effective_normal())
-    ? get_effective_normal() : near_plane.get_normal();
+  LPoint3 point = from_origin + t1 * from_direction;
+  new_entry->set_surface_point(point);
 
 
-  new_entry->set_surface_normal(normal);
-  new_entry->set_surface_point(into_intersection_point);
+  if (has_effective_normal() && ray->get_respect_effective_normal()) {
+    new_entry->set_surface_normal(get_effective_normal());
+  } else {
+    LVector3 normal(
+      IS_NEARLY_EQUAL(point[0], _max[0]) - IS_NEARLY_EQUAL(point[0], _min[0]),
+      IS_NEARLY_EQUAL(point[1], _max[1]) - IS_NEARLY_EQUAL(point[1], _min[1]),
+      IS_NEARLY_EQUAL(point[2], _max[2]) - IS_NEARLY_EQUAL(point[2], _min[2])
+    );
+    normal.normalize();
+    new_entry->set_surface_normal(normal);
+  }
 
 
   return new_entry;
   return new_entry;
 }
 }
 
 
-
 /**
 /**
  * Double dispatch point for segment as a FROM object
  * Double dispatch point for segment as a FROM object
  */
  */
@@ -493,70 +504,188 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
   LPoint3 from_extent = seg->get_point_b() * wrt_mat;
   LPoint3 from_extent = seg->get_point_b() * wrt_mat;
   LVector3 from_direction = from_extent - from_origin;
   LVector3 from_direction = from_extent - from_origin;
 
 
-  int i, j;
-  PN_stdfloat t;
-  PN_stdfloat near_t = 0.0;
-  bool intersect;
-  LPlane plane;
-  LPlane near_plane;
+  double t1, t2;
+  if (!intersects_line(t1, t2, from_origin, from_direction) ||
+      (t1 < 0.0 && t2 < 0.0) || (t1 > 1.0 && t2 > 1.0)) {
+    // No intersection.
+    return nullptr;
+  }
 
 
-  // Returns the details about the first plane of the box that the segment
-  // intersects.
-  for(i = 0, intersect = false, t = 0, j = 0; i < 6 && j < 2; i++) {
-    plane = get_plane(i);
+  if (collide_cat.is_debug()) {
+    collide_cat.debug()
+      << "intersection detected from " << entry.get_from_node_path()
+      << " into " << entry.get_into_node_path() << "\n";
+  }
+  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
 
-    if (!plane.intersects_line(t, from_origin, from_direction)) {
-      // No intersection.  The segment is parallel to the plane.
-      continue;
-    }
+  // In case the segment is entirely inside the cube, we consider the point
+  // closest to the surface as our entry point.
+  if (t1 < (1.0 - t2)) {
+    std::swap(t1, t2);
+  }
 
 
-    if (t < 0.0f || t > 1.0f) {
-      // The intersection point is before the start of the segment, or after
-      // the end of the segment, so the segment is either entirely in front of
-      // or behind the plane.
-      continue;
-    }
-    LPoint3 plane_point = from_origin + t * from_direction;
-    LPoint2 p = to_2d(plane_point, i);
+  // Our interior point is the closest point to t2 that is inside the segment.
+  new_entry->set_interior_point(from_origin + std::min(std::max(t2, 0.0), 1.0) * from_direction);
 
 
-    if (!point_is_inside(p, _points[i])){
-      continue;
-    }
-    intersect = true;
-    if(j) {
-      if(t < near_t) {
-        near_plane = plane;
-        near_t = t;
-      }
-    }
-    else {
-      near_plane = plane;
-      near_t = t;
-    }
-    ++j;
+  LPoint3 point = from_origin + t1 * from_direction;
+  new_entry->set_surface_point(point);
+
+  if (has_effective_normal() && seg->get_respect_effective_normal()) {
+    new_entry->set_surface_normal(get_effective_normal());
+  } else {
+    LVector3 normal(
+      IS_NEARLY_EQUAL(point[0], _max[0]) - IS_NEARLY_EQUAL(point[0], _min[0]),
+      IS_NEARLY_EQUAL(point[1], _max[1]) - IS_NEARLY_EQUAL(point[1], _min[1]),
+      IS_NEARLY_EQUAL(point[2], _max[2]) - IS_NEARLY_EQUAL(point[2], _min[2])
+    );
+    normal.normalize();
+    new_entry->set_surface_normal(normal);
   }
   }
 
 
-  if(!intersect) {
-    // No intersection with ANY of the box's planes has been detected
+  return new_entry;
+}
+
+/**
+ * Double dispatch point for tube as a FROM object
+ */
+PT(CollisionEntry) CollisionBox::
+test_intersection_from_tube(const CollisionEntry &entry) const {
+  const CollisionTube *tube;
+  DCAST_INTO_R(tube, entry.get_from(), nullptr);
+
+  const LMatrix4 &wrt_mat = entry.get_wrt_mat();
+
+  LPoint3 from_a = tube->get_point_a() * wrt_mat;
+  LPoint3 from_b = tube->get_point_b() * wrt_mat;
+  LVector3 from_direction = from_b - from_a;
+  PN_stdfloat radius_sq = wrt_mat.xform_vec(LVector3(0, 0, tube->get_radius())).length_squared();
+  PN_stdfloat radius = csqrt(radius_sq);
+
+  LPoint3 box_min = get_min();
+  LPoint3 box_max = get_max();
+  LVector3 dimensions = box_max - box_min;
+
+  // The method below is inspired by Christer Ericson's book Real-Time
+  // Collision Detection.  Instead of testing a capsule against a box, we test
+  // a segment against an box that is oversized by the capsule radius.
+
+  // First, we test if the line segment intersects a box with its faces
+  // expanded outwards by the capsule radius.  If not, there is no collision.
+  double t1, t2;
+  if (!intersects_line(t1, t2, from_a, from_direction, radius)) {
+    return nullptr;
+  }
+
+  if (t2 < 0.0 || t1 > 1.0) {
     return nullptr;
     return nullptr;
   }
   }
 
 
+  t1 = std::min(1.0, std::max(0.0, (t1 + t2) * 0.5));
+  LPoint3 point = from_a + from_direction * t1;
+
+  // We now have a point of intersection between the line segment and the
+  // oversized box.  Check on how many axes it lies outside the box.  If it is
+  // less than two, we know that it does not lie in one of the rounded regions
+  // of the oversized rounded box, and it is a guaranteed hit.  Otherwise, we
+  // will need to test against the edge regions.
+  if ((point[0] < box_min[0] || point[0] > box_max[0]) +
+      (point[1] < box_min[1] || point[1] > box_max[1]) +
+      (point[2] < box_min[2] || point[2] > box_max[2]) > 1) {
+    // Test the capsule against each edge of the box.
+    static const struct {
+      LPoint3 point;
+      int axis;
+    } edges[] = {
+      {{0, 0, 0}, 0},
+      {{0, 1, 0}, 0},
+      {{0, 0, 1}, 0},
+      {{0, 1, 1}, 0},
+      {{0, 0, 0}, 1},
+      {{0, 0, 1}, 1},
+      {{1, 0, 0}, 1},
+      {{1, 0, 1}, 1},
+      {{0, 0, 0}, 2},
+      {{0, 1, 0}, 2},
+      {{1, 0, 0}, 2},
+      {{1, 1, 0}, 2},
+    };
+
+    PN_stdfloat best_dist_sq = FLT_MAX;
+
+    for (int i = 0; i < 12; ++i) {
+      LPoint3 vertex = edges[i].point;
+      vertex.componentwise_mult(dimensions);
+      vertex += box_min;
+      LVector3 delta(0);
+      delta[edges[i].axis] = dimensions[edges[i].axis];
+      double u1, u2;
+      CollisionTube::calc_closest_segment_points(u1, u2, from_a, from_direction, vertex, delta);
+      PN_stdfloat dist_sq = ((from_a + from_direction * u1) - (vertex + delta * u2)).length_squared();
+      if (dist_sq < best_dist_sq) {
+        best_dist_sq = dist_sq;
+      }
+    }
+
+    if (best_dist_sq > radius_sq) {
+      // It is not actually touching any edge.
+      return nullptr;
+    }
+  }
+
   if (collide_cat.is_debug()) {
   if (collide_cat.is_debug()) {
     collide_cat.debug()
     collide_cat.debug()
       << "intersection detected from " << entry.get_from_node_path()
       << "intersection detected from " << entry.get_from_node_path()
       << " into " << entry.get_into_node_path() << "\n";
       << " into " << entry.get_into_node_path() << "\n";
   }
   }
-
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
 
-  LPoint3 into_intersection_point = from_origin + near_t * from_direction;
-
-  LVector3 normal =
-    (has_effective_normal() && seg->get_respect_effective_normal())
-    ? get_effective_normal() : near_plane.get_normal();
+  // Which is the longest axis?
+  LVector3 diff = point - _center;
+  diff[0] /= dimensions[0];
+  diff[1] /= dimensions[1];
+  diff[2] /= dimensions[2];
+  int axis = 0;
+  if (cabs(diff[0]) > cabs(diff[1])) {
+    if (cabs(diff[0]) > cabs(diff[2])) {
+      axis = 0;
+    } else {
+      axis = 2;
+    }
+  } else {
+    if (cabs(diff[1]) > cabs(diff[2])) {
+      axis = 1;
+    } else {
+      axis = 2;
+    }
+  }
+  LVector3 normal(0);
+  normal[axis] = std::copysign(1, diff[axis]);
+
+  LPoint3 clamped = point.fmax(box_min).fmin(box_max);
+  LPoint3 surface_point = clamped;
+  surface_point[axis] = (diff[axis] >= 0.0f) ? box_max[axis] : box_min[axis];
+
+  // Is the point inside the box?
+  LVector3 interior_vec;
+  if (clamped != point) {
+    // No, it is outside.  The interior point is in the direction of the
+    // surface point.
+    interior_vec = point - surface_point;
+    if (!interior_vec.normalize()) {
+      interior_vec = normal;
+    }
+  } else {
+    // It is inside.  I think any point will work for this.
+    interior_vec = normal;
+  }
+  new_entry->set_interior_point(point - interior_vec * radius);
+  new_entry->set_surface_point(surface_point);
 
 
-  new_entry->set_surface_normal(normal);
-  new_entry->set_surface_point(into_intersection_point);
+  if (has_effective_normal() && tube->get_respect_effective_normal()) {
+    new_entry->set_surface_normal(get_effective_normal());
+  } else {
+    new_entry->set_surface_normal(normal);
+  }
 
 
   return new_entry;
   return new_entry;
 }
 }
@@ -823,6 +952,51 @@ fill_viz_geom() {
   _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
   _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
 }
 }
 
 
+/**
+ * Determine the point(s) of intersection of a parametric line with the box.
+ * The line is infinite in both directions, and passes through "from" and
+ * from+delta.  If the line does not intersect the box, the function returns
+ * false, and t1 and t2 are undefined.  If it does intersect the box, it
+ * returns true, and t1 and t2 are set to the points along the equation
+ * from+t*delta that correspond to the two points of intersection.
+ */
+bool CollisionBox::
+intersects_line(double &t1, double &t2,
+                const LPoint3 &from, const LVector3 &delta,
+                PN_stdfloat inflate_size) const {
+
+  LPoint3 bmin = _min - LVector3(inflate_size);
+  LPoint3 bmax = _max + LVector3(inflate_size);
+
+  double tmin = -DBL_MAX;
+  double tmax = DBL_MAX;
+
+  for (int i = 0; i < 3; ++i) {
+    PN_stdfloat d = delta[i];
+    if (!IS_NEARLY_ZERO(d)) {
+      double tmin2 = (bmin[i] - from[i]) / d;
+      double tmax2 = (bmax[i] - from[i]) / d;
+      if (tmin2 > tmax2) {
+        std::swap(tmin2, tmax2);
+      }
+      tmin = std::max(tmin, tmin2);
+      tmax = std::min(tmax, tmax2);
+
+      if (tmin > tmax) {
+        return false;
+      }
+
+    } else if (from[i] < bmin[i] || from[i] > bmax[i]) {
+      // The line is entirely parallel in this dimension.
+      return false;
+    }
+  }
+
+  t1 = tmin;
+  t2 = tmax;
+  return true;
+}
+
 /**
 /**
  * Clips the polygon by all of the clip planes named in the clip plane
  * Clips the polygon by all of the clip planes named in the clip plane
  * attribute and fills new_points up with the resulting points.
  * attribute and fills new_points up with the resulting points.

+ 9 - 0
panda/src/collide/collisionBox.h

@@ -75,15 +75,24 @@ protected:
   virtual PT(BoundingVolume) compute_internal_bounds() const;
   virtual PT(BoundingVolume) compute_internal_bounds() const;
   virtual PT(CollisionEntry)
   virtual PT(CollisionEntry)
     test_intersection_from_sphere(const CollisionEntry &entry) const;
     test_intersection_from_sphere(const CollisionEntry &entry) const;
+  virtual PT(CollisionEntry)
+    test_intersection_from_line(const CollisionEntry &entry) const;
   virtual PT(CollisionEntry)
   virtual PT(CollisionEntry)
     test_intersection_from_ray(const CollisionEntry &entry) const;
     test_intersection_from_ray(const CollisionEntry &entry) const;
   virtual PT(CollisionEntry)
   virtual PT(CollisionEntry)
     test_intersection_from_segment(const CollisionEntry &entry) const;
     test_intersection_from_segment(const CollisionEntry &entry) const;
+  virtual PT(CollisionEntry)
+    test_intersection_from_tube(const CollisionEntry &entry) const;
   virtual PT(CollisionEntry)
   virtual PT(CollisionEntry)
     test_intersection_from_box(const CollisionEntry &entry) const;
     test_intersection_from_box(const CollisionEntry &entry) const;
 
 
   virtual void fill_viz_geom();
   virtual void fill_viz_geom();
 
 
+protected:
+  bool intersects_line(double &t1, double &t2,
+                       const LPoint3 &from, const LVector3 &delta,
+                       PN_stdfloat inflate_size=0) const;
+
 private:
 private:
   LPoint3 _center;
   LPoint3 _center;
   LPoint3 _min;
   LPoint3 _min;

+ 144 - 8
panda/src/collide/collisionTube.cxx

@@ -391,6 +391,70 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
   return new_entry;
   return new_entry;
 }
 }
 
 
+/**
+ *
+ */
+PT(CollisionEntry) CollisionTube::
+test_intersection_from_tube(const CollisionEntry &entry) const {
+  const CollisionTube *tube;
+  DCAST_INTO_R(tube, entry.get_from(), nullptr);
+
+  LPoint3 into_a = _a;
+  LVector3 into_direction = _b - into_a;
+
+  const LMatrix4 &wrt_mat = entry.get_wrt_mat();
+
+  LPoint3 from_a = tube->get_point_a() * wrt_mat;
+  LPoint3 from_b = tube->get_point_b() * wrt_mat;
+  LVector3 from_direction = from_b - from_a;
+
+  LVector3 from_radius_v =
+    LVector3(tube->get_radius(), 0.0f, 0.0f) * wrt_mat;
+  PN_stdfloat from_radius = length(from_radius_v);
+
+  // Determine the points on each segment with the smallest distance between.
+  double into_t, from_t;
+  calc_closest_segment_points(into_t, from_t,
+                              into_a, into_direction,
+                              from_a, from_direction);
+  LPoint3 into_closest = into_a + into_direction * into_t;
+  LPoint3 from_closest = from_a + from_direction * from_t;
+
+  // If the distance is greater than the sum of tube radii, the test fails.
+  LVector3 closest_vec = from_closest - into_closest;
+  PN_stdfloat distance = closest_vec.length();
+  if (distance > _radius + from_radius) {
+    return nullptr;
+  }
+
+  if (collide_cat.is_debug()) {
+    collide_cat.debug()
+      << "intersection detected from " << entry.get_from_node_path()
+      << " into " << entry.get_into_node_path() << "\n";
+  }
+  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
+
+  if (distance != 0) {
+    // This is the most common case, where the line segments don't touch
+    // exactly.  We point the normal along the vector of the closest distance.
+    LVector3 surface_normal = closest_vec * (1.0 / distance);
+
+    new_entry->set_surface_point(into_closest + surface_normal * _radius);
+    new_entry->set_interior_point(from_closest - surface_normal * from_radius);
+
+    if (has_effective_normal() && tube->get_respect_effective_normal()) {
+      new_entry->set_surface_normal(get_effective_normal());
+    } else if (distance != 0) {
+      new_entry->set_surface_normal(surface_normal);
+    }
+  } else {
+    // The rare case of the line segments touching exactly.
+    set_intersection_point(new_entry, into_closest, 0);
+  }
+
+  return new_entry;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -578,6 +642,80 @@ calc_sphere2_vertex(int ri, int si, int num_rings, int num_slices,
   return LVertex(x, y, z);
   return LVertex(x, y, z);
 }
 }
 
 
+/**
+ * Given line segments s1 and s2 defined by two points each, computes the
+ * point on each segment with the closest distance between them.
+ */
+void CollisionTube::
+calc_closest_segment_points(double &t1, double &t2,
+                            const LPoint3 &from1, const LVector3 &delta1,
+                            const LPoint3 &from2, const LVector3 &delta2) {
+  // Copyright 2001 softSurfer, 2012 Dan Sunday
+  // This code may be freely used, distributed and modified for any purpose
+  // providing that this copyright notice is included with it.
+  // SoftSurfer makes no warranty for this code, and cannot be held
+  // liable for any real or imagined damage resulting from its use.
+  // Users of this code must verify correctness for their application.
+  LVector3 w = from1 - from2;
+  PN_stdfloat a = delta1.dot(delta1); // always >= 0
+  PN_stdfloat b = delta1.dot(delta2);
+  PN_stdfloat c = delta2.dot(delta2); // always >= 0
+  PN_stdfloat d = delta1.dot(w);
+  PN_stdfloat e = delta2.dot(w);
+  PN_stdfloat D = a * c - b * b; // always >= 0
+  PN_stdfloat sN, sD = D;
+  PN_stdfloat tN, tD = D;
+
+  // compute the line parameters of the two closest points
+  if (IS_NEARLY_ZERO(D)) { // the lines are almost parallel
+    sN = 0.0; // force using point P0 on segment S1
+    sD = 1.0; // to prevent possible division by 0.0 later
+    tN = e;
+    tD = c;
+  } else {
+    // get the closest points on the infinite lines
+    sN = (b*e - c*d);
+    tN = (a*e - b*d);
+    if (sN < 0.0) { // sc < 0 => the s=0 edge is visible
+      sN = 0.0;
+      tN = e;
+      tD = c;
+    } else if (sN > sD) { // sc > 1  => the s=1 edge is visible
+      sN = sD;
+      tN = e + b;
+      tD = c;
+    }
+  }
+
+  if (tN < 0.0) { // tc < 0 => the t=0 edge is visible
+    tN = 0.0;
+    // recompute sc for this edge
+    if (-d < 0.0) {
+      sN = 0.0;
+    } else if (-d > a) {
+      sN = sD;
+    } else {
+      sN = -d;
+      sD = a;
+    }
+  } else if (tN > tD) { // tc > 1  => the t=1 edge is visible
+    tN = tD;
+    // recompute sc for this edge
+    if ((-d + b) < 0.0) {
+      sN = 0;
+    } else if ((-d + b) > a) {
+      sN = sD;
+    } else {
+      sN = (-d +  b);
+      sD = a;
+    }
+  }
+
+  // finally do the division to get sc and tc
+  t1 = (IS_NEARLY_ZERO(sN) ? 0.0 : sN / sD);
+  t2 = (IS_NEARLY_ZERO(tN) ? 0.0 : tN / tD);
+}
+
 /**
 /**
  * Determine the point(s) of intersection of a parametric line with the tube.
  * Determine the point(s) of intersection of a parametric line with the tube.
  * The line is infinite in both directions, and passes through "from" and
  * The line is infinite in both directions, and passes through "from" and
@@ -692,7 +830,7 @@ intersects_line(double &t1, double &t2,
     // The starting point is off the bottom of the tube.  Test the line
     // The starting point is off the bottom of the tube.  Test the line
     // against the first endcap.
     // against the first endcap.
     double t1a, t2a;
     double t1a, t2a;
-    if (!sphere_intersects_line(t1a, t2a, 0.0f, from, delta, inflate_radius)) {
+    if (!sphere_intersects_line(t1a, t2a, 0.0f, from, delta, radius)) {
       // If there's no intersection with the endcap, there can't be an
       // If there's no intersection with the endcap, there can't be an
       // intersection with the cylinder.
       // intersection with the cylinder.
       return false;
       return false;
@@ -703,7 +841,7 @@ intersects_line(double &t1, double &t2,
     // The starting point is off the top of the tube.  Test the line against
     // The starting point is off the top of the tube.  Test the line against
     // the second endcap.
     // the second endcap.
     double t1b, t2b;
     double t1b, t2b;
-    if (!sphere_intersects_line(t1b, t2b, _length, from, delta, inflate_radius)) {
+    if (!sphere_intersects_line(t1b, t2b, _length, from, delta, radius)) {
       // If there's no intersection with the endcap, there can't be an
       // If there's no intersection with the endcap, there can't be an
       // intersection with the cylinder.
       // intersection with the cylinder.
       return false;
       return false;
@@ -715,7 +853,7 @@ intersects_line(double &t1, double &t2,
     // The ending point is off the bottom of the tube.  Test the line against
     // The ending point is off the bottom of the tube.  Test the line against
     // the first endcap.
     // the first endcap.
     double t1a, t2a;
     double t1a, t2a;
-    if (!sphere_intersects_line(t1a, t2a, 0.0f, from, delta, inflate_radius)) {
+    if (!sphere_intersects_line(t1a, t2a, 0.0f, from, delta, radius)) {
       // If there's no intersection with the endcap, there can't be an
       // If there's no intersection with the endcap, there can't be an
       // intersection with the cylinder.
       // intersection with the cylinder.
       return false;
       return false;
@@ -726,7 +864,7 @@ intersects_line(double &t1, double &t2,
     // The ending point is off the top of the tube.  Test the line against the
     // The ending point is off the top of the tube.  Test the line against the
     // second endcap.
     // second endcap.
     double t1b, t2b;
     double t1b, t2b;
-    if (!sphere_intersects_line(t1b, t2b, _length, from, delta, inflate_radius)) {
+    if (!sphere_intersects_line(t1b, t2b, _length, from, delta, radius)) {
       // If there's no intersection with the endcap, there can't be an
       // If there's no intersection with the endcap, there can't be an
       // intersection with the cylinder.
       // intersection with the cylinder.
       return false;
       return false;
@@ -740,16 +878,14 @@ intersects_line(double &t1, double &t2,
 /**
 /**
  * After confirming that the line intersects an infinite cylinder, test
  * After confirming that the line intersects an infinite cylinder, test
  * whether it intersects one or the other endcaps.  The y parameter specifies
  * whether it intersects one or the other endcaps.  The y parameter specifies
- * the center of the sphere (and hence the particular endcap.
+ * the center of the sphere (and hence the particular endcap).
  */
  */
 bool CollisionTube::
 bool CollisionTube::
 sphere_intersects_line(double &t1, double &t2, PN_stdfloat center_y,
 sphere_intersects_line(double &t1, double &t2, PN_stdfloat center_y,
                        const LPoint3 &from, const LVector3 &delta,
                        const LPoint3 &from, const LVector3 &delta,
-                       PN_stdfloat inflate_radius) const {
+                       PN_stdfloat radius) {
   // See CollisionSphere::intersects_line() for a derivation of the formula
   // See CollisionSphere::intersects_line() for a derivation of the formula
   // here.
   // here.
-  PN_stdfloat radius = _radius + inflate_radius;
-
   double A = dot(delta, delta);
   double A = dot(delta, delta);
 
 
   nassertr(A != 0.0, false);
   nassertr(A != 0.0, false);

+ 10 - 3
panda/src/collide/collisionTube.h

@@ -82,6 +82,8 @@ protected:
   virtual PT(CollisionEntry)
   virtual PT(CollisionEntry)
   test_intersection_from_segment(const CollisionEntry &entry) const;
   test_intersection_from_segment(const CollisionEntry &entry) const;
   virtual PT(CollisionEntry)
   virtual PT(CollisionEntry)
+  test_intersection_from_tube(const CollisionEntry &entry) const;
+  virtual PT(CollisionEntry)
   test_intersection_from_parabola(const CollisionEntry &entry) const;
   test_intersection_from_parabola(const CollisionEntry &entry) const;
 
 
   virtual void fill_viz_geom();
   virtual void fill_viz_geom();
@@ -93,12 +95,15 @@ private:
   LVertex calc_sphere2_vertex(int ri, int si, int num_rings, int num_slices,
   LVertex calc_sphere2_vertex(int ri, int si, int num_rings, int num_slices,
                               PN_stdfloat length);
                               PN_stdfloat length);
 
 
+  static void calc_closest_segment_points(double &t1, double &t2,
+                                          const LPoint3 &from1, const LVector3 &delta1,
+                                          const LPoint3 &from2, const LVector3 &delta2);
   bool intersects_line(double &t1, double &t2,
   bool intersects_line(double &t1, double &t2,
                        const LPoint3 &from, const LVector3 &delta,
                        const LPoint3 &from, const LVector3 &delta,
                        PN_stdfloat inflate_radius) const;
                        PN_stdfloat inflate_radius) const;
-  bool sphere_intersects_line(double &t1, double &t2, PN_stdfloat center_y,
-                              const LPoint3 &from, const LVector3 &delta,
-                              PN_stdfloat inflate_radius) const;
+  static bool sphere_intersects_line(double &t1, double &t2, PN_stdfloat center_y,
+                                     const LPoint3 &from, const LVector3 &delta,
+                                     PN_stdfloat radius);
   bool intersects_parabola(double &t, const LParabola &parabola,
   bool intersects_parabola(double &t, const LParabola &parabola,
                            double t1, double t2,
                            double t1, double t2,
                            const LPoint3 &p1, const LPoint3 &p2) const;
                            const LPoint3 &p1, const LPoint3 &p2) const;
@@ -146,6 +151,8 @@ public:
 
 
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
+
+  friend class CollisionBox;
 };
 };
 
 
 #include "collisionTube.I"
 #include "collisionTube.I"

+ 0 - 70
panda/src/collide/test_collide.cxx

@@ -1,70 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file test_collide.cxx
- * @author drose
- * @date 2000-04-24
- */
-
-#include "collisionTraverser.h"
-#include "collisionNode.h"
-#include "collisionSphere.h"
-#include "collisionPlane.h"
-#include "collisionHandlerPusher.h"
-
-#include "namedNode.h"
-#include "pt_NamedNode.h"
-#include "pointerTo.h"
-#include "transformTransition.h"
-#include "luse.h"
-#include "get_rel_pos.h"
-#include "renderRelation.h"
-
-int
-main(int argc, char *argv[]) {
-  PT_NamedNode r = new NamedNode("r");
-
-  PT_NamedNode a = new NamedNode("a");
-  PT_NamedNode b = new NamedNode("b");
-
-  PT(CollisionNode) aa = new CollisionNode("aa");
-  PT(CollisionNode) ab = new CollisionNode("ab");
-  PT(CollisionNode) ba = new CollisionNode("ba");
-
-  RenderRelation *r_a = new RenderRelation(r, a);
-  RenderRelation *r_b = new RenderRelation(r, b);
-
-  RenderRelation *a_aa = new RenderRelation(a, aa);
-  RenderRelation *a_ab = new RenderRelation(a, ab);
-  RenderRelation *b_ba = new RenderRelation(b, ba);
-
-
-  CollisionSphere *aa1 = new CollisionSphere(LPoint3f(0, 0, 0), 1);
-  aa->add_solid(aa1);
-  a_aa->set_transition(new TransformTransition(LMatrix4f::translate_mat(0, -5, 0)));
-
-  CollisionSphere *ab1 = new CollisionSphere(LPoint3f(0, 2, 0), 1.5);
-  ab->add_solid(ab1);
-
-  Planef plane(LVector3f(0, 1, 0), LPoint3f(0, 0, 0));
-  CollisionPlane *ba1 = new CollisionPlane(plane);
-  ba->add_solid(ba1);
-
-  CollisionTraverser ct;
-  PT(CollisionHandlerPusher) chp = new CollisionHandlerPusher;
-  chp->add_collider(aa, a_aa);
-  ct.add_collider(aa, chp);
-
-  ct.traverse(r);
-
-  nout << "\nFrame 2:\n\n";
-
-  ct.traverse(r);
-
-  return (0);
-}

+ 3 - 5
panda/src/cull/cullBinBackToFront.cxx

@@ -85,9 +85,6 @@ void CullBinBackToFront::
 draw(bool force, Thread *current_thread) {
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
   PStatTimer timer(_draw_this_pcollector, current_thread);
 
 
-  GeomPipelineReader geom_reader(current_thread);
-  GeomVertexDataPipelineReader data_reader(current_thread);
-
   Objects::const_iterator oi;
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
     CullableObject *object = (*oi)._object;
@@ -96,9 +93,10 @@ draw(bool force, Thread *current_thread) {
       nassertd(object->_geom != nullptr) continue;
       nassertd(object->_geom != nullptr) continue;
 
 
       _gsg->set_state_and_transform(object->_state, object->_internal_transform);
       _gsg->set_state_and_transform(object->_state, object->_internal_transform);
-      data_reader.set_object(object->_munged_data);
+
+      GeomPipelineReader geom_reader(object->_geom, current_thread);
+      GeomVertexDataPipelineReader data_reader(object->_munged_data, current_thread);
       data_reader.check_array_readers();
       data_reader.check_array_readers();
-      geom_reader.set_object(object->_geom);
       geom_reader.draw(_gsg, &data_reader, force);
       geom_reader.draw(_gsg, &data_reader, force);
     } else {
     } else {
       // It has a callback associated.
       // It has a callback associated.

+ 3 - 5
panda/src/cull/cullBinFixed.cxx

@@ -71,9 +71,6 @@ void CullBinFixed::
 draw(bool force, Thread *current_thread) {
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
   PStatTimer timer(_draw_this_pcollector, current_thread);
 
 
-  GeomPipelineReader geom_reader(current_thread);
-  GeomVertexDataPipelineReader data_reader(current_thread);
-
   Objects::const_iterator oi;
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
     CullableObject *object = (*oi)._object;
@@ -82,9 +79,10 @@ draw(bool force, Thread *current_thread) {
       nassertd(object->_geom != nullptr) continue;
       nassertd(object->_geom != nullptr) continue;
 
 
       _gsg->set_state_and_transform(object->_state, object->_internal_transform);
       _gsg->set_state_and_transform(object->_state, object->_internal_transform);
-      data_reader.set_object(object->_munged_data);
+
+      GeomPipelineReader geom_reader(object->_geom, current_thread);
+      GeomVertexDataPipelineReader data_reader(object->_munged_data, current_thread);
       data_reader.check_array_readers();
       data_reader.check_array_readers();
-      geom_reader.set_object(object->_geom);
       geom_reader.draw(_gsg, &data_reader, force);
       geom_reader.draw(_gsg, &data_reader, force);
     } else {
     } else {
       // It has a callback associated.
       // It has a callback associated.

+ 3 - 5
panda/src/cull/cullBinFrontToBack.cxx

@@ -85,9 +85,6 @@ void CullBinFrontToBack::
 draw(bool force, Thread *current_thread) {
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
   PStatTimer timer(_draw_this_pcollector, current_thread);
 
 
-  GeomPipelineReader geom_reader(current_thread);
-  GeomVertexDataPipelineReader data_reader(current_thread);
-
   Objects::const_iterator oi;
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
     CullableObject *object = (*oi)._object;
@@ -96,9 +93,10 @@ draw(bool force, Thread *current_thread) {
       nassertd(object->_geom != nullptr) continue;
       nassertd(object->_geom != nullptr) continue;
 
 
       _gsg->set_state_and_transform(object->_state, object->_internal_transform);
       _gsg->set_state_and_transform(object->_state, object->_internal_transform);
-      data_reader.set_object(object->_munged_data);
+
+      GeomPipelineReader geom_reader(object->_geom, current_thread);
+      GeomVertexDataPipelineReader data_reader(object->_munged_data, current_thread);
       data_reader.check_array_readers();
       data_reader.check_array_readers();
-      geom_reader.set_object(object->_geom);
       geom_reader.draw(_gsg, &data_reader, force);
       geom_reader.draw(_gsg, &data_reader, force);
     } else {
     } else {
       // It has a callback associated.
       // It has a callback associated.

+ 3 - 5
panda/src/cull/cullBinStateSorted.cxx

@@ -70,9 +70,6 @@ void CullBinStateSorted::
 draw(bool force, Thread *current_thread) {
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
   PStatTimer timer(_draw_this_pcollector, current_thread);
 
 
-  GeomPipelineReader geom_reader(current_thread);
-  GeomVertexDataPipelineReader data_reader(current_thread);
-
   Objects::const_iterator oi;
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
     CullableObject *object = (*oi)._object;
@@ -81,9 +78,10 @@ draw(bool force, Thread *current_thread) {
       nassertd(object->_geom != nullptr) continue;
       nassertd(object->_geom != nullptr) continue;
 
 
       _gsg->set_state_and_transform(object->_state, object->_internal_transform);
       _gsg->set_state_and_transform(object->_state, object->_internal_transform);
-      data_reader.set_object(object->_munged_data);
+
+      GeomPipelineReader geom_reader(object->_geom, current_thread);
+      GeomVertexDataPipelineReader data_reader(object->_munged_data, current_thread);
       data_reader.check_array_readers();
       data_reader.check_array_readers();
-      geom_reader.set_object(object->_geom);
       geom_reader.draw(_gsg, &data_reader, force);
       geom_reader.draw(_gsg, &data_reader, force);
     } else {
     } else {
       // It has a callback associated.
       // It has a callback associated.

+ 3 - 5
panda/src/cull/cullBinUnsorted.cxx

@@ -55,9 +55,6 @@ void CullBinUnsorted::
 draw(bool force, Thread *current_thread) {
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
   PStatTimer timer(_draw_this_pcollector, current_thread);
 
 
-  GeomPipelineReader geom_reader(current_thread);
-  GeomVertexDataPipelineReader data_reader(current_thread);
-
   Objects::iterator oi;
   Objects::iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi);
     CullableObject *object = (*oi);
@@ -66,9 +63,10 @@ draw(bool force, Thread *current_thread) {
       nassertd(object->_geom != nullptr) continue;
       nassertd(object->_geom != nullptr) continue;
 
 
       _gsg->set_state_and_transform(object->_state, object->_internal_transform);
       _gsg->set_state_and_transform(object->_state, object->_internal_transform);
-      data_reader.set_object(object->_munged_data);
+
+      GeomPipelineReader geom_reader(object->_geom, current_thread);
+      GeomVertexDataPipelineReader data_reader(object->_munged_data, current_thread);
       data_reader.check_array_readers();
       data_reader.check_array_readers();
-      geom_reader.set_object(object->_geom);
       geom_reader.draw(_gsg, &data_reader, force);
       geom_reader.draw(_gsg, &data_reader, force);
     } else {
     } else {
       // It has a callback associated.
       // It has a callback associated.

+ 0 - 18
panda/src/display/test_display.cxx

@@ -1,18 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file test_display.cxx
- * @author shochet
- * @date 2000-02-02
- */
-
-#include "graphicsWindow.h"
-
-int main() {
-  return 0;
-}

+ 10 - 4
panda/src/dxgsg9/dxGeomMunger9.cxx

@@ -300,8 +300,11 @@ compare_to_impl(const GeomMunger *other) const {
   if (_filtered_texture != om->_filtered_texture) {
   if (_filtered_texture != om->_filtered_texture) {
     return _filtered_texture < om->_filtered_texture ? -1 : 1;
     return _filtered_texture < om->_filtered_texture ? -1 : 1;
   }
   }
-  if (_tex_gen != om->_tex_gen) {
-    return _tex_gen < om->_tex_gen ? -1 : 1;
+  if (_tex_gen.owner_before(om->_tex_gen)) {
+    return -1;
+  }
+  if (om->_tex_gen.owner_before(_tex_gen)) {
+    return 1;
   }
   }
 
 
   return StandardMunger::compare_to_impl(other);
   return StandardMunger::compare_to_impl(other);
@@ -321,8 +324,11 @@ geom_compare_to_impl(const GeomMunger *other) const {
   if (_filtered_texture != om->_filtered_texture) {
   if (_filtered_texture != om->_filtered_texture) {
     return _filtered_texture < om->_filtered_texture ? -1 : 1;
     return _filtered_texture < om->_filtered_texture ? -1 : 1;
   }
   }
-  if (_tex_gen != om->_tex_gen) {
-    return _tex_gen < om->_tex_gen ? -1 : 1;
+  if (_tex_gen.owner_before(om->_tex_gen)) {
+    return -1;
+  }
+  if (om->_tex_gen.owner_before(_tex_gen)) {
+    return 1;
   }
   }
 
 
   return StandardMunger::geom_compare_to_impl(other);
   return StandardMunger::geom_compare_to_impl(other);

+ 6 - 0
panda/src/egg/eggData.h

@@ -68,6 +68,12 @@ PUBLISHED:
   INLINE void set_egg_timestamp(time_t egg_timestamp);
   INLINE void set_egg_timestamp(time_t egg_timestamp);
   INLINE time_t get_egg_timestamp() const;
   INLINE time_t get_egg_timestamp() const;
 
 
+  MAKE_PROPERTY(auto_resolve_externals, get_auto_resolve_externals,
+                                        set_auto_resolve_externals);
+  MAKE_PROPERTY(coordinate_system, get_coordinate_system, set_coordinate_system);
+  MAKE_PROPERTY(egg_filename, get_egg_filename, set_egg_filename);
+  MAKE_PROPERTY(egg_timestamp, get_egg_timestamp, set_egg_timestamp);
+
   INLINE void recompute_vertex_normals(double threshold);
   INLINE void recompute_vertex_normals(double threshold);
   INLINE void recompute_polygon_normals();
   INLINE void recompute_polygon_normals();
   INLINE void strip_normals();
   INLINE void strip_normals();

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

@@ -109,6 +109,7 @@ PUBLISHED:
   EggNode *get_next_child();
   EggNode *get_next_child();
 
 
   EXTENSION(PyObject *get_children() const);
   EXTENSION(PyObject *get_children() const);
+  MAKE_PROPERTY(children, get_children);
 
 
   EggNode *add_child(EggNode *node);
   EggNode *add_child(EggNode *node);
   PT(EggNode) remove_child(EggNode *node);
   PT(EggNode) remove_child(EggNode *node);

+ 9 - 6
panda/src/egg/eggNode.h

@@ -44,6 +44,9 @@ PUBLISHED:
   INLINE bool is_under_transform() const;
   INLINE bool is_under_transform() const;
   INLINE bool is_local_coord() const;
   INLINE bool is_local_coord() const;
 
 
+  MAKE_PROPERTY(parent, get_parent);
+  MAKE_PROPERTY(depth, get_depth);
+
   INLINE const LMatrix4d &get_vertex_frame() const;
   INLINE const LMatrix4d &get_vertex_frame() const;
   INLINE const LMatrix4d &get_node_frame() const;
   INLINE const LMatrix4d &get_node_frame() const;
   INLINE const LMatrix4d &get_vertex_frame_inv() const;
   INLINE const LMatrix4d &get_vertex_frame_inv() const;
@@ -51,12 +54,12 @@ PUBLISHED:
   INLINE const LMatrix4d &get_vertex_to_node() const;
   INLINE const LMatrix4d &get_vertex_to_node() const;
   INLINE const LMatrix4d &get_node_to_vertex() const;
   INLINE const LMatrix4d &get_node_to_vertex() const;
 
 
-  INLINE const LMatrix4d *get_vertex_frame_ptr()const;
-  INLINE const LMatrix4d *get_node_frame_ptr()const;
-  INLINE const LMatrix4d *get_vertex_frame_inv_ptr()const;
-  INLINE const LMatrix4d *get_node_frame_inv_ptr()const;
-  INLINE const LMatrix4d *get_vertex_to_node_ptr()const;
-  INLINE const LMatrix4d *get_node_to_vertex_ptr()const;
+  INLINE const LMatrix4d *get_vertex_frame_ptr() const;
+  INLINE const LMatrix4d *get_node_frame_ptr() const;
+  INLINE const LMatrix4d *get_vertex_frame_inv_ptr() const;
+  INLINE const LMatrix4d *get_node_frame_inv_ptr() const;
+  INLINE const LMatrix4d *get_vertex_to_node_ptr() const;
+  INLINE const LMatrix4d *get_node_to_vertex_ptr() const;
 
 
   INLINE void transform(const LMatrix4d &mat);
   INLINE void transform(const LMatrix4d &mat);
   INLINE void transform_vertices_only(const LMatrix4d &mat);
   INLINE void transform_vertices_only(const LMatrix4d &mat);

+ 20 - 0
panda/src/express/pointerTo.h

@@ -215,6 +215,26 @@ void swap(ConstPointerTo<T> &one, ConstPointerTo<T> &two) noexcept {
 }
 }
 
 
 
 
+// Define owner_less specializations, for completeness' sake.
+namespace std {
+  template<class T>
+  struct owner_less<PointerTo<T> > {
+    bool operator () (const PointerTo<T> &lhs,
+                      const PointerTo<T> &rhs) const noexcept {
+      return lhs < rhs;
+    }
+  };
+
+  template<class T>
+  struct owner_less<ConstPointerTo<T> > {
+    bool operator () (const ConstPointerTo<T> &lhs,
+                      const ConstPointerTo<T> &rhs) const noexcept {
+      return lhs < rhs;
+    }
+  };
+}
+
+
 // Finally, we'll define a couple of handy abbreviations to save on all that
 // Finally, we'll define a couple of handy abbreviations to save on all that
 // wasted typing time.
 // wasted typing time.
 
 

+ 1 - 0
panda/src/express/pointerToBase.h

@@ -53,6 +53,7 @@ protected:
 
 
   // This is needed to be able to access the privates of other instantiations.
   // This is needed to be able to access the privates of other instantiations.
   template<typename Y> friend class PointerToBase;
   template<typename Y> friend class PointerToBase;
+  template<typename Y> friend class WeakPointerToBase;
 
 
 PUBLISHED:
 PUBLISHED:
   ALWAYS_INLINE void clear();
   ALWAYS_INLINE void clear();

+ 0 - 7
panda/src/express/pointerToVoid.I

@@ -11,13 +11,6 @@
  * @date 2004-09-27
  * @date 2004-09-27
  */
  */
 
 
-/**
- *
- */
-constexpr PointerToVoid::
-PointerToVoid() noexcept : _void_ptr(nullptr) {
-}
-
 /**
 /**
  *
  *
  */
  */

+ 2 - 2
panda/src/express/pointerToVoid.h

@@ -32,7 +32,7 @@
  */
  */
 class EXPCL_PANDA_EXPRESS PointerToVoid : public MemoryBase {
 class EXPCL_PANDA_EXPRESS PointerToVoid : public MemoryBase {
 protected:
 protected:
-  constexpr PointerToVoid() noexcept;
+  constexpr PointerToVoid() noexcept = default;
   //INLINE ~PointerToVoid();
   //INLINE ~PointerToVoid();
 
 
 private:
 private:
@@ -63,7 +63,7 @@ protected:
   // a PointerTo any class that inherits virtually from ReferenceCount.  (You
   // a PointerTo any class that inherits virtually from ReferenceCount.  (You
   // can't downcast past a virtual inheritance level, but you can always
   // can't downcast past a virtual inheritance level, but you can always
   // cross-cast from a void pointer.)
   // cross-cast from a void pointer.)
-  AtomicAdjust::Pointer _void_ptr;
+  AtomicAdjust::Pointer _void_ptr = nullptr;
 };
 };
 
 
 #include "pointerToVoid.I"
 #include "pointerToVoid.I"

+ 264 - 34
panda/src/express/weakPointerTo.I

@@ -39,6 +39,49 @@ WeakPointerTo(const WeakPointerTo<T> &copy) :
 {
 {
 }
 }
 
 
+/**
+ *
+ */
+template<class T>
+INLINE WeakPointerTo<T>::
+WeakPointerTo(WeakPointerTo<T> &&from) noexcept :
+  WeakPointerToBase<T>(std::move(from))
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakPointerTo<T>::
+WeakPointerTo(const WeakPointerTo<Y> &r) noexcept :
+  WeakPointerToBase<T>(r)
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakPointerTo<T>::
+WeakPointerTo(const PointerTo<Y> &r) noexcept :
+  WeakPointerToBase<T>(r)
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakPointerTo<T>::
+WeakPointerTo(WeakPointerTo<Y> &&r) noexcept :
+  WeakPointerToBase<T>(std::move(r))
+{
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -82,23 +125,9 @@ operator T * () const {
 template<class T>
 template<class T>
 INLINE PointerTo<T> WeakPointerTo<T>::
 INLINE PointerTo<T> WeakPointerTo<T>::
 lock() const {
 lock() const {
-  WeakReferenceList *weak_ref = this->_weak_ref;
-  if (weak_ref != nullptr) {
-    PointerTo<T> ptr;
-    weak_ref->_lock.lock();
-    if (!weak_ref->was_deleted()) {
-      // We also need to check that the reference count is not zero (which can
-      // happen if the object is currently being destructed), since that could
-      // cause double deletion.
-      To *plain_ptr = (To *)WeakPointerToBase<T>::_void_ptr;
-      if (plain_ptr != nullptr && plain_ptr->ref_if_nonzero()) {
-        ptr.cheat() = plain_ptr;
-      }
-    }
-    weak_ref->_lock.unlock();
-    return ptr;
-  }
-  return nullptr;
+  PointerTo<T> ptr;
+  this->lock_into(ptr);
+  return ptr;
 }
 }
 
 
 /**
 /**
@@ -152,6 +181,49 @@ operator = (const WeakPointerTo<T> &copy) {
   return *this;
   return *this;
 }
 }
 
 
+/**
+ *
+ */
+template<class T>
+INLINE WeakPointerTo<T> &WeakPointerTo<T>::
+operator = (WeakPointerTo<T> &&from) noexcept {
+  this->reassign(std::move(from));
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakPointerTo<T> &WeakPointerTo<T>::
+operator = (const WeakPointerTo<Y> &r) noexcept {
+  this->reassign(r);
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakPointerTo<T> &WeakPointerTo<T>::
+operator = (const PointerTo<Y> &r) noexcept {
+  this->reassign(r);
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakPointerTo<T> &WeakPointerTo<T>::
+operator = (WeakPointerTo<Y> &&r) noexcept {
+  this->reassign(std::move(r));
+  return *this;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -202,6 +274,92 @@ WeakConstPointerTo(const WeakConstPointerTo<T> &copy) :
 {
 {
 }
 }
 
 
+/**
+ *
+ */
+template<class T>
+INLINE WeakConstPointerTo<T>::
+WeakConstPointerTo(WeakPointerTo<T> &&from) noexcept :
+  WeakPointerToBase<T>(std::move(from))
+{
+}
+
+/**
+ *
+ */
+template<class T>
+INLINE WeakConstPointerTo<T>::
+WeakConstPointerTo(WeakConstPointerTo<T> &&from) noexcept :
+  WeakPointerToBase<T>(std::move(from))
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T>::
+WeakConstPointerTo(const WeakPointerTo<Y> &r) noexcept :
+  WeakPointerToBase<T>(r)
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T>::
+WeakConstPointerTo(const WeakConstPointerTo<Y> &r) noexcept :
+  WeakPointerToBase<T>(r)
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T>::
+WeakConstPointerTo(const PointerTo<Y> &r) noexcept :
+  WeakPointerToBase<T>(r)
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T>::
+WeakConstPointerTo(const ConstPointerTo<Y> &r) noexcept :
+  WeakPointerToBase<T>(r)
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T>::
+WeakConstPointerTo(WeakPointerTo<Y> &&r) noexcept :
+  WeakPointerToBase<T>(std::move(r))
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T>::
+WeakConstPointerTo(WeakConstPointerTo<Y> &&r) noexcept :
+  WeakPointerToBase<T>(std::move(r))
+{
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -243,23 +401,9 @@ operator const T * () const {
 template<class T>
 template<class T>
 INLINE ConstPointerTo<T> WeakConstPointerTo<T>::
 INLINE ConstPointerTo<T> WeakConstPointerTo<T>::
 lock() const {
 lock() const {
-  WeakReferenceList *weak_ref = this->_weak_ref;
-  if (weak_ref != nullptr) {
-    ConstPointerTo<T> ptr;
-    weak_ref->_lock.lock();
-    if (!weak_ref->was_deleted()) {
-      // We also need to check that the reference count is not zero (which can
-      // happen if the object is currently being destructed), since that could
-      // cause double deletion.
-      const To *plain_ptr = (const To *)WeakPointerToBase<T>::_void_ptr;
-      if (plain_ptr != nullptr && plain_ptr->ref_if_nonzero()) {
-        ptr.cheat() = plain_ptr;
-      }
-    }
-    weak_ref->_lock.unlock();
-    return ptr;
-  }
-  return nullptr;
+  ConstPointerTo<T> ptr;
+  this->lock_into(ptr);
+  return ptr;
 }
 }
 
 
 /**
 /**
@@ -332,3 +476,89 @@ operator = (const WeakConstPointerTo<T> &copy) {
   ((WeakConstPointerTo<T> *)this)->reassign(*(const PointerToBase<T> *)&copy);
   ((WeakConstPointerTo<T> *)this)->reassign(*(const PointerToBase<T> *)&copy);
   return *this;
   return *this;
 }
 }
+
+/**
+ *
+ */
+template<class T>
+INLINE WeakConstPointerTo<T> &WeakConstPointerTo<T>::
+operator = (WeakPointerTo<T> &&from) noexcept {
+  this->reassign(std::move(from));
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+INLINE WeakConstPointerTo<T> &WeakConstPointerTo<T>::
+operator = (WeakConstPointerTo<T> &&from) noexcept {
+  this->reassign(std::move(from));
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T> &WeakConstPointerTo<T>::
+operator = (const WeakPointerTo<Y> &r) noexcept {
+  this->reassign(r);
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T> &WeakConstPointerTo<T>::
+operator = (const WeakConstPointerTo<Y> &r) noexcept {
+  this->reassign(r);
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T> &WeakConstPointerTo<T>::
+operator = (const PointerTo<Y> &r) noexcept {
+  this->reassign(r);
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T> &WeakConstPointerTo<T>::
+operator = (const ConstPointerTo<Y> &r) noexcept {
+  this->reassign(r);
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T> &WeakConstPointerTo<T>::
+operator = (WeakPointerTo<Y> &&r) noexcept {
+  this->reassign(std::move(r));
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE WeakConstPointerTo<T> &WeakConstPointerTo<T>::
+operator = (WeakConstPointerTo<Y> &&r) noexcept {
+  this->reassign(std::move(r));
+  return *this;
+}

+ 77 - 2
panda/src/express/weakPointerTo.h

@@ -30,11 +30,21 @@ class WeakPointerTo : public WeakPointerToBase<T> {
 public:
 public:
   typedef typename WeakPointerToBase<T>::To To;
   typedef typename WeakPointerToBase<T>::To To;
 PUBLISHED:
 PUBLISHED:
-  INLINE WeakPointerTo(To *ptr = nullptr);
+  constexpr WeakPointerTo() noexcept = default;
+  INLINE WeakPointerTo(To *ptr);
   INLINE WeakPointerTo(const PointerTo<T> &copy);
   INLINE WeakPointerTo(const PointerTo<T> &copy);
   INLINE WeakPointerTo(const WeakPointerTo<T> &copy);
   INLINE WeakPointerTo(const WeakPointerTo<T> &copy);
 
 
 public:
 public:
+  INLINE WeakPointerTo(WeakPointerTo<T> &&from) noexcept;
+
+  template<class Y>
+  ALWAYS_INLINE WeakPointerTo(const WeakPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakPointerTo(const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakPointerTo(WeakPointerTo<Y> &&r) noexcept;
+
   INLINE To &operator *() const;
   INLINE To &operator *() const;
   INLINE To *operator -> () const;
   INLINE To *operator -> () const;
   // MSVC.NET 2005 insists that we use T *, and not To *, here.
   // MSVC.NET 2005 insists that we use T *, and not To *, here.
@@ -49,6 +59,17 @@ PUBLISHED:
   INLINE WeakPointerTo<T> &operator = (const PointerTo<T> &copy);
   INLINE WeakPointerTo<T> &operator = (const PointerTo<T> &copy);
   INLINE WeakPointerTo<T> &operator = (const WeakPointerTo<T> &copy);
   INLINE WeakPointerTo<T> &operator = (const WeakPointerTo<T> &copy);
 
 
+public:
+  INLINE WeakPointerTo<T> &operator = (WeakPointerTo<T> &&from) noexcept;
+
+  template<class Y>
+  ALWAYS_INLINE WeakPointerTo<T> &operator = (const WeakPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakPointerTo<T> &operator = (const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakPointerTo<T> &operator = (WeakPointerTo<Y> &&r) noexcept;
+
+PUBLISHED:
   // This function normally wouldn't need to be redefined here, but we do so
   // This function normally wouldn't need to be redefined here, but we do so
   // anyway just to help out interrogate (which doesn't seem to want to
   // anyway just to help out interrogate (which doesn't seem to want to
   // automatically export the WeakPointerToBase class).  When this works again
   // automatically export the WeakPointerToBase class).  When this works again
@@ -66,13 +87,30 @@ class WeakConstPointerTo : public WeakPointerToBase<T> {
 public:
 public:
   typedef typename WeakPointerToBase<T>::To To;
   typedef typename WeakPointerToBase<T>::To To;
 PUBLISHED:
 PUBLISHED:
-  INLINE WeakConstPointerTo(const To *ptr = nullptr);
+  constexpr WeakConstPointerTo() noexcept = default;
+  INLINE WeakConstPointerTo(const To *ptr);
   INLINE WeakConstPointerTo(const PointerTo<T> &copy);
   INLINE WeakConstPointerTo(const PointerTo<T> &copy);
   INLINE WeakConstPointerTo(const ConstPointerTo<T> &copy);
   INLINE WeakConstPointerTo(const ConstPointerTo<T> &copy);
   INLINE WeakConstPointerTo(const WeakPointerTo<T> &copy);
   INLINE WeakConstPointerTo(const WeakPointerTo<T> &copy);
   INLINE WeakConstPointerTo(const WeakConstPointerTo<T> &copy);
   INLINE WeakConstPointerTo(const WeakConstPointerTo<T> &copy);
 
 
 public:
 public:
+  INLINE WeakConstPointerTo(WeakPointerTo<T> &&from) noexcept;
+  INLINE WeakConstPointerTo(WeakConstPointerTo<T> &&from) noexcept;
+
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo(const WeakPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo(const WeakConstPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo(const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo(const ConstPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo(WeakPointerTo<Y> &&r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo(WeakConstPointerTo<Y> &&r) noexcept;
+
   INLINE const To &operator *() const;
   INLINE const To &operator *() const;
   INLINE const To *operator -> () const;
   INLINE const To *operator -> () const;
   INLINE explicit operator const T *() const;
   INLINE explicit operator const T *() const;
@@ -88,6 +126,24 @@ PUBLISHED:
   INLINE WeakConstPointerTo<T> &operator = (const WeakPointerTo<T> &copy);
   INLINE WeakConstPointerTo<T> &operator = (const WeakPointerTo<T> &copy);
   INLINE WeakConstPointerTo<T> &operator = (const WeakConstPointerTo<T> &copy);
   INLINE WeakConstPointerTo<T> &operator = (const WeakConstPointerTo<T> &copy);
 
 
+public:
+  INLINE WeakConstPointerTo<T> &operator = (WeakPointerTo<T> &&from) noexcept;
+  INLINE WeakConstPointerTo<T> &operator = (WeakConstPointerTo<T> &&from) noexcept;
+
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo<T> &operator = (const WeakPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo<T> &operator = (const WeakConstPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo<T> &operator = (const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo<T> &operator = (const ConstPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo<T> &operator = (WeakPointerTo<Y> &&r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE WeakConstPointerTo<T> &operator = (WeakConstPointerTo<Y> &&r) noexcept;
+
+PUBLISHED:
   // These functions normally wouldn't need to be redefined here, but we do so
   // These functions normally wouldn't need to be redefined here, but we do so
   // anyway just to help out interrogate (which doesn't seem to want to
   // anyway just to help out interrogate (which doesn't seem to want to
   // automatically export the WeakPointerToBase class).  When this works again
   // automatically export the WeakPointerToBase class).  When this works again
@@ -96,6 +152,25 @@ PUBLISHED:
   INLINE void clear() { WeakPointerToBase<T>::clear(); }
   INLINE void clear() { WeakPointerToBase<T>::clear(); }
 };
 };
 
 
+// Provide specializations of std::owner_less, for using a WPT as a map key.
+namespace std {
+  template<class T>
+  struct owner_less<WeakPointerTo<T> > {
+    bool operator () (const WeakPointerTo<T> &lhs,
+                      const WeakPointerTo<T> &rhs) const noexcept {
+      return lhs.owner_before(rhs);
+    }
+  };
+
+  template<class T>
+  struct owner_less<WeakConstPointerTo<T> > {
+    bool operator () (const WeakConstPointerTo<T> &lhs,
+                      const WeakConstPointerTo<T> &rhs) const noexcept {
+      return lhs.owner_before(rhs);
+    }
+  };
+}
+
 #define WPT(type) WeakPointerTo< type >
 #define WPT(type) WeakPointerTo< type >
 #define WCPT(type) WeakConstPointerTo< type >
 #define WCPT(type) WeakConstPointerTo< type >
 
 

+ 191 - 33
panda/src/express/weakPointerToBase.I

@@ -12,7 +12,8 @@
  */
  */
 
 
 /**
 /**
- *
+ * Constructs a weak pointer from a plain pointer (or nullptr).  It is the
+ * caller's responsibility to ensure that it points to a valid object.
  */
  */
 template<class T>
 template<class T>
 INLINE WeakPointerToBase<T>::
 INLINE WeakPointerToBase<T>::
@@ -27,7 +28,7 @@ WeakPointerToBase(To *ptr) {
 }
 }
 
 
 /**
 /**
- *
+ * Constructs a weak pointer from a reference-counting pointer.
  */
  */
 template<class T>
 template<class T>
 INLINE WeakPointerToBase<T>::
 INLINE WeakPointerToBase<T>::
@@ -42,44 +43,72 @@ WeakPointerToBase(const PointerToBase<T> &copy) {
 }
 }
 
 
 /**
 /**
- *
+ * Copies a weak pointer.  This is always safe, even for expired pointers.
  */
  */
 template<class T>
 template<class T>
 INLINE WeakPointerToBase<T>::
 INLINE WeakPointerToBase<T>::
 WeakPointerToBase(const WeakPointerToBase<T> &copy) {
 WeakPointerToBase(const WeakPointerToBase<T> &copy) {
   _void_ptr = copy._void_ptr;
   _void_ptr = copy._void_ptr;
 
 
-  // Don't bother increasing the weak reference count if the object was
-  // already deleted.
+  // While it is tempting to stop maintaining the control block pointer after
+  // the object has been deleted, we still need it in order to define a
+  // consistent ordering in owner_before.
   WeakReferenceList *weak_ref = copy._weak_ref;
   WeakReferenceList *weak_ref = copy._weak_ref;
-  if (weak_ref != nullptr && !weak_ref->was_deleted()) {
+  if (weak_ref != nullptr/* && !weak_ref->was_deleted()*/) {
     _weak_ref = copy._weak_ref;
     _weak_ref = copy._weak_ref;
     _weak_ref->ref();
     _weak_ref->ref();
   }
   }
 }
 }
 
 
 /**
 /**
- *
+ * Moves a weak pointer.  This is always safe, even for expired pointers.
  */
  */
 template<class T>
 template<class T>
 INLINE WeakPointerToBase<T>::
 INLINE WeakPointerToBase<T>::
 WeakPointerToBase(WeakPointerToBase<T> &&from) noexcept {
 WeakPointerToBase(WeakPointerToBase<T> &&from) noexcept {
-  // Protect against self-move-assignment.
-  if (from._void_ptr != this->_void_ptr) {
-    WeakReferenceList *old_ref = (To *)this->_weak_ref;
+  this->_void_ptr = from._void_ptr;
+  this->_weak_ref = from._weak_ref;
+  from._void_ptr = nullptr;
+  from._weak_ref = nullptr;
+}
 
 
-    this->_void_ptr = from._void_ptr;
-    this->_weak_ref = from._weak_ref;
-    from._void_ptr = nullptr;
-    from._weak_ref = nullptr;
+/**
+ * Copies a weak pointer from a cast-convertible weak pointer type.
+ */
+template<class T>
+template<class Y>
+INLINE WeakPointerToBase<T>::
+WeakPointerToBase(const WeakPointerToBase<Y> &r) {
+  // If this next line gives an error, you are trying to convert a WeakPointerTo
+  // from an incompatible type of another WeakPointerTo.
+  To *ptr = (Y *)r._void_ptr;
 
 
-    // Now delete the old pointer.
-    if (old_ref != nullptr && !old_ref->unref()) {
-      delete old_ref;
-    }
+  this->_void_ptr = ptr;
+
+  WeakReferenceList *weak_ref = r._weak_ref;
+  if (weak_ref != nullptr) {
+    _weak_ref = weak_ref;
+    weak_ref->ref();
   }
   }
 }
 }
 
 
+/**
+ * Moves a weak pointer from a cast-convertible weak pointer type.
+ */
+template<class T>
+template<class Y>
+INLINE WeakPointerToBase<T>::
+WeakPointerToBase(WeakPointerToBase<Y> &&r) noexcept {
+  // If this next line gives an error, you are trying to convert a WeakPointerTo
+  // from an incompatible type of another WeakPointerTo.
+  To *ptr = (Y *)r._void_ptr;
+
+  this->_void_ptr = ptr;
+  this->_weak_ref = r._weak_ref;
+  r._void_ptr = nullptr;
+  r._weak_ref = nullptr;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -141,10 +170,11 @@ reassign(const WeakPointerToBase<To> &copy) {
     WeakReferenceList *old_ref = (WeakReferenceList *)_weak_ref;
     WeakReferenceList *old_ref = (WeakReferenceList *)_weak_ref;
     _void_ptr = new_ptr;
     _void_ptr = new_ptr;
 
 
-    // Don't bother increasing the weak reference count if the object was
-    // already deleted.
+    // While it is tempting to stop maintaining the control block pointer
+    // after the object has been deleted, we still need it in order to define
+    // a consistent ordering in owner_before.
     WeakReferenceList *weak_ref = copy._weak_ref;
     WeakReferenceList *weak_ref = copy._weak_ref;
-    if (weak_ref != nullptr && !weak_ref->was_deleted()) {
+    if (weak_ref != nullptr/* && !weak_ref->was_deleted()*/) {
       weak_ref->ref();
       weak_ref->ref();
       _weak_ref = weak_ref;
       _weak_ref = weak_ref;
     } else {
     } else {
@@ -180,6 +210,61 @@ reassign(WeakPointerToBase<To> &&from) noexcept {
   }
   }
 }
 }
 
 
+/**
+ * Like above, but casts from a compatible pointer type.
+ */
+template<class T>
+template<class Y>
+INLINE void WeakPointerToBase<T>::
+reassign(const WeakPointerToBase<Y> &copy) {
+  // If there is a compile error on this line, it means you tried to assign
+  // an incompatible type.
+  To *new_ptr = (Y *)copy._void_ptr;
+
+  if (new_ptr != (To *)_void_ptr) {
+    WeakReferenceList *old_ref = (WeakReferenceList *)_weak_ref;
+    WeakReferenceList *new_ref = copy._weak_ref;
+    _void_ptr = new_ptr;
+    _weak_ref = new_ref;
+
+    if (new_ref != nullptr) {
+      new_ref->ref();
+    }
+
+    // Now remove the old reference.
+    if (old_ref != nullptr && !old_ref->unref()) {
+      delete old_ref;
+    }
+  }
+}
+
+/**
+ * Like above, but casts from a compatible pointer type.
+ */
+template<class T>
+template<class Y>
+INLINE void WeakPointerToBase<T>::
+reassign(WeakPointerToBase<Y> &&from) noexcept {
+  // Protect against self-move-assignment.
+  if (from._void_ptr != this->_void_ptr) {
+    WeakReferenceList *old_ref = (WeakReferenceList *)this->_weak_ref;
+
+    // If there is a compile error on this line, it means you tried to assign
+    // an incompatible type.
+    To *new_ptr = (Y *)from._void_ptr;
+
+    this->_void_ptr = new_ptr;
+    this->_weak_ref = from._weak_ref;
+    from._void_ptr = nullptr;
+    from._weak_ref = nullptr;
+
+    // Now delete the old pointer.
+    if (old_ref != nullptr && !old_ref->unref()) {
+      delete old_ref;
+    }
+  }
+}
+
 /**
 /**
  * Ensures that the MemoryUsage record for the pointer has the right type of
  * Ensures that the MemoryUsage record for the pointer has the right type of
  * object, if we know the type ourselves.
  * object, if we know the type ourselves.
@@ -201,6 +286,34 @@ update_type(To *ptr) {
 #endif  // DO_MEMORY_USAGE
 #endif  // DO_MEMORY_USAGE
 }
 }
 
 
+/**
+ * A thread-safe way to access the underlying pointer; will only write to the
+ * given pointer if the underlying pointer has not yet been deleted and is not
+ * null.  Note that it may leave the pointer unassigned even if was_deleted()
+ * still returns true, which can occur if the object has reached reference
+ * count 0 and is about to be destroyed.
+ */
+template<class T>
+INLINE void WeakPointerToBase<T>::
+lock_into(PointerToBase<To> &locked) const {
+  WeakReferenceList *weak_ref = this->_weak_ref;
+  if (weak_ref != nullptr) {
+    weak_ref->_lock.lock();
+    if (!weak_ref->was_deleted()) {
+      // We also need to check that the reference count is not zero (which can
+      // happen if the object is currently being destructed), since that could
+      // cause double deletion.
+      To *plain_ptr = (To *)WeakPointerToBase<T>::_void_ptr;
+      if (plain_ptr != nullptr && plain_ptr->ref_if_nonzero()) {
+        // It is valid and we successfully grabbed a reference.  Assign it,
+        // noting we have already incremented the reference count.
+        locked._void_ptr = plain_ptr;
+      }
+    }
+    weak_ref->_lock.unlock();
+  }
+}
+
 #ifndef CPPPARSER
 #ifndef CPPPARSER
 /**
 /**
  *
  *
@@ -337,7 +450,11 @@ operator >= (std::nullptr_t) const {
 }
 }
 
 
 /**
 /**
- *
+ * Returns true if both pointers have the same raw pointer value.  For this to
+ * be meaningful, neither pointer may have expired, since if one has expired
+ * while the other was allocated at the expired pointer's memory address, this
+ * comparison will be true even though they didn't refer to the same object.
+ * @see owner_before
  */
  */
 template<class T>
 template<class T>
 INLINE bool WeakPointerToBase<T>::
 INLINE bool WeakPointerToBase<T>::
@@ -346,7 +463,7 @@ operator == (const WeakPointerToBase<To> &other) const {
 }
 }
 
 
 /**
 /**
- *
+ * @see operator ==
  */
  */
 template<class T>
 template<class T>
 INLINE bool WeakPointerToBase<T>::
 INLINE bool WeakPointerToBase<T>::
@@ -355,7 +472,8 @@ operator != (const WeakPointerToBase<To> &other) const {
 }
 }
 
 
 /**
 /**
- *
+ * Defines an ordering between WeakPointerTo based on their raw pointer value.
+ * @deprecated Do not use this.  Use owner_before or std::owner_less instead.
  */
  */
 template<class T>
 template<class T>
 INLINE bool WeakPointerToBase<T>::
 INLINE bool WeakPointerToBase<T>::
@@ -364,7 +482,8 @@ operator > (const WeakPointerToBase<To> &other) const {
 }
 }
 
 
 /**
 /**
- *
+ * Defines an ordering between WeakPointerTo based on their raw pointer value.
+ * @deprecated Do not use this.  Use owner_before or std::owner_less instead.
  */
  */
 template<class T>
 template<class T>
 INLINE bool WeakPointerToBase<T>::
 INLINE bool WeakPointerToBase<T>::
@@ -373,7 +492,8 @@ operator <= (const WeakPointerToBase<To> &other) const {
 }
 }
 
 
 /**
 /**
- *
+ * Defines an ordering between WeakPointerTo based on their raw pointer value.
+ * @deprecated Do not use this.  Use owner_before or std::owner_less instead.
  */
  */
 template<class T>
 template<class T>
 INLINE bool WeakPointerToBase<T>::
 INLINE bool WeakPointerToBase<T>::
@@ -382,7 +502,7 @@ operator >= (const WeakPointerToBase<To> &other) const {
 }
 }
 
 
 /**
 /**
- *
+ * Returns true if both pointers point to the same object.
  */
  */
 template<class T>
 template<class T>
 INLINE bool WeakPointerToBase<T>::
 INLINE bool WeakPointerToBase<T>::
@@ -391,7 +511,7 @@ operator == (const PointerToBase<To> &other) const {
 }
 }
 
 
 /**
 /**
- *
+ * Returns false if both pointers point to the same object.
  */
  */
 template<class T>
 template<class T>
 INLINE bool WeakPointerToBase<T>::
 INLINE bool WeakPointerToBase<T>::
@@ -445,7 +565,8 @@ operator < (std::nullptr_t) const {
 }
 }
 
 
 /**
 /**
- *
+ * Defines an ordering between WeakPointerTo based on their raw pointer value.
+ * @deprecated Do not use this.  Use owner_before or std::owner_less instead.
  */
  */
 template<class T>
 template<class T>
 INLINE bool WeakPointerToBase<T>::
 INLINE bool WeakPointerToBase<T>::
@@ -464,6 +585,35 @@ operator < (const PointerToBase<To> &other) const {
 
 
 #endif  // CPPPARSER
 #endif  // CPPPARSER
 
 
+/**
+ * Defines an ordering that is guaranteed to remain consistent even after the
+ * weak pointers have expired.  This may result in two pointers with the same
+ * get_orig() value comparing unequal if one of them is a new object that was
+ * allocated at the same memory address as the older, expired pointer.
+ */
+template<class T>
+template<class Y>
+INLINE bool WeakPointerToBase<T>::
+owner_before(const WeakPointerToBase<Y> &other) const noexcept {
+  return _weak_ref < other._weak_ref;
+}
+
+/**
+ * Defines an ordering that is guaranteed to remain consistent even after this
+ * weak pointer has expired.  This may result in two pointers with the same
+ * get_orig() value comparing unequal if one of them is a new object that was
+ * allocated at the same memory address as the older, expired pointer.
+ */
+template<class T>
+template<class Y>
+INLINE bool WeakPointerToBase<T>::
+owner_before(const PointerToBase<Y> &other) const noexcept {
+  // Unfortunately, this may needlessly cause a control block to be allocated,
+  // but I do not see a more efficient solution.
+  return (other._void_ptr != nullptr) &&
+    (_void_ptr == nullptr || _weak_ref < ((const Y *)other._void_ptr)->get_weak_list());
+}
+
 /**
 /**
  * A convenient way to set the PointerTo object to NULL. (Assignment to a NULL
  * A convenient way to set the PointerTo object to NULL. (Assignment to a NULL
  * pointer also works, of course.)
  * pointer also works, of course.)
@@ -505,9 +655,17 @@ template<class T>
 INLINE void WeakPointerToBase<T>::
 INLINE void WeakPointerToBase<T>::
 output(std::ostream &out) const {
 output(std::ostream &out) const {
   out << _void_ptr;
   out << _void_ptr;
-  if (was_deleted()) {
-    out << ":deleted";
-  } else if (_void_ptr != nullptr) {
-    out << ":" << ((To *)_void_ptr)->get_ref_count();
+
+  WeakReferenceList *weak_ref = this->_weak_ref;
+  if (weak_ref != nullptr) {
+    weak_ref->_lock.lock();
+    if (!weak_ref->was_deleted()) {
+      out << ":" << ((To *)_void_ptr)->get_ref_count();
+    } else {
+      out << ":deleted";
+    }
+    weak_ref->_lock.unlock();
+  } else {
+    out << ":invalid";
   }
   }
 }
 }

+ 21 - 1
panda/src/express/weakPointerToBase.h

@@ -28,19 +28,31 @@ public:
   typedef T To;
   typedef T To;
 
 
 protected:
 protected:
-  INLINE WeakPointerToBase(To *ptr);
+  constexpr WeakPointerToBase() noexcept = default;
+  INLINE explicit WeakPointerToBase(To *ptr);
   INLINE WeakPointerToBase(const PointerToBase<T> &copy);
   INLINE WeakPointerToBase(const PointerToBase<T> &copy);
   INLINE WeakPointerToBase(const WeakPointerToBase<T> &copy);
   INLINE WeakPointerToBase(const WeakPointerToBase<T> &copy);
   INLINE WeakPointerToBase(WeakPointerToBase<T> &&from) noexcept;
   INLINE WeakPointerToBase(WeakPointerToBase<T> &&from) noexcept;
+  template<class Y>
+  INLINE WeakPointerToBase(const WeakPointerToBase<Y> &r);
+  template<class Y>
+  INLINE WeakPointerToBase(WeakPointerToBase<Y> &&r) noexcept;
+
   INLINE ~WeakPointerToBase();
   INLINE ~WeakPointerToBase();
 
 
   void reassign(To *ptr);
   void reassign(To *ptr);
   INLINE void reassign(const PointerToBase<To> &copy);
   INLINE void reassign(const PointerToBase<To> &copy);
   INLINE void reassign(const WeakPointerToBase<To> &copy);
   INLINE void reassign(const WeakPointerToBase<To> &copy);
   INLINE void reassign(WeakPointerToBase<To> &&from) noexcept;
   INLINE void reassign(WeakPointerToBase<To> &&from) noexcept;
+  template<class Y>
+  INLINE void reassign(const WeakPointerToBase<Y> &copy);
+  template<class Y>
+  INLINE void reassign(WeakPointerToBase<Y> &&from) noexcept;
 
 
   INLINE void update_type(To *ptr);
   INLINE void update_type(To *ptr);
 
 
+  INLINE void lock_into(PointerToBase<To> &locked) const;
+
   // No assignment or retrieval functions are declared in WeakPointerToBase,
   // No assignment or retrieval functions are declared in WeakPointerToBase,
   // because we will have to specialize on const vs.  non-const later.
   // because we will have to specialize on const vs.  non-const later.
 
 
@@ -83,6 +95,14 @@ public:
   INLINE bool operator < (const PointerToBase<To> &other) const;
   INLINE bool operator < (const PointerToBase<To> &other) const;
 #endif  // CPPPARSER
 #endif  // CPPPARSER
 
 
+  template<class Y>
+  INLINE bool owner_before(const WeakPointerToBase<Y> &other) const noexcept;
+  template<class Y>
+  INLINE bool owner_before(const PointerToBase<Y> &other) const noexcept;
+
+  // This is needed to be able to access the privates of other instantiations.
+  template<typename Y> friend class WeakPointerToBase;
+
 PUBLISHED:
 PUBLISHED:
   INLINE void clear();
   INLINE void clear();
   INLINE void refresh() const;
   INLINE void refresh() const;

+ 6 - 9
panda/src/express/weakPointerToVoid.I

@@ -11,13 +11,6 @@
  * @date 2004-09-27
  * @date 2004-09-27
  */
  */
 
 
-/**
- *
- */
-INLINE WeakPointerToVoid::
-WeakPointerToVoid() : _weak_ref(nullptr) {
-}
-
 /**
 /**
  * Sets a callback that will be made when the pointer is deleted.  Does
  * Sets a callback that will be made when the pointer is deleted.  Does
  * nothing if this is a null pointer.
  * nothing if this is a null pointer.
@@ -47,7 +40,11 @@ remove_callback(WeakPointerCallback *callback) const {
 
 
 /**
 /**
  * Returns true if the object we are pointing to has been deleted, false
  * Returns true if the object we are pointing to has been deleted, false
- * otherwise.
+ * otherwise.  If this returns true, it means that the pointer can not yet be
+ * reused, but it does not guarantee that it can be safely accessed.  See the
+ * lock() method for a safe way to access the underlying pointer.
+ *
+ * This will always return true for a null pointer, unlike is_valid_pointer().
  */
  */
 INLINE bool WeakPointerToVoid::
 INLINE bool WeakPointerToVoid::
 was_deleted() const {
 was_deleted() const {
@@ -56,7 +53,7 @@ was_deleted() const {
 
 
 /**
 /**
  * Returns true if the pointer is not null and the object has not been
  * Returns true if the pointer is not null and the object has not been
- * deleted.
+ * deleted.  See was_deleted() for caveats.
  */
  */
 INLINE bool WeakPointerToVoid::
 INLINE bool WeakPointerToVoid::
 is_valid_pointer() const {
 is_valid_pointer() const {

+ 2 - 2
panda/src/express/weakPointerToVoid.h

@@ -25,7 +25,7 @@
  */
  */
 class EXPCL_PANDA_EXPRESS WeakPointerToVoid : public PointerToVoid {
 class EXPCL_PANDA_EXPRESS WeakPointerToVoid : public PointerToVoid {
 protected:
 protected:
-  INLINE WeakPointerToVoid();
+  constexpr WeakPointerToVoid() noexcept = default;
 
 
 public:
 public:
   INLINE void add_callback(WeakPointerCallback *callback) const;
   INLINE void add_callback(WeakPointerCallback *callback) const;
@@ -36,7 +36,7 @@ PUBLISHED:
   INLINE bool is_valid_pointer() const;
   INLINE bool is_valid_pointer() const;
 
 
 protected:
 protected:
-  mutable WeakReferenceList *_weak_ref;
+  mutable WeakReferenceList *_weak_ref = nullptr;
 };
 };
 
 
 #include "weakPointerToVoid.I"
 #include "weakPointerToVoid.I"

+ 9 - 1
panda/src/framework/pandaFramework.cxx

@@ -82,7 +82,7 @@ PandaFramework::
  * control parameters.
  * control parameters.
  */
  */
 void PandaFramework::
 void PandaFramework::
-open_framework(int &argc, char **&argv) {
+open_framework() {
   if (_is_open) {
   if (_is_open) {
     return;
     return;
   }
   }
@@ -162,6 +162,14 @@ open_framework(int &argc, char **&argv) {
   _event_handler.add_hook("window-event", event_window_event, this);
   _event_handler.add_hook("window-event", event_window_event, this);
 }
 }
 
 
+/**
+ * @deprecated See the version of open_framework() without arguments.
+ */
+void PandaFramework::
+open_framework(int &argc, char **&argv) {
+  open_framework();
+}
+
 /**
 /**
  * Should be called at the end of an application to close Panda.  This is
  * Should be called at the end of an application to close Panda.  This is
  * optional, as the destructor will do the same thing.
  * optional, as the destructor will do the same thing.

+ 1 - 0
panda/src/framework/pandaFramework.h

@@ -40,6 +40,7 @@ public:
   PandaFramework();
   PandaFramework();
   virtual ~PandaFramework();
   virtual ~PandaFramework();
 
 
+  void open_framework();
   void open_framework(int &argc, char **&argv);
   void open_framework(int &argc, char **&argv);
   void close_framework();
   void close_framework();
 
 

+ 15 - 8
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -648,6 +648,7 @@ issue_parameters(int altered) {
         continue;
         continue;
 
 
       case Shader::SPT_int:
       case Shader::SPT_int:
+      case Shader::SPT_uint:
         switch (spec._info._class) {
         switch (spec._info._class) {
         case Shader::SAC_scalar:
         case Shader::SAC_scalar:
           cgSetParameter1iv(p, (int*)ptr_data->_ptr);
           cgSetParameter1iv(p, (int*)ptr_data->_ptr);
@@ -884,17 +885,21 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
 
 
           _glgsg->enable_vertex_attrib_array(p);
           _glgsg->enable_vertex_attrib_array(p);
 
 
-          if (bind._integer) {
-            _glgsg->_glVertexAttribIPointer(p, num_values, type,
-                                            stride, client_pointer);
-          } else if (numeric_type == GeomEnums::NT_packed_dabc) {
+          if (numeric_type == GeomEnums::NT_packed_dabc) {
             // GL_BGRA is a special accepted value available since OpenGL 3.2.
             // GL_BGRA is a special accepted value available since OpenGL 3.2.
             // It requires us to pass GL_TRUE for normalized.
             // It requires us to pass GL_TRUE for normalized.
             _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
             _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
                                            GL_TRUE, stride, client_pointer);
                                            GL_TRUE, stride, client_pointer);
-          } else {
+          } else if (bind._numeric_type == Shader::SPT_float ||
+                     numeric_type == GeomEnums::NT_float32) {
             _glgsg->_glVertexAttribPointer(p, num_values, type,
             _glgsg->_glVertexAttribPointer(p, num_values, type,
                                            normalized, stride, client_pointer);
                                            normalized, stride, client_pointer);
+          } else if (bind._numeric_type == Shader::SPT_double) {
+            _glgsg->_glVertexAttribLPointer(p, num_values, type,
+                                            stride, client_pointer);
+          } else {
+            _glgsg->_glVertexAttribIPointer(p, num_values, type,
+                                            stride, client_pointer);
           }
           }
 
 
           if (divisor > 0) {
           if (divisor > 0) {
@@ -951,10 +956,12 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
           // So, we work around this by just binding something silly to 0.
           // So, we work around this by just binding something silly to 0.
           // This breaks flat colors, but it's better than invisible objects?
           // This breaks flat colors, but it's better than invisible objects?
           _glgsg->enable_vertex_attrib_array(0);
           _glgsg->enable_vertex_attrib_array(0);
-          if (bind._integer) {
-            _glgsg->_glVertexAttribIPointer(0, 4, GL_INT, 0, 0);
-          } else {
+          if (bind._numeric_type == Shader::SPT_float) {
             _glgsg->_glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
             _glgsg->_glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
+          } else if (bind._numeric_type == Shader::SPT_double) {
+            _glgsg->_glVertexAttribLPointer(0, 4, GL_DOUBLE, 0, 0);
+          } else {
+            _glgsg->_glVertexAttribIPointer(0, 4, GL_INT, 0, 0);
           }
           }
 
 
         } else if (p >= 0) {
         } else if (p >= 0) {

+ 20 - 8
panda/src/glstuff/glGeomMunger_src.cxx

@@ -426,11 +426,17 @@ premunge_format_impl(const GeomVertexFormat *orig) {
 int CLP(GeomMunger)::
 int CLP(GeomMunger)::
 compare_to_impl(const GeomMunger *other) const {
 compare_to_impl(const GeomMunger *other) const {
   const CLP(GeomMunger) *om = (CLP(GeomMunger) *)other;
   const CLP(GeomMunger) *om = (CLP(GeomMunger) *)other;
-  if (_texture != om->_texture) {
-    return _texture < om->_texture ? -1 : 1;
+  if (_texture.owner_before(om->_texture)) {
+    return -1;
   }
   }
-  if (_tex_gen != om->_tex_gen) {
-    return _tex_gen < om->_tex_gen ? -1 : 1;
+  if (om->_texture.owner_before(_texture)) {
+    return 1;
+  }
+  if (_tex_gen.owner_before(om->_tex_gen)) {
+    return -1;
+  }
+  if (om->_tex_gen.owner_before(_tex_gen)) {
+    return 1;
   }
   }
   if (_flags != om->_flags) {
   if (_flags != om->_flags) {
     return _flags < om->_flags ? -1 : 1;
     return _flags < om->_flags ? -1 : 1;
@@ -447,11 +453,17 @@ compare_to_impl(const GeomMunger *other) const {
 int CLP(GeomMunger)::
 int CLP(GeomMunger)::
 geom_compare_to_impl(const GeomMunger *other) const {
 geom_compare_to_impl(const GeomMunger *other) const {
   const CLP(GeomMunger) *om = (CLP(GeomMunger) *)other;
   const CLP(GeomMunger) *om = (CLP(GeomMunger) *)other;
-  if (_texture != om->_texture) {
-    return _texture < om->_texture ? -1 : 1;
+  if (_texture.owner_before(om->_texture)) {
+    return -1;
+  }
+  if (om->_texture.owner_before(_texture)) {
+    return 1;
+  }
+  if (_tex_gen.owner_before(om->_tex_gen)) {
+    return -1;
   }
   }
-  if (_tex_gen != om->_tex_gen) {
-    return _tex_gen < om->_tex_gen ? -1 : 1;
+  if (om->_tex_gen.owner_before(_tex_gen)) {
+    return 1;
   }
   }
   if (_flags != om->_flags) {
   if (_flags != om->_flags) {
     return _flags < om->_flags ? -1 : 1;
     return _flags < om->_flags ? -1 : 1;

+ 87 - 15
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -92,10 +92,6 @@ PStatCollector CLP(GraphicsStateGuardian)::_texture_update_pcollector("Draw:Upda
 PStatCollector CLP(GraphicsStateGuardian)::_fbo_bind_pcollector("Draw:Bind FBO");
 PStatCollector CLP(GraphicsStateGuardian)::_fbo_bind_pcollector("Draw:Bind FBO");
 PStatCollector CLP(GraphicsStateGuardian)::_check_error_pcollector("Draw:Check errors");
 PStatCollector CLP(GraphicsStateGuardian)::_check_error_pcollector("Draw:Check errors");
 
 
-#ifndef OPENGLES_1
-PT(Shader) CLP(GraphicsStateGuardian)::_default_shader = nullptr;
-#endif
-
 // The following noop functions are assigned to the corresponding glext
 // The following noop functions are assigned to the corresponding glext
 // function pointers in the class, in case the functions are not defined by
 // function pointers in the class, in case the functions are not defined by
 // the GL, just so it will always be safe to call the extension functions.
 // the GL, just so it will always be safe to call the extension functions.
@@ -188,6 +184,48 @@ static const string default_vshader =
   "  color = p3d_Color * p3d_ColorScale;\n"
   "  color = p3d_Color * p3d_ColorScale;\n"
   "}\n";
   "}\n";
 
 
+#ifndef OPENGLES
+// This version of the shader is used if vertices-float64 is enabled.
+static const string default_vshader_fp64 =
+#ifdef __APPLE__
+  "#version 150\n"
+#else
+  "#version 130\n"
+#endif
+  "#extension GL_ARB_vertex_attrib_64bit : require\n"
+  "#extension GL_ARB_gpu_shader_fp64 : require\n"
+  "in dvec3 p3d_Vertex;\n"
+  "in vec4 p3d_Color;\n"
+  "in dvec2 p3d_MultiTexCoord0;\n"
+  "out vec2 texcoord;\n"
+  "out vec4 color;\n"
+  "uniform mat4 p3d_ModelViewMatrix;\n"
+  "uniform mat4 p3d_ProjectionMatrix;\n"
+  "uniform vec4 p3d_ColorScale;\n"
+  "void main(void) {\n" // Apply proj & modelview in two steps, more precise
+  "  gl_Position = vec4(dmat4(p3d_ProjectionMatrix) * (dmat4(p3d_ModelViewMatrix) * dvec4(p3d_Vertex, 1)));\n"
+  "  texcoord = vec2(p3d_MultiTexCoord0);\n"
+  "  color = p3d_Color * p3d_ColorScale;\n"
+  "}\n";
+
+// Same as above, but for OpenGL 4.1.
+static const string default_vshader_fp64_gl41 =
+  "#version 410\n"
+  "in dvec3 p3d_Vertex;\n"
+  "in vec4 p3d_Color;\n"
+  "in dvec2 p3d_MultiTexCoord0;\n"
+  "out vec2 texcoord;\n"
+  "out vec4 color;\n"
+  "uniform mat4 p3d_ModelViewMatrix;\n"
+  "uniform mat4 p3d_ProjectionMatrix;\n"
+  "uniform vec4 p3d_ColorScale;\n"
+  "void main(void) {\n" // Apply proj & modelview in two steps, more precise
+  "  gl_Position = vec4(dmat4(p3d_ProjectionMatrix) * (dmat4(p3d_ModelViewMatrix) * dvec4(p3d_Vertex, 1)));\n"
+  "  texcoord = vec2(p3d_MultiTexCoord0);\n"
+  "  color = p3d_Color * p3d_ColorScale;\n"
+  "}\n";
+#endif
+
 static const string default_fshader =
 static const string default_fshader =
 #ifndef OPENGLES
 #ifndef OPENGLES
 #ifdef __APPLE__  // Apple's GL 3.2 contexts require at least GLSL 1.50.
 #ifdef __APPLE__  // Apple's GL 3.2 contexts require at least GLSL 1.50.
@@ -1699,6 +1737,14 @@ reset() {
        get_extension_func("glUniform3iv");
        get_extension_func("glUniform3iv");
     _glUniform4iv = (PFNGLUNIFORM4IVPROC)
     _glUniform4iv = (PFNGLUNIFORM4IVPROC)
        get_extension_func("glUniform4iv");
        get_extension_func("glUniform4iv");
+    _glUniform1uiv = (PFNGLUNIFORM1UIVPROC)
+       get_extension_func("glUniform1uiv");
+    _glUniform2uiv = (PFNGLUNIFORM2UIVPROC)
+       get_extension_func("glUniform2uiv");
+    _glUniform3uiv = (PFNGLUNIFORM3UIVPROC)
+       get_extension_func("glUniform3uiv");
+    _glUniform4uiv = (PFNGLUNIFORM4UIVPROC)
+       get_extension_func("glUniform4uiv");
     _glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)
     _glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)
        get_extension_func("glUniformMatrix3fv");
        get_extension_func("glUniformMatrix3fv");
     _glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)
     _glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)
@@ -1777,6 +1823,10 @@ reset() {
   _glUniform2fv = glUniform2fv;
   _glUniform2fv = glUniform2fv;
   _glUniform3fv = glUniform3fv;
   _glUniform3fv = glUniform3fv;
   _glUniform4fv = glUniform4fv;
   _glUniform4fv = glUniform4fv;
+  _glUniform1iv = glUniform1iv;
+  _glUniform2iv = glUniform2iv;
+  _glUniform3iv = glUniform3iv;
+  _glUniform4iv = glUniform4iv;
   _glUniformMatrix3fv = glUniformMatrix3fv;
   _glUniformMatrix3fv = glUniformMatrix3fv;
   _glUniformMatrix4fv = glUniformMatrix4fv;
   _glUniformMatrix4fv = glUniformMatrix4fv;
   _glValidateProgram = glValidateProgram;
   _glValidateProgram = glValidateProgram;
@@ -1827,7 +1877,17 @@ reset() {
   // shader just outputs a red color, indicating that something went wrong.
   // shader just outputs a red color, indicating that something went wrong.
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
   if (_default_shader == nullptr && !has_fixed_function_pipeline()) {
   if (_default_shader == nullptr && !has_fixed_function_pipeline()) {
-    _default_shader = Shader::make(Shader::SL_GLSL, default_vshader, default_fshader);
+#ifndef OPENGLES
+    bool use_float64 = vertices_float64;
+    if (use_float64 && is_at_least_gl_version(4, 1)) {
+      _default_shader = Shader::make(Shader::SL_GLSL, default_vshader_fp64_gl41, default_fshader);
+    } else if (use_float64 && has_extension("GL_ARB_vertex_attrib_64bit")) {
+      _default_shader = Shader::make(Shader::SL_GLSL, default_vshader_fp64, default_fshader);
+    } else
+#endif
+    {
+      _default_shader = Shader::make(Shader::SL_GLSL, default_vshader, default_fshader);
+    }
   }
   }
 #endif
 #endif
 
 
@@ -2226,8 +2286,10 @@ reset() {
   if (is_at_least_gl_version(4, 5) || has_extension("GL_ARB_direct_state_access")) {
   if (is_at_least_gl_version(4, 5) || has_extension("GL_ARB_direct_state_access")) {
     _glGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC)
     _glGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC)
       get_extension_func("glGenerateTextureMipmap");
       get_extension_func("glGenerateTextureMipmap");
+
+    _supports_dsa = true;
   } else {
   } else {
-    _glGenerateTextureMipmap = nullptr;
+    _supports_dsa = false;
   }
   }
 #endif
 #endif
 
 
@@ -2770,7 +2832,9 @@ reset() {
   // Check availability of anisotropic texture filtering.
   // Check availability of anisotropic texture filtering.
   _supports_anisotropy = false;
   _supports_anisotropy = false;
   _max_anisotropy = 1.0;
   _max_anisotropy = 1.0;
-  if (has_extension("GL_EXT_texture_filter_anisotropic")) {
+  if (is_at_least_gl_version(4, 6) ||
+      has_extension("GL_EXT_texture_filter_anisotropic") ||
+      has_extension("GL_ARB_texture_filter_anisotropic")) {
     GLfloat max_anisotropy;
     GLfloat max_anisotropy;
     glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy);
     glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy);
     _max_anisotropy = (PN_stdfloat)max_anisotropy;
     _max_anisotropy = (PN_stdfloat)max_anisotropy;
@@ -3177,7 +3241,7 @@ reset() {
   if (GLCAT.is_debug()) {
   if (GLCAT.is_debug()) {
     if (_supports_get_program_binary) {
     if (_supports_get_program_binary) {
       GLCAT.debug()
       GLCAT.debug()
-        << "Supported shader binary formats:\n";
+        << "Supported program binary formats:\n";
       GLCAT.debug() << " ";
       GLCAT.debug() << " ";
 
 
       pset<GLenum>::const_iterator it;
       pset<GLenum>::const_iterator it;
@@ -3189,7 +3253,7 @@ reset() {
       }
       }
       GLCAT.debug(false) << "\n";
       GLCAT.debug(false) << "\n";
     } else {
     } else {
-      GLCAT.debug() << "No shader binary formats supported.\n";
+      GLCAT.debug() << "No program binary formats supported.\n";
     }
     }
   }
   }
 #endif
 #endif
@@ -6389,10 +6453,11 @@ prepare_shader_buffer(ShaderBuffer *data) {
 
 
     if (_use_object_labels) {
     if (_use_object_labels) {
       string name = data->get_name();
       string name = data->get_name();
-      _glObjectLabel(GL_SHADER_STORAGE_BUFFER, gbc->_index, name.size(), name.data());
+      _glObjectLabel(GL_BUFFER, gbc->_index, name.size(), name.data());
     }
     }
 
 
-    uint64_t num_bytes = data->get_data_size_bytes();
+    // Some drivers require the buffer to be padded to 16 byte boundary.
+    uint64_t num_bytes = (data->get_data_size_bytes() + 15u) & ~15u;
     if (_supports_buffer_storage) {
     if (_supports_buffer_storage) {
       _glBufferStorage(GL_SHADER_STORAGE_BUFFER, num_bytes, data->get_initial_data(), 0);
       _glBufferStorage(GL_SHADER_STORAGE_BUFFER, num_bytes, data->get_initial_data(), 0);
     } else {
     } else {
@@ -7572,7 +7637,6 @@ do_issue_material() {
   } else if (material->has_ambient()) {
   } else if (material->has_ambient()) {
     // The material specifies an ambient, but not a diffuse component.  The
     // The material specifies an ambient, but not a diffuse component.  The
     // diffuse component comes from the object's color.
     // diffuse component comes from the object's color.
-    call_glMaterialfv(face, GL_AMBIENT, material->get_ambient());
     if (has_material_force_color) {
     if (has_material_force_color) {
       glDisable(GL_COLOR_MATERIAL);
       glDisable(GL_COLOR_MATERIAL);
       call_glMaterialfv(face, GL_DIFFUSE, _material_force_color);
       call_glMaterialfv(face, GL_DIFFUSE, _material_force_color);
@@ -7582,11 +7646,11 @@ do_issue_material() {
 #endif  // OPENGLES
 #endif  // OPENGLES
       glEnable(GL_COLOR_MATERIAL);
       glEnable(GL_COLOR_MATERIAL);
     }
     }
+    call_glMaterialfv(face, GL_AMBIENT, material->get_ambient());
 
 
   } else if (material->has_diffuse()) {
   } else if (material->has_diffuse()) {
     // The material specifies a diffuse, but not an ambient component.  The
     // The material specifies a diffuse, but not an ambient component.  The
     // ambient component comes from the object's color.
     // ambient component comes from the object's color.
-    call_glMaterialfv(face, GL_DIFFUSE, material->get_diffuse());
     if (has_material_force_color) {
     if (has_material_force_color) {
       glDisable(GL_COLOR_MATERIAL);
       glDisable(GL_COLOR_MATERIAL);
       call_glMaterialfv(face, GL_AMBIENT, _material_force_color);
       call_glMaterialfv(face, GL_AMBIENT, _material_force_color);
@@ -7596,6 +7660,7 @@ do_issue_material() {
 #endif  // OPENGLES
 #endif  // OPENGLES
       glEnable(GL_COLOR_MATERIAL);
       glEnable(GL_COLOR_MATERIAL);
     }
     }
+    call_glMaterialfv(face, GL_DIFFUSE, material->get_diffuse());
 
 
   } else {
   } else {
     // The material specifies neither a diffuse nor an ambient component.
     // The material specifies neither a diffuse nor an ambient component.
@@ -13132,7 +13197,7 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 generate_mipmaps(CLP(TextureContext) *gtc) {
 generate_mipmaps(CLP(TextureContext) *gtc) {
 #ifndef OPENGLES
 #ifndef OPENGLES
-  if (_glGenerateTextureMipmap != nullptr) {
+  if (_supports_dsa) {
     // OpenGL 4.5 offers an easy way to do this without binding.
     // OpenGL 4.5 offers an easy way to do this without binding.
     _glGenerateTextureMipmap(gtc->_index);
     _glGenerateTextureMipmap(gtc->_index);
     return;
     return;
@@ -13442,7 +13507,14 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
 
 
   GLint internal_format = GL_RGBA;
   GLint internal_format = GL_RGBA;
 #ifndef OPENGLES
 #ifndef OPENGLES
-  glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
+  if (target != GL_TEXTURE_BUFFER) {
+    glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
+  } else {
+    // Some drivers give the wrong result for the above call.  No problem; we
+    // already know the internal format of a buffer texture since glTexBuffer
+    // required passing the exact sized format.
+    internal_format = gtc->_internal_format;
+  }
 #endif  // OPENGLES
 #endif  // OPENGLES
 
 
   // Make sure we were able to query those parameters properly.
   // Make sure we were able to query those parameters properly.

+ 10 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -175,6 +175,10 @@ typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, con
 typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
 typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
 typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
 typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
 typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
 typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value);
 typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
 typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
@@ -670,7 +674,7 @@ protected:
   PT(Shader) _texture_binding_shader;
   PT(Shader) _texture_binding_shader;
   ShaderContext *_texture_binding_shader_context;
   ShaderContext *_texture_binding_shader_context;
 
 
-  static PT(Shader) _default_shader;
+  PT(Shader) _default_shader;
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
   bool _shader_point_size;
   bool _shader_point_size;
@@ -905,6 +909,7 @@ public:
   PFNGLBINDPROGRAMARBPROC _glBindProgram;
   PFNGLBINDPROGRAMARBPROC _glBindProgram;
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
+  bool _supports_dsa;
   PFNGLGENERATETEXTUREMIPMAPPROC _glGenerateTextureMipmap;
   PFNGLGENERATETEXTUREMIPMAPPROC _glGenerateTextureMipmap;
 #endif
 #endif
 
 
@@ -984,6 +989,10 @@ public:
   PFNGLUNIFORM2IVPROC _glUniform2iv;
   PFNGLUNIFORM2IVPROC _glUniform2iv;
   PFNGLUNIFORM3IVPROC _glUniform3iv;
   PFNGLUNIFORM3IVPROC _glUniform3iv;
   PFNGLUNIFORM4IVPROC _glUniform4iv;
   PFNGLUNIFORM4IVPROC _glUniform4iv;
+  PFNGLUNIFORM1UIVPROC _glUniform1uiv;
+  PFNGLUNIFORM2UIVPROC _glUniform2uiv;
+  PFNGLUNIFORM3UIVPROC _glUniform3uiv;
+  PFNGLUNIFORM4UIVPROC _glUniform4uiv;
   PFNGLUNIFORMMATRIX3FVPROC _glUniformMatrix3fv;
   PFNGLUNIFORMMATRIX3FVPROC _glUniformMatrix3fv;
   PFNGLUNIFORMMATRIX4FVPROC _glUniformMatrix4fv;
   PFNGLUNIFORMMATRIX4FVPROC _glUniformMatrix4fv;
   PFNGLVALIDATEPROGRAMPROC _glValidateProgram;
   PFNGLVALIDATEPROGRAMPROC _glValidateProgram;

+ 99 - 22
panda/src/glstuff/glShaderContext_src.cxx

@@ -426,18 +426,34 @@ reflect_attribute(int i, char *name_buffer, GLsizei name_buflen) {
   bind._elements = 1;
   bind._elements = 1;
 
 
   // Check if this is an integer input- if so, we have to bind it differently.
   // Check if this is an integer input- if so, we have to bind it differently.
-  bind._integer = (param_type == GL_BOOL ||
-                   param_type == GL_BOOL_VEC2 ||
-                   param_type == GL_BOOL_VEC3 ||
-                   param_type == GL_BOOL_VEC4 ||
-                   param_type == GL_INT ||
-                   param_type == GL_INT_VEC2 ||
-                   param_type == GL_INT_VEC3 ||
-                   param_type == GL_INT_VEC4 ||
-                   param_type == GL_UNSIGNED_INT_VEC2 ||
-                   param_type == GL_UNSIGNED_INT_VEC3 ||
-                   param_type == GL_UNSIGNED_INT_VEC4 ||
-                   param_type == GL_UNSIGNED_INT);
+  switch (param_type) {
+  case GL_INT:
+  case GL_INT_VEC2:
+  case GL_INT_VEC3:
+  case GL_INT_VEC4:
+    bind._numeric_type = Shader::SPT_int;
+    break;
+  case GL_BOOL:
+  case GL_BOOL_VEC2:
+  case GL_BOOL_VEC3:
+  case GL_BOOL_VEC4:
+  case GL_UNSIGNED_INT:
+  case GL_UNSIGNED_INT_VEC2:
+  case GL_UNSIGNED_INT_VEC3:
+  case GL_UNSIGNED_INT_VEC4:
+    bind._numeric_type = Shader::SPT_uint;
+    break;
+#ifndef OPENGLES
+  case GL_DOUBLE:
+  case GL_DOUBLE_VEC2:
+  case GL_DOUBLE_VEC3:
+  case GL_DOUBLE_VEC4:
+    bind._numeric_type = Shader::SPT_double;
+    break;
+#endif
+  default:
+    bind._numeric_type = Shader::SPT_float;
+  }
 
 
   // Check if it has a p3d_ prefix - if so, assign special meaning.
   // Check if it has a p3d_ prefix - if so, assign special meaning.
   if (strncmp(name_buffer, "p3d_", 4) == 0) {
   if (strncmp(name_buffer, "p3d_", 4) == 0) {
@@ -1501,21 +1517,29 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_INT:
       case GL_INT:
       case GL_INT_VEC2:
       case GL_INT_VEC2:
       case GL_INT_VEC3:
       case GL_INT_VEC3:
-      case GL_INT_VEC4: {
+      case GL_INT_VEC4:
+      case GL_UNSIGNED_INT:
+      case GL_UNSIGNED_INT_VEC2:
+      case GL_UNSIGNED_INT_VEC3:
+      case GL_UNSIGNED_INT_VEC4: {
         Shader::ShaderPtrSpec bind;
         Shader::ShaderPtrSpec bind;
         bind._id = arg_id;
         bind._id = arg_id;
         switch (param_type) {
         switch (param_type) {
           case GL_BOOL:
           case GL_BOOL:
           case GL_INT:
           case GL_INT:
+          case GL_UNSIGNED_INT:
           case GL_FLOAT:      bind._dim[1] = 1; break;
           case GL_FLOAT:      bind._dim[1] = 1; break;
           case GL_BOOL_VEC2:
           case GL_BOOL_VEC2:
           case GL_INT_VEC2:
           case GL_INT_VEC2:
+          case GL_UNSIGNED_INT_VEC2:
           case GL_FLOAT_VEC2: bind._dim[1] = 2; break;
           case GL_FLOAT_VEC2: bind._dim[1] = 2; break;
           case GL_BOOL_VEC3:
           case GL_BOOL_VEC3:
           case GL_INT_VEC3:
           case GL_INT_VEC3:
+          case GL_UNSIGNED_INT_VEC3:
           case GL_FLOAT_VEC3: bind._dim[1] = 3; break;
           case GL_FLOAT_VEC3: bind._dim[1] = 3; break;
           case GL_BOOL_VEC4:
           case GL_BOOL_VEC4:
           case GL_INT_VEC4:
           case GL_INT_VEC4:
+          case GL_UNSIGNED_INT_VEC4:
           case GL_FLOAT_VEC4: bind._dim[1] = 4; break;
           case GL_FLOAT_VEC4: bind._dim[1] = 4; break;
           case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
           case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
           case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
           case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
@@ -1525,6 +1549,12 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         case GL_BOOL_VEC2:
         case GL_BOOL_VEC2:
         case GL_BOOL_VEC3:
         case GL_BOOL_VEC3:
         case GL_BOOL_VEC4:
         case GL_BOOL_VEC4:
+        case GL_UNSIGNED_INT:
+        case GL_UNSIGNED_INT_VEC2:
+        case GL_UNSIGNED_INT_VEC3:
+        case GL_UNSIGNED_INT_VEC4:
+          bind._type = Shader::SPT_uint;
+          break;
         case GL_INT:
         case GL_INT:
         case GL_INT_VEC2:
         case GL_INT_VEC2:
         case GL_INT_VEC3:
         case GL_INT_VEC3:
@@ -1604,6 +1634,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
     case GL_INT_VEC2:
     case GL_INT_VEC2:
     case GL_INT_VEC3:
     case GL_INT_VEC3:
     case GL_INT_VEC4:
     case GL_INT_VEC4:
+    case GL_UNSIGNED_INT:
+    case GL_UNSIGNED_INT_VEC2:
+    case GL_UNSIGNED_INT_VEC3:
+    case GL_UNSIGNED_INT_VEC4:
     case GL_FLOAT:
     case GL_FLOAT:
     case GL_FLOAT_VEC2:
     case GL_FLOAT_VEC2:
     case GL_FLOAT_VEC3:
     case GL_FLOAT_VEC3:
@@ -1633,6 +1667,12 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_BOOL_VEC2:
       case GL_BOOL_VEC2:
       case GL_BOOL_VEC3:
       case GL_BOOL_VEC3:
       case GL_BOOL_VEC4:
       case GL_BOOL_VEC4:
+      case GL_UNSIGNED_INT:
+      case GL_UNSIGNED_INT_VEC2:
+      case GL_UNSIGNED_INT_VEC3:
+      case GL_UNSIGNED_INT_VEC4:
+        bind._type = Shader::SPT_uint;
+        break;
       case GL_INT:
       case GL_INT:
       case GL_INT_VEC2:
       case GL_INT_VEC2:
       case GL_INT_VEC3:
       case GL_INT_VEC3:
@@ -2003,6 +2043,8 @@ issue_parameters(int altered) {
         return;
         return;
       }
       }
 
 
+      nassertd(spec._dim[1] > 0) continue;
+
       GLint p = spec._id._seqno;
       GLint p = spec._id._seqno;
       int array_size = min(spec._dim[0], (int)ptr_data->_size / spec._dim[1]);
       int array_size = min(spec._dim[0], (int)ptr_data->_size / spec._dim[1]);
       switch (spec._type) {
       switch (spec._type) {
@@ -2019,6 +2061,14 @@ issue_parameters(int altered) {
             }
             }
             break;
             break;
 
 
+          case Shader::SPT_uint:
+            // Convert unsigned int data to float data.
+            data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]);
+            for (int i = 0; i < (array_size * spec._dim[1]); ++i) {
+              data[i] = (float)(((unsigned int*)ptr_data->_ptr)[i]);
+            }
+            break;
+
           case Shader::SPT_double:
           case Shader::SPT_double:
             // Downgrade double data to float data.
             // Downgrade double data to float data.
             data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]);
             data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]);
@@ -2048,7 +2098,8 @@ issue_parameters(int altered) {
         break;
         break;
 
 
       case Shader::SPT_int:
       case Shader::SPT_int:
-        if (ptr_data->_type != Shader::SPT_int) {
+        if (ptr_data->_type != Shader::SPT_int &&
+            ptr_data->_type != Shader::SPT_uint) {
           GLCAT.error()
           GLCAT.error()
             << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
             << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
 
 
@@ -2068,6 +2119,28 @@ issue_parameters(int altered) {
         }
         }
         break;
         break;
 
 
+      case Shader::SPT_uint:
+        if (ptr_data->_type != Shader::SPT_uint &&
+            ptr_data->_type != Shader::SPT_int) {
+          GLCAT.error()
+            << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
+
+          // Deactivate it to make sure the user doesn't get flooded with this
+          // error.
+          spec._dep[0] = 0;
+          spec._dep[1] = 0;
+
+        } else {
+          switch (spec._dim[1]) {
+          case 1: _glgsg->_glUniform1uiv(p, array_size, (GLuint *)ptr_data->_ptr); continue;
+          case 2: _glgsg->_glUniform2uiv(p, array_size, (GLuint *)ptr_data->_ptr); continue;
+          case 3: _glgsg->_glUniform3uiv(p, array_size, (GLuint *)ptr_data->_ptr); continue;
+          case 4: _glgsg->_glUniform4uiv(p, array_size, (GLuint *)ptr_data->_ptr); continue;
+          }
+          nassertd(false) continue;
+        }
+        break;
+
       case Shader::SPT_double:
       case Shader::SPT_double:
         GLCAT.error() << "Passing double-precision shader inputs to GLSL shaders is not currently supported\n";
         GLCAT.error() << "Passing double-precision shader inputs to GLSL shaders is not currently supported\n";
 
 
@@ -2207,7 +2280,7 @@ disable_shader_vertex_arrays() {
     return;
     return;
   }
   }
 
 
-  for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
+  for (size_t i = 0; i < _shader->_var_spec.size(); ++i) {
     const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
     const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
     GLint p = bind._id._seqno;
     GLint p = bind._id._seqno;
 
 
@@ -2332,21 +2405,25 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
         }
         }
         client_pointer += start;
         client_pointer += start;
 
 
+        GLenum type = _glgsg->get_numeric_type(numeric_type);
         for (int i = 0; i < num_elements; ++i) {
         for (int i = 0; i < num_elements; ++i) {
           _glgsg->enable_vertex_attrib_array(p);
           _glgsg->enable_vertex_attrib_array(p);
 
 
-          if (bind._integer) {
-            _glgsg->_glVertexAttribIPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
-                                            stride, client_pointer);
-          } else if (numeric_type == GeomEnums::NT_packed_dabc) {
+          if (numeric_type == GeomEnums::NT_packed_dabc) {
             // GL_BGRA is a special accepted value available since OpenGL 3.2.
             // GL_BGRA is a special accepted value available since OpenGL 3.2.
             // It requires us to pass GL_TRUE for normalized.
             // It requires us to pass GL_TRUE for normalized.
             _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
             _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
                                            GL_TRUE, stride, client_pointer);
                                            GL_TRUE, stride, client_pointer);
-          } else {
-            _glgsg->_glVertexAttribPointer(p, num_values,
-                                           _glgsg->get_numeric_type(numeric_type),
+          } else if (bind._numeric_type == Shader::SPT_float ||
+                     numeric_type == GeomEnums::NT_float32) {
+            _glgsg->_glVertexAttribPointer(p, num_values, type,
                                            normalized, stride, client_pointer);
                                            normalized, stride, client_pointer);
+          } else if (bind._numeric_type == Shader::SPT_double) {
+            _glgsg->_glVertexAttribLPointer(p, num_values, type,
+                                            stride, client_pointer);
+          } else {
+            _glgsg->_glVertexAttribIPointer(p, num_values, type,
+                                            stride, client_pointer);
           }
           }
 
 
           if (divisor > 0) {
           if (divisor > 0) {

File diff suppressed because it is too large
+ 631 - 31
panda/src/glstuff/panda_glext.h


+ 0 - 12
panda/src/gobj/config_gobj.cxx

@@ -260,18 +260,6 @@ ConfigVariableBool cache_generated_shaders
  PRC_DESC("Set this true to cause all generated shaders to be cached in "
  PRC_DESC("Set this true to cause all generated shaders to be cached in "
           "memory.  This is useful to prevent unnecessary recompilation."));
           "memory.  This is useful to prevent unnecessary recompilation."));
 
 
-ConfigVariableBool enforce_attrib_lock
-("enforce-attrib-lock", true,
- PRC_DESC("When a MaterialAttrib, TextureAttrib, or LightAttrib is "
-          "constructed, the corresponding Material, Texture, or Light "
-          "is 'attrib locked.'  The attrib lock prevents qualitative "
-          "changes to the object.  This makes it possible to hardwire "
-          "information about material, light, and texture properties "
-          "into generated shaders.  This config variable can disable "
-          "the attrib lock.  Disabling the lock will break the shader "
-          "generator, but doing so may be necessary for backward "
-          "compatibility with old code."));
-
 ConfigVariableBool vertices_float64
 ConfigVariableBool vertices_float64
 ("vertices-float64", false,
 ("vertices-float64", false,
  PRC_DESC("When this is true, the default float format for vertices "
  PRC_DESC("When this is true, the default float format for vertices "

+ 0 - 1
panda/src/gobj/config_gobj.h

@@ -51,7 +51,6 @@ extern EXPCL_PANDA_GOBJ ConfigVariableBool connect_triangle_strips;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool preserve_triangle_strips;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool preserve_triangle_strips;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool dump_generated_shaders;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool dump_generated_shaders;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool cache_generated_shaders;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool cache_generated_shaders;
-extern EXPCL_PANDA_GOBJ ConfigVariableBool enforce_attrib_lock;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool vertices_float64;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool vertices_float64;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_column_alignment;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_column_alignment;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_animation_align_16;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_animation_align_16;

+ 49 - 12
panda/src/gobj/geom.cxx

@@ -195,6 +195,9 @@ offset_vertices(const GeomVertexData *data, int offset) {
   cdata->_data = (GeomVertexData *)data;
   cdata->_data = (GeomVertexData *)data;
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
+  GeomVertexDataPipelineReader data_reader(data, current_thread);
+  data_reader.check_array_readers();
+
   bool all_is_valid = true;
   bool all_is_valid = true;
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
@@ -203,7 +206,7 @@ offset_vertices(const GeomVertexData *data, int offset) {
     prim->offset_vertices(offset);
     prim->offset_vertices(offset);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-    if (!prim->check_valid(data)) {
+    if (!prim->check_valid(&data_reader)) {
       gobj_cat.warning()
       gobj_cat.warning()
         << *prim << " is invalid for " << *data << ":\n";
         << *prim << " is invalid for " << *data << ":\n";
       prim->write(gobj_cat.warning(false), 4);
       prim->write(gobj_cat.warning(false), 4);
@@ -423,6 +426,9 @@ decompose_in_place() {
   CDWriter cdata(_cycler, true, current_thread);
   CDWriter cdata(_cycler, true, current_thread);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
+  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
+  data_reader.check_array_readers();
+
   bool all_is_valid = true;
   bool all_is_valid = true;
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
@@ -431,7 +437,7 @@ decompose_in_place() {
     (*pi) = (GeomPrimitive *)new_prim.p();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
+    if (!new_prim->check_valid(&data_reader)) {
       all_is_valid = false;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -457,6 +463,9 @@ doubleside_in_place() {
   CDWriter cdata(_cycler, true, current_thread);
   CDWriter cdata(_cycler, true, current_thread);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
+  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
+  data_reader.check_array_readers();
+
   bool all_is_valid = true;
   bool all_is_valid = true;
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
@@ -465,7 +474,7 @@ doubleside_in_place() {
     (*pi) = (GeomPrimitive *)new_prim.p();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
+    if (!new_prim->check_valid(&data_reader)) {
       all_is_valid = false;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -491,6 +500,9 @@ reverse_in_place() {
   CDWriter cdata(_cycler, true, current_thread);
   CDWriter cdata(_cycler, true, current_thread);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
+  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
+  data_reader.check_array_readers();
+
   bool all_is_valid = true;
   bool all_is_valid = true;
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
@@ -499,7 +511,7 @@ reverse_in_place() {
     (*pi) = (GeomPrimitive *)new_prim.p();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
+    if (!new_prim->check_valid(&data_reader)) {
       all_is_valid = false;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -525,6 +537,9 @@ rotate_in_place() {
   CDWriter cdata(_cycler, true, current_thread);
   CDWriter cdata(_cycler, true, current_thread);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
+  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
+  data_reader.check_array_readers();
+
   bool all_is_valid = true;
   bool all_is_valid = true;
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
@@ -533,7 +548,7 @@ rotate_in_place() {
     (*pi) = (GeomPrimitive *)new_prim.p();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
+    if (!new_prim->check_valid(&data_reader)) {
       all_is_valid = false;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -640,6 +655,9 @@ unify_in_place(int max_indices, bool preserve_order) {
     // primitives.)
     // primitives.)
     nassertv(false);
     nassertv(false);
   }
   }
+
+  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
+  data_reader.check_array_readers();
 #endif
 #endif
 
 
   // Finally, iterate through the remaining primitives, and copy them to the
   // Finally, iterate through the remaining primitives, and copy them to the
@@ -649,7 +667,7 @@ unify_in_place(int max_indices, bool preserve_order) {
   for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) {
   for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) {
     GeomPrimitive *prim = (*npi).second;
     GeomPrimitive *prim = (*npi).second;
 
 
-    nassertv(prim->check_valid(cdata->_data.get_read_pointer(current_thread)));
+    nassertv(prim->check_valid(&data_reader));
 
 
     // Each new primitive, naturally, inherits the Geom's overall shade model.
     // Each new primitive, naturally, inherits the Geom's overall shade model.
     prim->set_shade_model(cdata->_shade_model);
     prim->set_shade_model(cdata->_shade_model);
@@ -748,6 +766,9 @@ make_lines_in_place() {
   CDWriter cdata(_cycler, true, current_thread);
   CDWriter cdata(_cycler, true, current_thread);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
+  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
+  data_reader.check_array_readers();
+
   bool all_is_valid = true;
   bool all_is_valid = true;
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
@@ -756,7 +777,7 @@ make_lines_in_place() {
     (*pi) = (GeomPrimitive *)new_prim.p();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
+    if (!new_prim->check_valid(&data_reader)) {
       all_is_valid = false;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -782,6 +803,9 @@ make_points_in_place() {
   CDWriter cdata(_cycler, true, current_thread);
   CDWriter cdata(_cycler, true, current_thread);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
+  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
+  data_reader.check_array_readers();
+
   bool all_is_valid = true;
   bool all_is_valid = true;
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
@@ -790,7 +814,7 @@ make_points_in_place() {
     (*pi) = (GeomPrimitive *)new_prim.p();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
+    if (!new_prim->check_valid(&data_reader)) {
       all_is_valid = false;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -816,6 +840,9 @@ make_patches_in_place() {
   CDWriter cdata(_cycler, true, current_thread);
   CDWriter cdata(_cycler, true, current_thread);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
+  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
+  data_reader.check_array_readers();
+
   bool all_is_valid = true;
   bool all_is_valid = true;
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
@@ -824,7 +851,7 @@ make_patches_in_place() {
     (*pi) = (GeomPrimitive *)new_prim.p();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
+    if (!new_prim->check_valid(&data_reader)) {
       all_is_valid = false;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -850,6 +877,9 @@ make_adjacency_in_place() {
   CDWriter cdata(_cycler, true, current_thread);
   CDWriter cdata(_cycler, true, current_thread);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
+  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
+  data_reader.check_array_readers();
+
   bool all_is_valid = true;
   bool all_is_valid = true;
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
@@ -859,7 +889,7 @@ make_adjacency_in_place() {
       (*pi) = (GeomPrimitive *)new_prim.p();
       (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-      if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
+      if (!new_prim->check_valid(&data_reader)) {
         all_is_valid = false;
         all_is_valid = false;
       }
       }
 #endif
 #endif
@@ -1465,13 +1495,20 @@ clear_prepared(PreparedGraphicsObjects *prepared_objects) {
  */
  */
 bool Geom::
 bool Geom::
 check_will_be_valid(const GeomVertexData *vertex_data) const {
 check_will_be_valid(const GeomVertexData *vertex_data) const {
-  CDReader cdata(_cycler);
+  Thread *current_thread = Thread::get_current_thread();
+
+  CDReader cdata(_cycler, current_thread);
+
+  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
+  data_reader.check_array_readers();
 
 
   Primitives::const_iterator pi;
   Primitives::const_iterator pi;
   for (pi = cdata->_primitives.begin();
   for (pi = cdata->_primitives.begin();
        pi != cdata->_primitives.end();
        pi != cdata->_primitives.end();
        ++pi) {
        ++pi) {
-    if (!(*pi).get_read_pointer()->check_valid(vertex_data)) {
+    GeomPrimitivePipelineReader reader((*pi).get_read_pointer(), current_thread);
+    reader.check_minmax();
+    if (!reader.check_valid(&data_reader)) {
       return false;
       return false;
     }
     }
   }
   }

+ 11 - 3
panda/src/gobj/geomPrimitive.I

@@ -223,11 +223,19 @@ get_modified() const {
 INLINE bool GeomPrimitive::
 INLINE bool GeomPrimitive::
 check_valid(const GeomVertexData *vertex_data) const {
 check_valid(const GeomVertexData *vertex_data) const {
   Thread *current_thread = Thread::get_current_thread();
   Thread *current_thread = Thread::get_current_thread();
-  GeomPrimitivePipelineReader reader(this, current_thread);
-  reader.check_minmax();
   GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
   GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
   data_reader.check_array_readers();
   data_reader.check_array_readers();
-  return reader.check_valid(&data_reader);
+  return check_valid(&data_reader);
+}
+
+/**
+ *
+ */
+INLINE bool GeomPrimitive::
+check_valid(const GeomVertexDataPipelineReader *data_reader) const {
+  GeomPrimitivePipelineReader reader(this, data_reader->get_current_thread());
+  reader.check_minmax();
+  return reader.check_valid(data_reader);
 }
 }
 
 
 /**
 /**

+ 1 - 0
panda/src/gobj/geomPrimitive.h

@@ -146,6 +146,7 @@ PUBLISHED:
   bool request_resident(Thread *current_thread = Thread::get_current_thread()) const;
   bool request_resident(Thread *current_thread = Thread::get_current_thread()) const;
 
 
   INLINE bool check_valid(const GeomVertexData *vertex_data) const;
   INLINE bool check_valid(const GeomVertexData *vertex_data) const;
+  INLINE bool check_valid(const GeomVertexDataPipelineReader *data_reader) const;
 
 
   virtual void output(std::ostream &out) const;
   virtual void output(std::ostream &out) const;
   virtual void write(std::ostream &out, int indent_level) const;
   virtual void write(std::ostream &out, int indent_level) const;

+ 16 - 10
panda/src/gobj/lens.I

@@ -667,9 +667,11 @@ do_get_film_offset(const CData *cdata) const {
  */
  */
 INLINE void Lens::
 INLINE void Lens::
 do_set_near(CData *cdata, PN_stdfloat near_distance) {
 do_set_near(CData *cdata, PN_stdfloat near_distance) {
-  cdata->_near_distance = near_distance;
-  do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv, 0);
-  do_throw_change_event(cdata);
+  if (near_distance != cdata->_near_distance) {
+    cdata->_near_distance = near_distance;
+    do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv, 0);
+    do_throw_change_event(cdata);
+  }
 }
 }
 
 
 /**
 /**
@@ -685,9 +687,11 @@ do_get_near(const CData *cdata) const {
  */
  */
 INLINE void Lens::
 INLINE void Lens::
 do_set_far(CData *cdata, PN_stdfloat far_distance) {
 do_set_far(CData *cdata, PN_stdfloat far_distance) {
-  cdata->_far_distance = far_distance;
-  do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv, 0);
-  do_throw_change_event(cdata);
+  if (far_distance != cdata->_far_distance) {
+    cdata->_far_distance = far_distance;
+    do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv, 0);
+    do_throw_change_event(cdata);
+  }
 }
 }
 
 
 /**
 /**
@@ -703,10 +707,12 @@ do_get_far(const CData *cdata) const {
  */
  */
 INLINE void Lens::
 INLINE void Lens::
 do_set_near_far(CData *cdata, PN_stdfloat near_distance, PN_stdfloat far_distance) {
 do_set_near_far(CData *cdata, PN_stdfloat near_distance, PN_stdfloat far_distance) {
-  cdata->_near_distance = near_distance;
-  cdata->_far_distance = far_distance;
-  do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv, 0);
-  do_throw_change_event(cdata);
+  if (near_distance != cdata->_near_distance || far_distance != cdata->_far_distance) {
+    cdata->_near_distance = near_distance;
+    cdata->_far_distance = far_distance;
+    do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv, 0);
+    do_throw_change_event(cdata);
+  }
 }
 }
 
 
 INLINE std::ostream &
 INLINE std::ostream &

+ 43 - 15
panda/src/gobj/material.I

@@ -32,8 +32,18 @@ Material(const std::string &name) : Namable(name) {
  *
  *
  */
  */
 INLINE Material::
 INLINE Material::
-Material(const Material &copy) : Namable(copy) {
-  operator = (copy);
+Material(const Material &copy) :
+  Namable(copy) ,
+  _base_color(copy._base_color),
+  _ambient(copy._ambient),
+  _diffuse(copy._diffuse),
+  _specular(copy._specular),
+  _emission(copy._emission),
+  _shininess(copy._shininess),
+  _roughness(copy._roughness),
+  _metallic(copy._metallic),
+  _refractive_index(copy._refractive_index),
+  _flags(copy._flags & ~(F_attrib_lock | F_used_by_auto_shader)) {
 }
 }
 
 
 /**
 /**
@@ -99,8 +109,8 @@ get_ambient() const {
  */
  */
 INLINE void Material::
 INLINE void Material::
 clear_ambient() {
 clear_ambient() {
-  if (enforce_attrib_lock) {
-    nassertv(!is_attrib_locked());
+  if (has_ambient() && is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   _flags &= ~F_ambient;
   _flags &= ~F_ambient;
   _ambient = _base_color;
   _ambient = _base_color;
@@ -129,8 +139,8 @@ get_diffuse() const {
  */
  */
 INLINE void Material::
 INLINE void Material::
 clear_diffuse() {
 clear_diffuse() {
-  if (enforce_attrib_lock) {
-    nassertv(!is_attrib_locked());
+  if (has_diffuse() && is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   _flags &= ~F_diffuse;
   _flags &= ~F_diffuse;
   _diffuse = _base_color * (1 - _metallic);
   _diffuse = _base_color * (1 - _metallic);
@@ -177,8 +187,8 @@ get_emission() const {
  */
  */
 INLINE void Material::
 INLINE void Material::
 clear_emission() {
 clear_emission() {
-  if (enforce_attrib_lock) {
-    nassertv(!is_attrib_locked());
+  if (has_emission() && is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   _flags &= ~F_emission;
   _flags &= ~F_emission;
   _emission.set(0.0f, 0.0f, 0.0f, 0.0f);
   _emission.set(0.0f, 0.0f, 0.0f, 0.0f);
@@ -253,8 +263,8 @@ get_local() const {
  */
  */
 INLINE void Material::
 INLINE void Material::
 set_local(bool local) {
 set_local(bool local) {
-  if (enforce_attrib_lock) {
-    nassertv(!is_attrib_locked());
+  if (is_used_by_auto_shader() && get_local() != local) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   if (local) {
   if (local) {
     _flags |= F_local;
     _flags |= F_local;
@@ -278,8 +288,8 @@ get_twoside() const {
  */
  */
 INLINE void Material::
 INLINE void Material::
 set_twoside(bool twoside) {
 set_twoside(bool twoside) {
-  if (enforce_attrib_lock) {
-    nassertv(!is_attrib_locked());
+  if (is_used_by_auto_shader() && get_twoside() != twoside) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   if (twoside) {
   if (twoside) {
     _flags |= F_twoside;
     _flags |= F_twoside;
@@ -313,7 +323,7 @@ operator < (const Material &other) const {
 }
 }
 
 
 /**
 /**
- *
+ * @deprecated This no longer has any meaning in 1.10.
  */
  */
 INLINE bool Material::
 INLINE bool Material::
 is_attrib_locked() const {
 is_attrib_locked() const {
@@ -321,17 +331,35 @@ is_attrib_locked() const {
 }
 }
 
 
 /**
 /**
- *
+ * @deprecated This no longer has any meaning in 1.10.
  */
  */
 INLINE void Material::
 INLINE void Material::
 set_attrib_lock() {
 set_attrib_lock() {
   _flags |= F_attrib_lock;
   _flags |= F_attrib_lock;
 }
 }
 
 
+/**
+ * Internal.  Returns true if a shader has been generated that uses this.
+ */
+INLINE bool Material::
+is_used_by_auto_shader() const {
+  return (_flags & F_attrib_lock) != 0;
+}
+
+/**
+ * Called by the shader generator to indicate that a shader has been generated
+ * that uses this material.
+ */
+INLINE void Material::
+mark_used_by_auto_shader() {
+  _flags |= F_used_by_auto_shader;
+}
+
 /**
 /**
  *
  *
  */
  */
 INLINE int Material::
 INLINE int Material::
 get_flags() const {
 get_flags() const {
-  return _flags;
+  // F_used_by_auto_shader is an internal flag, ignore it.
+  return _flags & ~F_used_by_auto_shader;
 }
 }

+ 25 - 34
panda/src/gobj/material.cxx

@@ -28,6 +28,11 @@ PT(Material) Material::_default;
 void Material::
 void Material::
 operator = (const Material &copy) {
 operator = (const Material &copy) {
   Namable::operator = (copy);
   Namable::operator = (copy);
+
+  if (is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
+  }
+
   _base_color = copy._base_color;
   _base_color = copy._base_color;
   _ambient = copy._ambient;
   _ambient = copy._ambient;
   _diffuse = copy._diffuse;
   _diffuse = copy._diffuse;
@@ -37,7 +42,7 @@ operator = (const Material &copy) {
   _roughness = copy._roughness;
   _roughness = copy._roughness;
   _metallic = copy._metallic;
   _metallic = copy._metallic;
   _refractive_index = copy._refractive_index;
   _refractive_index = copy._refractive_index;
-  _flags = copy._flags & (~F_attrib_lock);
+  _flags = (copy._flags & ~(F_attrib_lock | F_used_by_auto_shader)) | (_flags & (F_attrib_lock | F_used_by_auto_shader));
 }
 }
 
 
 /**
 /**
@@ -53,10 +58,8 @@ operator = (const Material &copy) {
  */
  */
 void Material::
 void Material::
 set_base_color(const LColor &color) {
 set_base_color(const LColor &color) {
-  if (enforce_attrib_lock) {
-    if ((_flags & F_base_color) == 0) {
-      nassertv(!is_attrib_locked());
-    }
+  if (!has_base_color() && is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   _base_color = color;
   _base_color = color;
   _flags |= F_base_color | F_metallic;
   _flags |= F_base_color | F_metallic;
@@ -81,8 +84,8 @@ set_base_color(const LColor &color) {
  */
  */
 void Material::
 void Material::
 clear_base_color() {
 clear_base_color() {
-  if (enforce_attrib_lock) {
-    nassertv(!is_attrib_locked());
+  if (has_base_color() && is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   _flags &= ~F_base_color;
   _flags &= ~F_base_color;
   _base_color.set(0.0f, 0.0f, 0.0f, 0.0f);
   _base_color.set(0.0f, 0.0f, 0.0f, 0.0f);
@@ -116,10 +119,8 @@ clear_base_color() {
  */
  */
 void Material::
 void Material::
 set_ambient(const LColor &color) {
 set_ambient(const LColor &color) {
-  if (enforce_attrib_lock) {
-    if ((_flags & F_ambient)==0) {
-      nassertv(!is_attrib_locked());
-    }
+  if (!has_ambient() && is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   _ambient = color;
   _ambient = color;
   _flags |= F_ambient;
   _flags |= F_ambient;
@@ -137,10 +138,8 @@ set_ambient(const LColor &color) {
  */
  */
 void Material::
 void Material::
 set_diffuse(const LColor &color) {
 set_diffuse(const LColor &color) {
-  if (enforce_attrib_lock) {
-    if ((_flags & F_diffuse)==0) {
-      nassertv(!is_attrib_locked());
-    }
+  if (!has_diffuse() && is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   _diffuse = color;
   _diffuse = color;
   _flags |= F_diffuse;
   _flags |= F_diffuse;
@@ -160,10 +159,8 @@ set_diffuse(const LColor &color) {
  */
  */
 void Material::
 void Material::
 set_specular(const LColor &color) {
 set_specular(const LColor &color) {
-  if (enforce_attrib_lock) {
-    if ((_flags & F_specular)==0) {
-      nassertv(!is_attrib_locked());
-    }
+  if (!has_specular() && is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   _specular = color;
   _specular = color;
   _flags |= F_specular;
   _flags |= F_specular;
@@ -174,8 +171,8 @@ set_specular(const LColor &color) {
  */
  */
 void Material::
 void Material::
 clear_specular() {
 clear_specular() {
-  if (enforce_attrib_lock) {
-    nassertv(!is_attrib_locked());
+  if (has_specular() && is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   _flags &= ~F_specular;
   _flags &= ~F_specular;
 
 
@@ -201,10 +198,8 @@ clear_specular() {
  */
  */
 void Material::
 void Material::
 set_emission(const LColor &color) {
 set_emission(const LColor &color) {
-  if (enforce_attrib_lock) {
-    if ((_flags & F_emission)==0) {
-      nassertv(!is_attrib_locked());
-    }
+  if (!has_emission() && is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
   }
   }
   _emission = color;
   _emission = color;
   _flags |= F_emission;
   _flags |= F_emission;
@@ -275,11 +270,6 @@ set_roughness(PN_stdfloat roughness) {
  */
  */
 void Material::
 void Material::
 set_metallic(PN_stdfloat metallic) {
 set_metallic(PN_stdfloat metallic) {
-  if (enforce_attrib_lock) {
-    if ((_flags & F_metallic) == 0) {
-      nassertv(!is_attrib_locked());
-    }
-  }
   _metallic = metallic;
   _metallic = metallic;
   _flags |= F_metallic;
   _flags |= F_metallic;
 
 
@@ -305,9 +295,6 @@ set_metallic(PN_stdfloat metallic) {
  */
  */
 void Material::
 void Material::
 clear_metallic() {
 clear_metallic() {
-  if (enforce_attrib_lock) {
-    nassertv(!is_attrib_locked());
-  }
   _flags &= ~F_metallic;
   _flags &= ~F_metallic;
   _metallic = 0;
   _metallic = 0;
 
 
@@ -482,7 +469,7 @@ write_datagram(BamWriter *manager, Datagram &me) {
   me.add_string(get_name());
   me.add_string(get_name());
 
 
   if (manager->get_file_minor_ver() >= 39) {
   if (manager->get_file_minor_ver() >= 39) {
-    me.add_int32(_flags);
+    me.add_int32(_flags & ~F_used_by_auto_shader);
 
 
     if (_flags & F_metallic) {
     if (_flags & F_metallic) {
       // Metalness workflow.
       // Metalness workflow.
@@ -570,4 +557,8 @@ fillin(DatagramIterator &scan, BamReader *manager) {
       set_roughness(_shininess);
       set_roughness(_shininess);
     }
     }
   }
   }
+
+  if (is_used_by_auto_shader()) {
+    GraphicsStateGuardianBase::mark_rehash_generated_shaders();
+  }
 }
 }

+ 6 - 0
panda/src/gobj/material.h

@@ -21,6 +21,7 @@
 #include "luse.h"
 #include "luse.h"
 #include "numeric_types.h"
 #include "numeric_types.h"
 #include "config_gobj.h"
 #include "config_gobj.h"
+#include "graphicsStateGuardianBase.h"
 
 
 class FactoryParams;
 class FactoryParams;
 
 
@@ -127,7 +128,11 @@ PUBLISHED:
   MAKE_PROPERTY(local, get_local, set_local);
   MAKE_PROPERTY(local, get_local, set_local);
   MAKE_PROPERTY(twoside, get_twoside, set_twoside);
   MAKE_PROPERTY(twoside, get_twoside, set_twoside);
 
 
+protected:
+  INLINE bool is_used_by_auto_shader() const;
+
 public:
 public:
+  INLINE void mark_used_by_auto_shader();
   INLINE int get_flags() const;
   INLINE int get_flags() const;
 
 
   enum Flags {
   enum Flags {
@@ -142,6 +147,7 @@ public:
     F_metallic    = 0x100,
     F_metallic    = 0x100,
     F_base_color  = 0x200,
     F_base_color  = 0x200,
     F_refractive_index = 0x400,
     F_refractive_index = 0x400,
+    F_used_by_auto_shader = 0x800,
   };
   };
 
 
 private:
 private:

+ 5 - 0
panda/src/gobj/perspectiveLens.cxx

@@ -71,9 +71,14 @@ do_compute_projection_mat(Lens::CData *lens_cdata) {
   PN_stdfloat fNear = do_get_near(lens_cdata);
   PN_stdfloat fNear = do_get_near(lens_cdata);
   PN_stdfloat a, b;
   PN_stdfloat a, b;
 
 
+  // Take the limits if either near or far is infinite.
   if (cinf(fFar)) {
   if (cinf(fFar)) {
     a = 1;
     a = 1;
     b = -2 * fNear;
     b = -2 * fNear;
+  } else if (cinf(fNear)) {
+    // This is valid if the near/far planes are inverted.
+    a = -1;
+    b = 2 * fFar;
   } else {
   } else {
     PN_stdfloat far_minus_near = fFar-fNear;
     PN_stdfloat far_minus_near = fFar-fNear;
     a = (fFar + fNear);
     a = (fFar + fNear);

+ 22 - 5
panda/src/gobj/shader.cxx

@@ -619,12 +619,29 @@ cg_recurse_parameters(CGparameter parameter, const ShaderType &type,
             p._type       = arg_type;
             p._type       = arg_type;
             p._direction  = arg_dir;
             p._direction  = arg_dir;
             p._varying    = (vbl == CG_VARYING);
             p._varying    = (vbl == CG_VARYING);
-            p._integer    = (base_type == CG_UINT || base_type == CG_INT ||
-                             base_type == CG_ULONG || base_type == CG_LONG ||
-                             base_type == CG_USHORT || base_type == CG_SHORT ||
-                             base_type == CG_UCHAR || base_type == CG_CHAR);
             p._cat        = shader_cat.get_safe_ptr();
             p._cat        = shader_cat.get_safe_ptr();
 
 
+            //NB. Cg does have a CG_DOUBLE type, but at least for the ARB
+            // profiles and GLSL profiles it just maps to float.
+            switch (base_type) {
+            case CG_UINT:
+            case CG_ULONG:
+            case CG_USHORT:
+            case CG_UCHAR:
+            case CG_BOOL:
+              p._numeric_type = SPT_uint;
+              break;
+            case CG_INT:
+            case CG_LONG:
+            case CG_SHORT:
+            case CG_CHAR:
+              p._numeric_type = SPT_int;
+              break;
+            default:
+              p._numeric_type = SPT_float;
+              break;
+            }
+
             success &= compile_parameter(p, arg_dim);
             success &= compile_parameter(p, arg_dim);
             break;
             break;
           }
           }
@@ -681,7 +698,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     ShaderVarSpec bind;
     ShaderVarSpec bind;
     bind._id = p._id;
     bind._id = p._id;
     bind._append_uv = -1;
     bind._append_uv = -1;
-    bind._integer = p._integer;
+    bind._numeric_type = p._numeric_type;
 
 
     if (pieces.size() == 2) {
     if (pieces.size() == 2) {
       if (pieces[1] == "position") {
       if (pieces[1] == "position") {

+ 10 - 9
panda/src/gobj/shader.h

@@ -331,6 +331,14 @@ public:
     int        _seqno;
     int        _seqno;
   };
   };
 
 
+  enum ShaderPtrType {
+    SPT_float,
+    SPT_double,
+    SPT_int,
+    SPT_uint,
+    SPT_unknown
+  };
+
   struct ShaderArgInfo {
   struct ShaderArgInfo {
     ShaderArgId       _id;
     ShaderArgId       _id;
     ShaderArgClass    _class;
     ShaderArgClass    _class;
@@ -338,17 +346,10 @@ public:
     ShaderArgType     _type;
     ShaderArgType     _type;
     ShaderArgDir      _direction;
     ShaderArgDir      _direction;
     bool              _varying;
     bool              _varying;
-    bool              _integer;
+    ShaderPtrType     _numeric_type;
     NotifyCategory   *_cat;
     NotifyCategory   *_cat;
   };
   };
 
 
-  enum ShaderPtrType {
-    SPT_float,
-    SPT_double,
-    SPT_int,
-    SPT_unknown
-  };
-
   // Container structure for data of parameters ShaderPtrSpec.
   // Container structure for data of parameters ShaderPtrSpec.
   struct ShaderPtrData {
   struct ShaderPtrData {
   private:
   private:
@@ -424,7 +425,7 @@ public:
     PT(InternalName)  _name;
     PT(InternalName)  _name;
     int               _append_uv;
     int               _append_uv;
     int               _elements;
     int               _elements;
-    bool              _integer;
+    ShaderPtrType     _numeric_type;
   };
   };
 
 
   struct ShaderPtrSpec {
   struct ShaderPtrSpec {

+ 8 - 4
panda/src/gobj/shaderBuffer.I

@@ -19,8 +19,7 @@ INLINE ShaderBuffer::
 ShaderBuffer(const std::string &name, uint64_t size, UsageHint usage_hint) :
 ShaderBuffer(const std::string &name, uint64_t size, UsageHint usage_hint) :
   Namable(name),
   Namable(name),
   _data_size_bytes(size),
   _data_size_bytes(size),
-  _usage_hint(usage_hint),
-  _contexts(nullptr) {
+  _usage_hint(usage_hint) {
 }
 }
 
 
 /**
 /**
@@ -32,8 +31,13 @@ ShaderBuffer(const std::string &name, vector_uchar initial_data, UsageHint usage
   Namable(name),
   Namable(name),
   _data_size_bytes(initial_data.size()),
   _data_size_bytes(initial_data.size()),
   _usage_hint(usage_hint),
   _usage_hint(usage_hint),
-  _initial_data(initial_data),
-  _contexts(nullptr) {
+  _initial_data(std::move(initial_data)) {
+
+  // Make sure it is padded to 16 bytes.  Some drivers like that.
+  if ((_initial_data.size() & 15u) != 0) {
+    _initial_data.resize((_initial_data.size() + 15u) & ~15u, 0);
+    _data_size_bytes = _initial_data.size();
+  }
 }
 }
 
 
 /**
 /**

+ 1 - 1
panda/src/gobj/shaderBuffer.cxx

@@ -193,7 +193,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 
 
   if (scan.get_bool() && _data_size_bytes > 0) {
   if (scan.get_bool() && _data_size_bytes > 0) {
     nassertv_always(_data_size_bytes <= scan.get_remaining_size());
     nassertv_always(_data_size_bytes <= scan.get_remaining_size());
-    _initial_data.resize(_data_size_bytes);
+    _initial_data.resize((_data_size_bytes + 15u) & ~15u);
     scan.extract_bytes(&_initial_data[0], _data_size_bytes);
     scan.extract_bytes(&_initial_data[0], _data_size_bytes);
   } else {
   } else {
     _initial_data.clear();
     _initial_data.clear();

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

@@ -63,7 +63,7 @@ private:
   vector_uchar _initial_data;
   vector_uchar _initial_data;
 
 
   typedef pmap<PreparedGraphicsObjects *, BufferContext *> Contexts;
   typedef pmap<PreparedGraphicsObjects *, BufferContext *> Contexts;
-  Contexts *_contexts;
+  Contexts *_contexts = nullptr;
 
 
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();

+ 0 - 25
panda/src/gobj/test_gobj.cxx

@@ -1,25 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file test_gobj.cxx
- * @author shochet
- * @date 2000-02-02
- */
-
-#include "geom.h"
-#include "perspectiveProjection.h"
-
-int main() {
-  nout << "running test_gobj" << std::endl;
-  PT(GeomTri) triangle = new GeomTri;
-  Frustumf frust;
-  PT(PerspectiveProjection) proj = new PerspectiveProjection(frust);
-  LMatrix4f mat = proj->get_projection_mat();
-  nout << "default proj matrix: " << mat;
-  return 0;
-}

+ 18 - 0
panda/src/gobj/texture.I

@@ -2342,6 +2342,24 @@ get_unsigned_int(const unsigned char *&p) {
   return (double)v.ui / 4294967295.0;
   return (double)v.ui / 4294967295.0;
 }
 }
 
 
+/**
+ * This is used by store() to retrieve the next consecutive component value
+ * from the indicated element of the array, which is taken to be an array of
+ * unsigned ints with the value packed in the 24 least significant bits.
+ */
+INLINE double Texture::
+get_unsigned_int_24(const unsigned char *&p) {
+  union {
+    uint32_t ui;
+    uint8_t uc[4];
+  } v;
+  v.uc[0] = (*p++);
+  v.uc[1] = (*p++);
+  v.uc[2] = (*p++);
+  v.uc[3] = (*p++);
+  return (double)(v.ui & 0xffffff) / (double)0xffffff;
+}
+
 /**
 /**
  * This is used by store() to retrieve the next consecutive component value
  * This is used by store() to retrieve the next consecutive component value
  * from the indicated element of the array, which is taken to be an array of
  * from the indicated element of the array, which is taken to be an array of

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

@@ -858,6 +858,7 @@ private:
   INLINE static double get_unsigned_byte(const unsigned char *&p);
   INLINE static double get_unsigned_byte(const unsigned char *&p);
   INLINE static double get_unsigned_short(const unsigned char *&p);
   INLINE static double get_unsigned_short(const unsigned char *&p);
   INLINE static double get_unsigned_int(const unsigned char *&p);
   INLINE static double get_unsigned_int(const unsigned char *&p);
+  INLINE static double get_unsigned_int_24(const unsigned char *&p);
   INLINE static double get_float(const unsigned char *&p);
   INLINE static double get_float(const unsigned char *&p);
   INLINE static double get_half_float(const unsigned char *&p);
   INLINE static double get_half_float(const unsigned char *&p);
 
 

+ 4 - 0
panda/src/gobj/texturePeeker.cxx

@@ -94,6 +94,10 @@ TexturePeeker(Texture *tex, Texture::CData *cdata) {
     _get_component = Texture::get_half_float;
     _get_component = Texture::get_half_float;
     break;
     break;
 
 
+  case Texture::T_unsigned_int_24_8:
+    _get_component = Texture::get_unsigned_int_24;
+    break;
+
   default:
   default:
     // Not supported.
     // Not supported.
     _image.clear();
     _image.clear();

+ 20 - 0
panda/src/gobj/texturePool.I

@@ -275,3 +275,23 @@ PT(Texture) TexturePool::
 make_texture(const std::string &extension) {
 make_texture(const std::string &extension) {
   return get_global_ptr()->ns_make_texture(extension);
   return get_global_ptr()->ns_make_texture(extension);
 }
 }
+
+/**
+ * Defines relative ordering between LookupKey instances.
+ */
+INLINE bool TexturePool::LookupKey::
+operator < (const LookupKey &other) const {
+  if (_fullpath != other._fullpath) {
+    return _fullpath < other._fullpath;
+  }
+  if (_alpha_fullpath != other._alpha_fullpath) {
+    return _alpha_fullpath < other._alpha_fullpath;
+  }
+  if (_primary_file_num_channels != other._primary_file_num_channels) {
+    return _primary_file_num_channels < other._primary_file_num_channels;
+  }
+  if (_alpha_file_channel != other._alpha_file_channel) {
+    return _alpha_file_channel < other._alpha_file_channel;
+  }
+  return _texture_type < other._texture_type;
+}

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