Browse Source

direct: More reduction of reliance on builtins, mypy fixes

rdb 2 years ago
parent
commit
c00f3b18f5

+ 187 - 166
direct/src/directtools/DirectCameraControl.py

@@ -1,6 +1,7 @@
 import math
 from panda3d.core import BitMask32, Mat4, NodePath, Point3, VBase3, Vec3, Vec4, rad2Deg
 from direct.showbase.DirectObject import DirectObject
+from direct.showbase import ShowBaseGlobal
 from .DirectUtil import CLAMP, useDirectRenderStyle
 from .DirectGeometry import getCrankAngle, getScreenXY
 from . import DirectGlobals as DG
@@ -26,7 +27,7 @@ class DirectCameraControl(DirectObject):
         self.orthoViewRoll = 0.0
         self.lastView = 0
         self.coa = Point3(0, 100, 0)
-        self.coaMarker = base.loader.loadModel('models/misc/sphere')
+        self.coaMarker = ShowBaseGlobal.loader.loadModel('models/misc/sphere')
         self.coaMarker.setName('DirectCameraCOAMarker')
         self.coaMarker.setTransparency(1)
         self.coaMarker.setColor(1, 0, 0, 0)
@@ -37,8 +38,8 @@ class DirectCameraControl(DirectObject):
         self.fLockCOA = 0
         self.nullHitPointCount = 0
         self.cqEntries = []
-        self.coaMarkerRef = base.direct.group.attachNewNode('coaMarkerRef')
-        self.camManipRef = base.direct.group.attachNewNode('camManipRef')
+        self.coaMarkerRef = ShowBaseGlobal.direct.group.attachNewNode('coaMarkerRef')
+        self.camManipRef = ShowBaseGlobal.direct.group.attachNewNode('camManipRef')
         self.switchDirBelowZero = True
         self.manipulateCameraTask = None
         self.manipulateCameraInterval = None
@@ -112,11 +113,6 @@ class DirectCameraControl(DirectObject):
         self.perspCollPlane2 = None # [gjeon] used for new LE
 
     def toggleMarkerVis(self):
-##        if base.direct.cameraControl.coaMarker.isHidden():
-##            base.direct.cameraControl.coaMarker.show()
-##        else:
-##            base.direct.cameraControl.coaMarker.hide()
-
         if self.coaMarker.isHidden():
             self.coaMarker.show()
         else:
@@ -132,11 +128,14 @@ class DirectCameraControl(DirectObject):
             # Hide the marker for this kind of motion
             self.coaMarker.hide()
             # Record time of start of mouse interaction
+            base = ShowBaseGlobal.base
             self.startT = base.clock.getFrameTime()
             self.startF = base.clock.getFrameCount()
             # If the cam is orthogonal, spawn differentTask
-            if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView and\
-               base.direct.camera.getName() != 'persp':
+            direct = ShowBaseGlobal.direct
+            if hasattr(direct, "manipulationControl") and \
+               direct.manipulationControl.fMultiView and \
+               direct.camera.getName() != 'persp':
                 self.spawnOrthoZoom()
             else:
                 # Start manipulation
@@ -167,7 +166,9 @@ class DirectCameraControl(DirectObject):
 
     def mouseFlyStart(self, modifiers):
         # Record undo point
-        # base.direct.pushUndo([base.direct.camera])            # Wasteful use of undo
+        base = ShowBaseGlobal.base
+        direct = ShowBaseGlobal.direct
+        #direct.pushUndo([direct.camera])            # Wasteful use of undo
         if self.useMayaCamControls and modifiers == 4:          # alt is down, use maya controls
             # Hide the marker for this kind of motion
             self.coaMarker.hide()
@@ -176,15 +177,16 @@ class DirectCameraControl(DirectObject):
             self.startF = base.clock.getFrameCount()
             # Start manipulation
             # If the cam is orthogonal, spawn differentTask
-            if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView and\
-               base.direct.camera.getName() != 'persp':
+            if hasattr(direct, "manipulationControl") and \
+               direct.manipulationControl.fMultiView and \
+               direct.camera.getName() != 'persp':
                 self.spawnOrthoTranslate()
             else:
                 self.spawnXZTranslate()
             self.altDown = 1
         elif not self.useMayaCamControls:
             # Where are we in the display region?
-            if ((abs(base.direct.dr.mouseX) < 0.9) and (abs(base.direct.dr.mouseY) < 0.9)):
+            if abs(direct.dr.mouseX) < 0.9 and abs(direct.dr.mouseY) < 0.9:
                 # MOUSE IS IN CENTRAL REGION
                 # Hide the marker for this kind of motion
                 self.coaMarker.hide()
@@ -194,19 +196,18 @@ class DirectCameraControl(DirectObject):
                 # Start manipulation
                 self.spawnXZTranslateOrHPanYZoom()
                 # END MOUSE IN CENTRAL REGION
+            elif abs(direct.dr.mouseX) > 0.9 and abs(direct.dr.mouseY) > 0.9:
+                # Mouse is in corners, spawn roll task
+                self.spawnMouseRollTask()
             else:
-                if ((abs(base.direct.dr.mouseX) > 0.9) and
-                    (abs(base.direct.dr.mouseY) > 0.9)):
-                    # Mouse is in corners, spawn roll task
-                    self.spawnMouseRollTask()
-                else:
-                    # Mouse is in outer frame, spawn mouseRotateTask
-                    self.spawnMouseRotateTask()
+                # Mouse is in outer frame, spawn mouseRotateTask
+                self.spawnMouseRotateTask()
         if not modifiers == 4:
             self.altDown = 0
 
     def mouseFlyStop(self):
         self.__stopManipulateCamera()
+        base = ShowBaseGlobal.base
         stopT = base.clock.getFrameTime()
         deltaT = stopT - self.startT
         stopF = base.clock.getFrameCount()
@@ -215,7 +216,8 @@ class DirectCameraControl(DirectObject):
         # if not self.useMayaCamControls and (deltaT <= 0.25) or (deltaF <= 1):
 
         # Do this when not trying to manipulate camera
-        if not self.altDown and len(base.direct.selected.getSelectedAsList()) == 0:
+        direct = ShowBaseGlobal.direct
+        if not self.altDown and len(direct.selected.getSelectedAsList()) == 0:
             # Check for a hit point based on
             # current mouse position
             # Allow intersection with unpickable objects
@@ -224,13 +226,13 @@ class DirectCameraControl(DirectObject):
             skipFlags = DG.SKIP_HIDDEN | DG.SKIP_BACKFACE
             # Skip camera (and its children), unless control key is pressed
             skipFlags |= DG.SKIP_CAMERA * (1 - base.getControl())
-            self.computeCOA(base.direct.iRay.pickGeom(skipFlags = skipFlags))
+            self.computeCOA(direct.iRay.pickGeom(skipFlags = skipFlags))
             # Record reference point
             self.coaMarkerRef.setPosHprScale(base.cam, 0, 0, 0, 0, 0, 0, 1, 1, 1)
             # Record entries
             self.cqEntries = []
-            for i in range(base.direct.iRay.getNumEntries()):
-                self.cqEntries.append(base.direct.iRay.getEntry(i))
+            for i in range(direct.iRay.getNumEntries()):
+                self.cqEntries.append(direct.iRay.getEntry(i))
         # Show the marker
         self.coaMarker.show()
         # Resize it
@@ -251,7 +253,7 @@ class DirectCameraControl(DirectObject):
         # Spawn the new task
         t = Task.Task(self.XZTranslateOrHPanYZoomTask)
         # For HPanYZoom
-        t.zoomSF = Vec3(self.coaMarker.getPos(base.direct.camera)).length()
+        t.zoomSF = Vec3(self.coaMarker.getPos(ShowBaseGlobal.direct.camera)).length()
         self.__startManipulateCamera(task = t)
 
     def spawnXZTranslateOrHPPan(self):
@@ -277,7 +279,7 @@ class DirectCameraControl(DirectObject):
         self.__stopManipulateCamera()
         # Spawn new task
         t = Task.Task(self.HPanYZoomTask)
-        t.zoomSF = Vec3(self.coaMarker.getPos(base.direct.camera)).length()
+        t.zoomSF = Vec3(self.coaMarker.getPos(ShowBaseGlobal.direct.camera)).length()
         self.__startManipulateCamera(task = t)
 
     def spawnOrthoZoom(self):
@@ -294,13 +296,13 @@ class DirectCameraControl(DirectObject):
         self.__startManipulateCamera(func = self.HPPanTask)
 
     def XZTranslateOrHPanYZoomTask(self, state):
-        if base.direct.fShift:
+        if ShowBaseGlobal.direct.fShift:
             return self.XZTranslateTask(state)
         else:
             return self.HPanYZoomTask(state)
 
     def XZTranslateOrHPPanTask(self, state):
-        if base.direct.fShift:
+        if ShowBaseGlobal.direct.fShift:
             # Panning action
             return self.HPPanTask(state)
         else:
@@ -308,43 +310,46 @@ class DirectCameraControl(DirectObject):
             return self.XZTranslateTask(state)
 
     def XZTranslateTask(self, state):
-        coaDist = Vec3(self.coaMarker.getPos(base.direct.camera)).length()
-        xlateSF = coaDist / base.direct.dr.near
-        base.direct.camera.setPos(base.direct.camera,
-                             (-0.5 * base.direct.dr.mouseDeltaX *
-                              base.direct.dr.nearWidth *
+        direct = ShowBaseGlobal.direct
+        coaDist = Vec3(self.coaMarker.getPos(direct.camera)).length()
+        xlateSF = coaDist / direct.dr.near
+        direct.camera.setPos(direct.camera,
+                             (-0.5 * direct.dr.mouseDeltaX *
+                              direct.dr.nearWidth *
                               xlateSF),
                              0.0,
-                             (-0.5 * base.direct.dr.mouseDeltaY *
-                              base.direct.dr.nearHeight *
+                             (-0.5 * direct.dr.mouseDeltaY *
+                              direct.dr.nearHeight *
                               xlateSF))
         return Task.cont
 
     def OrthoTranslateTask(self, state):
         # create ray from the camera to detect 3d position
-        iRay = SelectionRay(base.direct.camera)
-        iRay.collider.setFromLens(base.direct.camNode, base.direct.dr.mouseX, base.direct.dr.mouseY)
+        direct = ShowBaseGlobal.direct
+        iRay = SelectionRay(direct.camera)
+        iRay.collider.setFromLens(direct.camNode, direct.dr.mouseX, direct.dr.mouseY)
         #iRay.collideWithBitMask(1)
         iRay.collideWithBitMask(BitMask32.bit(21))
-        iRay.ct.traverse(base.direct.grid)
+        iRay.ct.traverse(direct.grid)
 
         entry = iRay.getEntry(0)
         hitPt = entry.getSurfacePoint(entry.getFromNodePath())
         iRay.collisionNodePath.removeNode()
         del iRay
         if hasattr(state, 'prevPt'):
-            base.direct.camera.setPos(base.direct.camera, (state.prevPt - hitPt))
+            direct.camera.setPos(direct.camera, (state.prevPt - hitPt))
         state.prevPt = hitPt
         return Task.cont
 
     def HPanYZoomTask(self, state):
         # If the cam is orthogonal, don't rotate or zoom.
-        if (hasattr(base.direct.cam.node(), "getLens") and
-            base.direct.cam.node().getLens().__class__.__name__ == "OrthographicLens"):
+        direct = ShowBaseGlobal.direct
+        if (hasattr(direct.cam.node(), "getLens") and
+            direct.cam.node().getLens().__class__.__name__ == "OrthographicLens"):
             return
 
-        if base.direct.fControl:
-            moveDir = Vec3(self.coaMarker.getPos(base.direct.camera))
+        if direct.fControl:
+            moveDir = Vec3(self.coaMarker.getPos(direct.camera))
             # If marker is behind camera invert vector
             if moveDir[1] < 0.0:
                 moveDir.assign(moveDir * -1)
@@ -353,18 +358,18 @@ class DirectCameraControl(DirectObject):
             moveDir = Vec3(Y_AXIS)
 
         if self.useMayaCamControls: # use maya controls
-            moveDir.assign(moveDir * ((base.direct.dr.mouseDeltaX -1.0 * base.direct.dr.mouseDeltaY)
+            moveDir.assign(moveDir * ((direct.dr.mouseDeltaX -1.0 * direct.dr.mouseDeltaY)
                                     * state.zoomSF))
             hVal = 0.0
         else:
-            moveDir.assign(moveDir * (-1.0 * base.direct.dr.mouseDeltaY *
+            moveDir.assign(moveDir * (-1.0 * direct.dr.mouseDeltaY *
                                         state.zoomSF))
-            if base.direct.dr.mouseDeltaY > 0.0:
+            if direct.dr.mouseDeltaY > 0.0:
                 moveDir.setY(moveDir[1] * 1.0)
 
-            hVal = 0.5 * base.direct.dr.mouseDeltaX * base.direct.dr.fovH
+            hVal = 0.5 * direct.dr.mouseDeltaX * direct.dr.fovH
 
-        base.direct.camera.setPosHpr(base.direct.camera,
+        direct.camera.setPosHpr(direct.camera,
                                 moveDir[0],
                                 moveDir[1],
                                 moveDir[2],
@@ -372,39 +377,42 @@ class DirectCameraControl(DirectObject):
                                 0.0, 0.0)
         if self.lockRoll:
             # flatten roll
-            base.direct.camera.setR(0)
+            direct.camera.setR(0)
 
         return Task.cont
 
     def OrthoZoomTask(self, state):
-        filmSize = base.direct.camNode.getLens().getFilmSize()
-        factor = (base.direct.dr.mouseDeltaX -1.0 * base.direct.dr.mouseDeltaY) * 0.1
-        x = base.direct.dr.getWidth()
-        y = base.direct.dr.getHeight()
-        base.direct.dr.orthoFactor -= factor
-        if base.direct.dr.orthoFactor < 0:
-            base.direct.dr.orthoFactor = 0.0001
-        base.direct.dr.updateFilmSize(x, y)
+        direct = ShowBaseGlobal.direct
+        filmSize = direct.camNode.getLens().getFilmSize()
+        factor = (direct.dr.mouseDeltaX -1.0 * direct.dr.mouseDeltaY) * 0.1
+        x = direct.dr.getWidth()
+        y = direct.dr.getHeight()
+        direct.dr.orthoFactor -= factor
+        if direct.dr.orthoFactor < 0:
+            direct.dr.orthoFactor = 0.0001
+        direct.dr.updateFilmSize(x, y)
         return Task.cont
 
     def HPPanTask(self, state):
-        base.direct.camera.setHpr(base.direct.camera,
-                             (0.5 * base.direct.dr.mouseDeltaX *
-                              base.direct.dr.fovH),
-                             (-0.5 * base.direct.dr.mouseDeltaY *
-                              base.direct.dr.fovV),
+        direct = ShowBaseGlobal.direct
+        direct.camera.setHpr(direct.camera,
+                             (0.5 * direct.dr.mouseDeltaX *
+                              direct.dr.fovH),
+                             (-0.5 * direct.dr.mouseDeltaY *
+                              direct.dr.fovV),
                              0.0)
         return Task.cont
 
     def spawnMouseRotateTask(self):
         # Kill any existing tasks
         self.__stopManipulateCamera()
+        direct = ShowBaseGlobal.direct
         if self.perspCollPlane:
-            iRay = SelectionRay(base.direct.camera)
-            iRay.collider.setFromLens(base.direct.camNode, 0.0, 0.0)
+            iRay = SelectionRay(direct.camera)
+            iRay.collider.setFromLens(direct.camNode, 0.0, 0.0)
             iRay.collideWithBitMask(1)
 
-            if base.direct.camera.getPos().getZ() >=0:
+            if direct.camera.getPos().getZ() >=0:
                 iRay.ct.traverse(self.perspCollPlane)
             else:
                 iRay.ct.traverse(self.perspCollPlane2)
@@ -415,7 +423,7 @@ class DirectCameraControl(DirectObject):
 
                 # create a temp nodePath to get the position
                 np = NodePath('temp')
-                np.setPos(base.direct.camera, hitPt)
+                np.setPos(direct.camera, hitPt)
                 self.coaMarkerPos = np.getPos()
                 np.removeNode()
                 self.coaMarker.setPos(self.coaMarkerPos)
@@ -425,9 +433,9 @@ class DirectCameraControl(DirectObject):
 
         # Set at markers position in render coordinates
         self.camManipRef.setPos(self.coaMarkerPos)
-        self.camManipRef.setHpr(base.direct.camera, DG.ZERO_POINT)
+        self.camManipRef.setHpr(direct.camera, DG.ZERO_POINT)
         t = Task.Task(self.mouseRotateTask)
-        if abs(base.direct.dr.mouseX) > 0.9:
+        if abs(direct.dr.mouseX) > 0.9:
             t.constrainedDir = 'y'
         else:
             t.constrainedDir = 'x'
@@ -435,36 +443,37 @@ class DirectCameraControl(DirectObject):
 
     def mouseRotateTask(self, state):
         # If the cam is orthogonal, don't rotate.
-        if (hasattr(base.direct.cam.node(), "getLens") and
-            base.direct.cam.node().getLens().__class__.__name__ == "OrthographicLens"):
+        direct = ShowBaseGlobal.direct
+        if (hasattr(direct.cam.node(), "getLens") and
+            direct.cam.node().getLens().__class__.__name__ == "OrthographicLens"):
             return
         # If moving outside of center, ignore motion perpendicular to edge
-        if ((state.constrainedDir == 'y') and (abs(base.direct.dr.mouseX) > 0.9)):
+        if ((state.constrainedDir == 'y') and (abs(direct.dr.mouseX) > 0.9)):
             deltaX = 0
-            deltaY = base.direct.dr.mouseDeltaY
-        elif ((state.constrainedDir == 'x') and (abs(base.direct.dr.mouseY) > 0.9)):
-            deltaX = base.direct.dr.mouseDeltaX
+            deltaY = direct.dr.mouseDeltaY
+        elif ((state.constrainedDir == 'x') and (abs(direct.dr.mouseY) > 0.9)):
+            deltaX = direct.dr.mouseDeltaX
             deltaY = 0
         else:
-            deltaX = base.direct.dr.mouseDeltaX
-            deltaY = base.direct.dr.mouseDeltaY
-        if base.direct.fShift:
-            base.direct.camera.setHpr(base.direct.camera,
-                                 (deltaX * base.direct.dr.fovH),
-                                 (-deltaY * base.direct.dr.fovV),
+            deltaX = direct.dr.mouseDeltaX
+            deltaY = direct.dr.mouseDeltaY
+        if direct.fShift:
+            direct.camera.setHpr(direct.camera,
+                                 (deltaX * direct.dr.fovH),
+                                 (-deltaY * direct.dr.fovV),
                                  0.0)
             if self.lockRoll:
                 # flatten roll
-                base.direct.camera.setR(0)
+                direct.camera.setR(0)
             self.camManipRef.setPos(self.coaMarkerPos)
-            self.camManipRef.setHpr(base.direct.camera, DG.ZERO_POINT)
+            self.camManipRef.setHpr(direct.camera, DG.ZERO_POINT)
         else:
-            if base.direct.camera.getPos().getZ() >=0 or not self.switchDirBelowZero:
+            if direct.camera.getPos().getZ() >=0 or not self.switchDirBelowZero:
                 dirX = -1
             else:
                 dirX = 1
 
-            wrt = base.direct.camera.getTransform(self.camManipRef)
+            wrt = direct.camera.getTransform(self.camManipRef)
             self.camManipRef.setHpr(self.camManipRef,
                                     (dirX * deltaX * 180.0),
                                     (deltaY * 180.0),
@@ -473,20 +482,21 @@ class DirectCameraControl(DirectObject):
             if self.lockRoll:
                 # flatten roll
                 self.camManipRef.setR(0)
-            base.direct.camera.setTransform(self.camManipRef, wrt)
+            direct.camera.setTransform(self.camManipRef, wrt)
         return Task.cont
 
     def spawnMouseRollTask(self):
         # Kill any existing tasks
         self.__stopManipulateCamera()
         # Set at markers position in render coordinates
+        direct = ShowBaseGlobal.direct
         self.camManipRef.setPos(self.coaMarkerPos)
-        self.camManipRef.setHpr(base.direct.camera, DG.ZERO_POINT)
+        self.camManipRef.setHpr(direct.camera, DG.ZERO_POINT)
         t = Task.Task(self.mouseRollTask)
         t.coaCenter = getScreenXY(self.coaMarker)
         t.lastAngle = getCrankAngle(t.coaCenter)
         # Store the camera/manipRef offset transform
-        t.wrt = base.direct.camera.getTransform(self.camManipRef)
+        t.wrt = direct.camera.getTransform(self.camManipRef)
         self.__startManipulateCamera(task = t)
 
     def mouseRollTask(self, state):
@@ -498,23 +508,23 @@ class DirectCameraControl(DirectObject):
         if self.lockRoll:
             # flatten roll
             self.camManipRef.setR(0)
-        base.direct.camera.setTransform(self.camManipRef, wrt)
+        ShowBaseGlobal.direct.camera.setTransform(self.camManipRef, wrt)
         return Task.cont
 
     def lockCOA(self):
         self.fLockCOA = 1
-        base.direct.message('COA Lock On')
+        ShowBaseGlobal.direct.message('COA Lock On')
 
     def unlockCOA(self):
         self.fLockCOA = 0
-        base.direct.message('COA Lock Off')
+        ShowBaseGlobal.direct.message('COA Lock Off')
 
     def toggleCOALock(self):
         self.fLockCOA = 1 - self.fLockCOA
         if self.fLockCOA:
-            base.direct.message('COA Lock On')
+            ShowBaseGlobal.direct.message('COA Lock On')
         else:
-            base.direct.message('COA Lock Off')
+            ShowBaseGlobal.direct.message('COA Lock Off')
 
     def pickNextCOA(self):
         """ Cycle through collision handler entries """
@@ -524,7 +534,7 @@ class DirectCameraControl(DirectObject):
             self.cqEntries = self.cqEntries[1:] + self.cqEntries[:1]
             # Filter out object's under camera
             nodePath = entry.getIntoNodePath()
-            if base.direct.camera not in nodePath.getAncestors():
+            if ShowBaseGlobal.direct.camera not in nodePath.getAncestors():
                 # Compute new hit point
                 hitPt = entry.getSurfacePoint(entry.getFromNodePath())
                 # Move coa marker to new point
@@ -536,11 +546,11 @@ class DirectCameraControl(DirectObject):
 
     def computeCOA(self, entry):
         coa = Point3(0)
-        dr = base.direct.drList.getCurrentDr()
+        dr = ShowBaseGlobal.direct.drList.getCurrentDr()
         if self.fLockCOA:
             # COA is locked, use existing point
             # Use existing point
-            coa.assign(self.coaMarker.getPos(base.direct.camera))
+            coa.assign(self.coaMarker.getPos(ShowBaseGlobal.direct.camera))
             # Reset hit point count
             self.nullHitPointCount = 0
         elif entry:
@@ -553,7 +563,7 @@ class DirectCameraControl(DirectObject):
             if ((hitPtDist < (1.1 * dr.near)) or
                 (hitPtDist > dr.far)):
                 # Just use existing point
-                coa.assign(self.coaMarker.getPos(base.direct.camera))
+                coa.assign(self.coaMarker.getPos(ShowBaseGlobal.direct.camera))
             # Reset hit point count
             self.nullHitPointCount = 0
         else:
@@ -565,7 +575,7 @@ class DirectCameraControl(DirectObject):
             # MRM: Would be nice to be able to control this
             # At least display it
             dist = pow(10.0, self.nullHitPointCount)
-            base.direct.message('COA Distance: ' + repr(dist))
+            ShowBaseGlobal.direct.message('COA Distance: ' + repr(dist))
             coa.set(0, dist, 0)
         # Compute COA Dist
         coaDist = Vec3(coa - DG.ZERO_POINT).length()
@@ -583,7 +593,7 @@ class DirectCameraControl(DirectObject):
         if ref is None:
             # KEH: use the current display region
             # ref = base.cam
-            ref = base.direct.drList.getCurrentDr().cam
+            ref = ShowBaseGlobal.direct.drList.getCurrentDr().cam
         self.coaMarker.setPos(ref, self.coa)
         pos = self.coaMarker.getPos()
         self.coaMarker.setPosHprScale(pos, Vec3(0), Vec3(1))
@@ -598,10 +608,10 @@ class DirectCameraControl(DirectObject):
 
     def updateCoaMarkerSize(self, coaDist = None):
         if not coaDist:
-            coaDist = Vec3(self.coaMarker.getPos(base.direct.camera)).length()
+            coaDist = Vec3(self.coaMarker.getPos(ShowBaseGlobal.direct.camera)).length()
         # Nominal size based on default 30 degree vertical FOV
         # Need to adjust size based on distance and current FOV
-        sf = COA_MARKER_SF * coaDist * (base.direct.drList.getCurrentDr().fovV/30.0)
+        sf = COA_MARKER_SF * coaDist * (ShowBaseGlobal.direct.drList.getCurrentDr().fovV/30.0)
         if sf == 0.0:
             sf = 0.1
         self.coaMarker.setScale(sf)
@@ -619,32 +629,36 @@ class DirectCameraControl(DirectObject):
 
     def homeCam(self):
         # Record undo point
-        base.direct.pushUndo([base.direct.camera])
-        base.direct.camera.reparentTo(render)
-        base.direct.camera.clearMat()
+        direct = ShowBaseGlobal.direct
+        direct.pushUndo([direct.camera])
+        direct.camera.reparentTo(ShowBaseGlobal.base.render)
+        direct.camera.clearMat()
         # Resize coa marker
         self.updateCoaMarkerSize()
 
     def uprightCam(self):
         self.__stopManipulateCamera()
         # Record undo point
-        base.direct.pushUndo([base.direct.camera])
+        direct = ShowBaseGlobal.direct
+        direct.pushUndo([direct.camera])
         # Pitch camera till upright
-        currH = base.direct.camera.getH()
-        ival = base.direct.camera.hprInterval(CAM_MOVE_DURATION,
-                                              (currH, 0, 0),
-                                              other = render,
-                                              blendType = 'easeInOut',
-                                              name = 'manipulateCamera')
-        self.__startManipulateCamera(ival = ival)
+        currH = direct.camera.getH()
+        ival = direct.camera.hprInterval(CAM_MOVE_DURATION,
+                                         (currH, 0, 0),
+                                         other=ShowBaseGlobal.base.render,
+                                         blendType='easeInOut',
+                                         name='manipulateCamera')
+        self.__startManipulateCamera(ival=ival)
 
     def orbitUprightCam(self):
         self.__stopManipulateCamera()
         # Record undo point
-        base.direct.pushUndo([base.direct.camera])
+        direct = ShowBaseGlobal.direct
+        direct.pushUndo([direct.camera])
         # Transform camera z axis to render space
+        render = ShowBaseGlobal.base.render
         mCam2Render = Mat4(Mat4.identMat()) # [gjeon] fixed to give required argument
-        mCam2Render.assign(base.direct.camera.getMat(render))
+        mCam2Render.assign(direct.camera.getMat(render))
         zAxis = Vec3(mCam2Render.xformVec(DG.Z_AXIS))
         zAxis.normalize()
         # Compute rotation angle needed to upright cam
@@ -665,8 +679,8 @@ class DirectCameraControl(DirectObject):
         self.camManipRef.setPos(self.coaMarker, Vec3(0))
         self.camManipRef.setHpr(render, rotAngle, 0, 0)
         # Reparent Cam to ref Coordinate system
-        parent = base.direct.camera.getParent()
-        base.direct.camera.wrtReparentTo(self.camManipRef)
+        parent = direct.camera.getParent()
+        direct.camera.wrtReparentTo(self.camManipRef)
         # Rotate ref CS to final orientation
         ival = self.camManipRef.hprInterval(CAM_MOVE_DURATION,
                                             (rotAngle, orbitAngle, 0),
@@ -685,17 +699,18 @@ class DirectCameraControl(DirectObject):
     def centerCamIn(self, t):
         self.__stopManipulateCamera()
         # Record undo point
-        base.direct.pushUndo([base.direct.camera])
+        direct = ShowBaseGlobal.direct
+        direct.pushUndo([direct.camera])
         # Determine marker location
-        markerToCam = self.coaMarker.getPos(base.direct.camera)
+        markerToCam = self.coaMarker.getPos(direct.camera)
         dist = Vec3(markerToCam - DG.ZERO_POINT).length()
         scaledCenterVec = Y_AXIS * dist
         delta = markerToCam - scaledCenterVec
-        self.camManipRef.setPosHpr(base.direct.camera, Point3(0), Point3(0))
-        ival = base.direct.camera.posInterval(CAM_MOVE_DURATION,
-                                              Point3(delta),
-                                              other = self.camManipRef,
-                                              blendType = 'easeInOut')
+        self.camManipRef.setPosHpr(direct.camera, Point3(0), Point3(0))
+        ival = direct.camera.posInterval(CAM_MOVE_DURATION,
+                                         Point3(delta),
+                                         other=self.camManipRef,
+                                         blendType='easeInOut')
         ival = Sequence(ival, Func(self.updateCoaMarkerSizeOnDeath),
                         name = 'manipulateCamera')
         self.__startManipulateCamera(ival = ival)
@@ -703,17 +718,18 @@ class DirectCameraControl(DirectObject):
     def zoomCam(self, zoomFactor, t):
         self.__stopManipulateCamera()
         # Record undo point
-        base.direct.pushUndo([base.direct.camera])
+        direct = ShowBaseGlobal.direct
+        direct.pushUndo([direct.camera])
         # Find a point zoom factor times the current separation
         # of the widget and cam
-        zoomPtToCam = self.coaMarker.getPos(base.direct.camera) * zoomFactor
+        zoomPtToCam = self.coaMarker.getPos(direct.camera) * zoomFactor
         # Put a target nodePath there
-        self.camManipRef.setPos(base.direct.camera, zoomPtToCam)
+        self.camManipRef.setPos(direct.camera, zoomPtToCam)
         # Move to that point
-        ival = base.direct.camera.posInterval(CAM_MOVE_DURATION,
-                                              DG.ZERO_POINT,
-                                              other = self.camManipRef,
-                                              blendType = 'easeInOut')
+        ival = direct.camera.posInterval(CAM_MOVE_DURATION,
+                                         DG.ZERO_POINT,
+                                         other=self.camManipRef,
+                                         blendType='easeInOut')
         ival = Sequence(ival, Func(self.updateCoaMarkerSizeOnDeath),
                         name = 'manipulateCamera')
         self.__startManipulateCamera(ival = ival)
@@ -722,7 +738,8 @@ class DirectCameraControl(DirectObject):
         # Kill any existing tasks
         self.__stopManipulateCamera()
         # Record undo point
-        base.direct.pushUndo([base.direct.camera])
+        direct = ShowBaseGlobal.direct
+        direct.pushUndo([direct.camera])
         # Calc hprOffset
         hprOffset = VBase3()
         if view == 8:
@@ -751,7 +768,7 @@ class DirectCameraControl(DirectObject):
         self.camManipRef.setPosHpr(self.coaMarker, DG.ZERO_VEC,
                                    hprOffset)
         # Scale center vec by current distance to target
-        offsetDistance = Vec3(base.direct.camera.getPos(self.camManipRef) -
+        offsetDistance = Vec3(direct.camera.getPos(self.camManipRef) -
                               DG.ZERO_POINT).length()
         scaledCenterVec = Y_AXIS * (-1.0 * offsetDistance)
         # Now put the camManipRef at that point
@@ -760,11 +777,11 @@ class DirectCameraControl(DirectObject):
                                    DG.ZERO_VEC)
         # Record view for next time around
         self.lastView = view
-        ival = base.direct.camera.posHprInterval(CAM_MOVE_DURATION,
-                                                 pos = DG.ZERO_POINT,
-                                                 hpr = VBase3(0, 0, self.orthoViewRoll),
-                                                 other = self.camManipRef,
-                                                 blendType = 'easeInOut')
+        ival = direct.camera.posHprInterval(CAM_MOVE_DURATION,
+                                            pos=DG.ZERO_POINT,
+                                            hpr=VBase3(0, 0, self.orthoViewRoll),
+                                            other=self.camManipRef,
+                                            blendType='easeInOut')
         ival = Sequence(ival, Func(self.updateCoaMarkerSizeOnDeath),
                         name = 'manipulateCamera')
         self.__startManipulateCamera(ival = ival)
@@ -774,15 +791,16 @@ class DirectCameraControl(DirectObject):
         self.__stopManipulateCamera()
 
         # Record undo point
-        base.direct.pushUndo([base.direct.camera])
+        direct = ShowBaseGlobal.direct
+        direct.pushUndo([direct.camera])
 
         # Coincident with widget
         self.camManipRef.setPos(self.coaMarker, DG.ZERO_POINT)
         # But aligned with render space
         self.camManipRef.setHpr(DG.ZERO_POINT)
 
-        parent = base.direct.camera.getParent()
-        base.direct.camera.wrtReparentTo(self.camManipRef)
+        parent = direct.camera.getParent()
+        direct.camera.wrtReparentTo(self.camManipRef)
 
         ival = self.camManipRef.hprInterval(CAM_MOVE_DURATION,
                                             VBase3(degrees, 0, 0),
@@ -792,7 +810,7 @@ class DirectCameraControl(DirectObject):
         self.__startManipulateCamera(ival = ival)
 
     def reparentCam(self, parent):
-        base.direct.camera.wrtReparentTo(parent)
+        ShowBaseGlobal.direct.camera.wrtReparentTo(parent)
         self.updateCoaMarkerSize()
 
     def fitOnWidget(self, nodePath = 'None Given'):
@@ -800,75 +818,78 @@ class DirectCameraControl(DirectObject):
         # stop any ongoing tasks
         self.__stopManipulateCamera()
         # How big is the node?
-        nodeScale = base.direct.widget.scalingNode.getScale(render)
+        direct = ShowBaseGlobal.direct
+        nodeScale = direct.widget.scalingNode.getScale(ShowBaseGlobal.base.render)
         maxScale = max(nodeScale[0], nodeScale[1], nodeScale[2])
-        maxDim = min(base.direct.dr.nearWidth, base.direct.dr.nearHeight)
+        maxDim = min(direct.dr.nearWidth, direct.dr.nearHeight)
 
         # At what distance does the object fill 30% of the screen?
         # Assuming radius of 1 on widget
-        camY = base.direct.dr.near * (2.0 * maxScale)/(0.3 * maxDim)
+        camY = direct.dr.near * (2.0 * maxScale) / (0.3 * maxDim)
 
         # What is the vector through the center of the screen?
         centerVec = Y_AXIS * camY
 
         # Where is the node relative to the viewpoint
-        vWidget2Camera = base.direct.widget.getPos(base.direct.camera)
+        vWidget2Camera = direct.widget.getPos(direct.camera)
 
         # How far do you move the camera to be this distance from the node?
         deltaMove = vWidget2Camera - centerVec
 
         # Move a target there
         try:
-            self.camManipRef.setPos(base.direct.camera, deltaMove)
+            self.camManipRef.setPos(direct.camera, deltaMove)
         except Exception:
             #self.notify.debug
             pass
 
-        parent = base.direct.camera.getParent()
-        base.direct.camera.wrtReparentTo(self.camManipRef)
-        ival = base.direct.camera.posInterval(CAM_MOVE_DURATION,
-                                              Point3(0, 0, 0),
-                                              blendType = 'easeInOut')
+        parent = direct.camera.getParent()
+        direct.camera.wrtReparentTo(self.camManipRef)
+        ival = direct.camera.posInterval(CAM_MOVE_DURATION,
+                                         Point3(0, 0, 0),
+                                         blendType='easeInOut')
         ival = Sequence(ival, Func(self.reparentCam, parent),
-                        name = 'manipulateCamera')
-        self.__startManipulateCamera(ival = ival)
+                        name='manipulateCamera')
+        self.__startManipulateCamera(ival=ival)
 
     def moveToFit(self):
         # How big is the active widget?
-        widgetScale = base.direct.widget.scalingNode.getScale(render)
+        direct = ShowBaseGlobal.direct
+        widgetScale = direct.widget.scalingNode.getScale(ShowBaseGlobal.base.render)
         maxScale = max(widgetScale[0], widgetScale[1], widgetScale[2])
         # At what distance does the widget fill 50% of the screen?
-        camY = ((2 * base.direct.dr.near * (1.5 * maxScale)) /
-                min(base.direct.dr.nearWidth, base.direct.dr.nearHeight))
+        camY = ((2 * direct.dr.near * (1.5 * maxScale)) /
+                min(direct.dr.nearWidth, direct.dr.nearHeight))
         # Find a point this distance along the Y axis
         # MRM: This needs to be generalized to support non uniform frusta
         centerVec = Y_AXIS * camY
         # Before moving, record the relationship between the selected nodes
         # and the widget, so that this can be maintained
-        base.direct.selected.getWrtAll()
+        direct.selected.getWrtAll()
         # Push state onto undo stack
-        base.direct.pushUndo(base.direct.selected)
+        direct.pushUndo(direct.selected)
         # Remove the task to keep the widget attached to the object
         taskMgr.remove('followSelectedNodePath')
         # Spawn a task to keep the selected objects with the widget
         taskMgr.add(self.stickToWidgetTask, 'stickToWidget')
         # Spawn a task to move the widget
-        ival = base.direct.widget.posInterval(CAM_MOVE_DURATION,
-                                              Point3(centerVec),
-                                              other = base.direct.camera,
-                                              blendType = 'easeInOut')
+        ival = direct.widget.posInterval(CAM_MOVE_DURATION,
+                                         Point3(centerVec),
+                                         other=direct.camera,
+                                         blendType='easeInOut')
         ival = Sequence(ival, Func(lambda: taskMgr.remove('stickToWidget')),
                         name = 'moveToFit')
         ival.start()
 
     def stickToWidgetTask(self, state):
         # Move the objects with the widget
-        base.direct.selected.moveWrtWidgetAll()
+        ShowBaseGlobal.direct.selected.moveWrtWidgetAll()
         # Continue
         return Task.cont
 
     def enableMouseFly(self, fKeyEvents = 1):
         # disable C++ fly interface
+        base = ShowBaseGlobal.base
         base.disableMouse()
         # Enable events
         for event in self.actionEvents:
@@ -877,11 +898,11 @@ class DirectCameraControl(DirectObject):
             for event in self.keyEvents:
                 self.accept(event[0], event[1], extraArgs = event[2:])
         # Show marker
-        self.coaMarker.reparentTo(base.direct.group)
+        self.coaMarker.reparentTo(ShowBaseGlobal.direct.group)
 
     def disableMouseFly(self):
         # Hide the marker
-        self.coaMarker.reparentTo(hidden)
+        self.coaMarker.reparentTo(ShowBaseGlobal.hidden)
         # Ignore events
         for event in self.actionEvents:
             self.ignore(event[0])
@@ -890,7 +911,7 @@ class DirectCameraControl(DirectObject):
         # Kill tasks
         self.removeManipulateCameraTask()
         taskMgr.remove('stickToWidget')
-        base.enableMouse()
+        ShowBaseGlobal.base.enableMouse()
 
     def removeManipulateCameraTask(self):
         self.__stopManipulateCamera()

+ 4 - 3
direct/src/directtools/DirectGrid.py

@@ -1,6 +1,7 @@
 import math
 from panda3d.core import NodePath, Point3, VBase4
 from direct.showbase.DirectObject import DirectObject
+from direct.showbase import ShowBaseGlobal
 from .DirectUtil import ROUND_TO, useDirectRenderStyle
 from .DirectGeometry import LineNodePath
 
@@ -14,7 +15,7 @@ class DirectGrid(NodePath, DirectObject):
 
         # Load up grid parts to initialize grid object
         # Polygon used to mark grid plane
-        self.gridBack = base.loader.loadModel('models/misc/gridBack')
+        self.gridBack = ShowBaseGlobal.loader.loadModel('models/misc/gridBack')
         self.gridBack.reparentTo(self)
         self.gridBack.setColor(*planeColor)
 
@@ -36,7 +37,7 @@ class DirectGrid(NodePath, DirectObject):
         self.centerLines.setThickness(3)
 
         # Small marker to hilight snap-to-grid point
-        self.snapMarker = base.loader.loadModel('models/misc/sphere')
+        self.snapMarker = ShowBaseGlobal.loader.loadModel('models/misc/sphere')
         self.snapMarker.node().setName('gridSnapMarker')
         self.snapMarker.reparentTo(self)
         self.snapMarker.setColor(1, 0, 0, 1)
@@ -55,7 +56,7 @@ class DirectGrid(NodePath, DirectObject):
         if parent:
             self.reparentTo(parent)
         else:
-            self.reparentTo(base.direct.group)
+            self.reparentTo(ShowBaseGlobal.direct.group)
 
         self.updateGrid()
         self.fEnabled = 1

+ 1 - 1
direct/src/directtools/DirectManipulation.py

@@ -1113,7 +1113,7 @@ class ObjectHandles(NodePath, DirectObject):
         NodePath.__init__(self)
 
         # Load up object handles model and assign it to self
-        self.assign(ShowBaseGlobal.base.loader.loadModel('models/misc/objectHandles'))
+        self.assign(ShowBaseGlobal.loader.loadModel('models/misc/objectHandles'))
         self.setName(name)
         self.scalingNode = NodePath(self)
         self.scalingNode.setName('ohScalingNode')

+ 12 - 4
direct/src/extensions_native/NodePath_extensions.py

@@ -435,7 +435,8 @@ Dtool_funcToMethod(iPosHprScale, NodePath)
 del iPosHprScale
 #####################################################################
 def place(self):
-    base.startDirect(fWantTk = 1)
+    from direct.showbase import ShowBaseGlobal
+    ShowBaseGlobal.base.startDirect(fWantTk = 1)
     # Don't use a regular import, to prevent ModuleFinder from picking
     # it up as a dependency when building a .p3d package.
     import importlib
@@ -446,7 +447,8 @@ Dtool_funcToMethod(place, NodePath)
 del place
 #####################################################################
 def explore(self):
-    base.startDirect(fWantTk = 1)
+    from direct.showbase import ShowBaseGlobal
+    ShowBaseGlobal.base.startDirect(fWantTk = 1)
     # Don't use a regular import, to prevent ModuleFinder from picking
     # it up as a dependency when building a .p3d package.
     import importlib
@@ -457,7 +459,8 @@ Dtool_funcToMethod(explore, NodePath)
 del explore
 #####################################################################
 def rgbPanel(self, cb = None):
-    base.startTk()
+    from direct.showbase import ShowBaseGlobal
+    ShowBaseGlobal.base.startTk()
     # Don't use a regular import, to prevent ModuleFinder from picking
     # it up as a dependency when building a .p3d package.
     import importlib
@@ -468,6 +471,8 @@ Dtool_funcToMethod(rgbPanel, NodePath)
 del rgbPanel
 #####################################################################
 def select(self):
+    from direct.showbase import ShowBaseGlobal
+    base = ShowBaseGlobal.base
     base.startDirect(fWantTk = 0)
     base.direct.select(self)
 
@@ -475,6 +480,8 @@ Dtool_funcToMethod(select, NodePath)
 del select
 #####################################################################
 def deselect(self):
+    from direct.showbase import ShowBaseGlobal
+    base = ShowBaseGlobal.base
     base.startDirect(fWantTk = 0)
     base.direct.deselect(self)
 
@@ -676,7 +683,8 @@ def flattenMultitex(self, stateFrom = None, target = None,
     mr.setAllowTexMat(allowTexMat)
 
     if win is None:
-        win = base.win
+        from direct.showbase import ShowBaseGlobal
+        win = ShowBaseGlobal.base.win
 
     if stateFrom is None:
         mr.scan(self)

+ 1 - 0
direct/src/showbase/ShowBase.py

@@ -431,6 +431,7 @@ class ShowBase(DirectObject.DirectObject):
         #: `.Loader.Loader` object.
         self.loader = Loader.Loader(self)
         self.graphicsEngine.setDefaultLoader(self.loader.loader)
+        ShowBaseGlobal.loader = self.loader
 
         #: The global event manager, as imported from `.EventManagerGlobal`.
         self.eventMgr = eventMgr

+ 3 - 0
direct/src/showbase/ShowBaseGlobal.py

@@ -19,6 +19,7 @@ from panda3d.core import VirtualFileSystem, Notify, ClockObject, PandaSystem
 from panda3d.core import ConfigPageManager, ConfigVariableManager, ConfigVariableBool
 from panda3d.core import NodePath, PGTop
 from . import DConfig as config # pylint: disable=unused-import
+from .Loader import Loader
 import warnings
 
 __dev__: bool = ConfigVariableBool('want-dev', __debug__).value
@@ -61,6 +62,8 @@ aspect2d = render2d.attachNewNode(PGTop("aspect2d"))
 #: A dummy scene graph that is not being rendered by anything.
 hidden = NodePath("hidden")
 
+loader: Loader
+
 direct: "DirectSession"
 
 # Set direct notify categories now that we have config

+ 2 - 1
direct/src/showbase/TkGlobal.py

@@ -37,4 +37,5 @@ del bordercolors
 
 def spawnTkLoop():
     """Alias for :meth:`base.spawnTkLoop() <.ShowBase.spawnTkLoop>`."""
-    base.spawnTkLoop()
+    from direct.showbase import ShowBaseGlobal
+    ShowBaseGlobal.base.spawnTkLoop()

+ 2 - 1
direct/src/showbase/WxGlobal.py

@@ -3,4 +3,5 @@
 
 def spawnWxLoop():
     """Alias for :meth:`base.spawnWxLoop() <.ShowBase.spawnWxLoop>`."""
-    base.spawnWxLoop()
+    from direct.showbase import ShowBaseGlobal
+    ShowBaseGlobal.base.spawnWxLoop()

+ 2 - 0
direct/src/task/MiniTask.py

@@ -12,6 +12,8 @@ class MiniTask:
     done = 0
     cont = 1
 
+    name: str
+
     def __init__(self, callback):
         self.__call__ = callback
 

+ 4 - 5
direct/src/wxwidgets/WxAppShell.py

@@ -79,13 +79,12 @@ class WxAppShell(wx.Frame):
         self.onDestroy(event)
 
         # to close Panda
-        try:
-            base
-        except NameError:
+        from direct.showbase import ShowBaseGlobal
+        if hasattr(ShowBaseGlobal, 'base'):
+            ShowBaseGlobal.base.userExit()
+        else:
             sys.exit()
 
-        base.userExit()
-
     ### USER METHODS ###
     # To be overridden
     def appInit(self):