|
|
@@ -32,6 +32,8 @@ built-in scope.
|
|
|
|
|
|
"""
|
|
|
|
|
|
+from __future__ import annotations
|
|
|
+
|
|
|
__all__ = ['ShowBase', 'WindowControls']
|
|
|
|
|
|
# This module redefines the builtin import function with one
|
|
|
@@ -71,9 +73,11 @@ from panda3d.core import (
|
|
|
GraphicsPipe,
|
|
|
GraphicsPipeSelection,
|
|
|
GraphicsWindow,
|
|
|
+ InputDevice,
|
|
|
InputDeviceManager,
|
|
|
InputDeviceNode,
|
|
|
KeyboardButton,
|
|
|
+ Lens,
|
|
|
LensNode,
|
|
|
Mat4,
|
|
|
ModelNode,
|
|
|
@@ -118,9 +122,11 @@ from . import DConfig
|
|
|
from direct.extensions_native import NodePath_extensions # pylint: disable=unused-import
|
|
|
|
|
|
# This needs to be available early for DirectGUI imports
|
|
|
+from typing import Any
|
|
|
+builtins: Any # Tell mypy not to worry about us setting attributes on builtins
|
|
|
import sys
|
|
|
import builtins
|
|
|
-builtins.config = DConfig # type: ignore[attr-defined]
|
|
|
+builtins.config = DConfig
|
|
|
|
|
|
from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify
|
|
|
from direct.directnotify.Notifier import Notifier
|
|
|
@@ -141,7 +147,7 @@ import importlib
|
|
|
from direct.showbase import ExceptionVarDump
|
|
|
from . import DirectObject
|
|
|
from . import SfxPlayer
|
|
|
-from typing import ClassVar, Optional
|
|
|
+from typing import Callable, ClassVar, Literal, NoReturn
|
|
|
if __debug__:
|
|
|
from direct.showbase import GarbageReport
|
|
|
from direct.directutil import DeltaProfiler
|
|
|
@@ -150,9 +156,10 @@ if __debug__:
|
|
|
|
|
|
|
|
|
@atexit.register
|
|
|
-def exitfunc():
|
|
|
- if getattr(builtins, 'base', None) is not None:
|
|
|
- builtins.base.destroy()
|
|
|
+def exitfunc() -> None:
|
|
|
+ base = getattr(builtins, 'base', None)
|
|
|
+ if base is not None:
|
|
|
+ base.destroy()
|
|
|
|
|
|
# Now ShowBase is a DirectObject. We need this so ShowBase can hang
|
|
|
# hooks on messages, particularly on window-event. This doesn't
|
|
|
@@ -170,7 +177,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
aspect2d: NodePath
|
|
|
pixel2d: NodePath
|
|
|
|
|
|
- def __init__(self, fStartDirect=True, windowType=None):
|
|
|
+ def __init__(self, fStartDirect: bool = True, windowType: str | None = None) -> None:
|
|
|
"""Opens a window, sets up a 3-D and several 2-D scene graphs, and
|
|
|
everything else needed to render the scene graph to the window.
|
|
|
|
|
|
@@ -233,10 +240,10 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
self.wantRender2dp = ConfigVariableBool('want-render2dp', True).value
|
|
|
|
|
|
self.screenshotExtension = ConfigVariableString('screenshot-extension', 'jpg').value
|
|
|
- self.musicManager = None
|
|
|
- self.musicManagerIsValid = None
|
|
|
- self.sfxManagerList = []
|
|
|
- self.sfxManagerIsValidList = []
|
|
|
+ self.musicManager: AudioManager | None = None
|
|
|
+ self.musicManagerIsValid: bool | None = None
|
|
|
+ self.sfxManagerList: list[AudioManager] = []
|
|
|
+ self.sfxManagerIsValidList: list[bool] = []
|
|
|
|
|
|
self.wantStats = ConfigVariableBool('want-pstats', False).value
|
|
|
self.wantTk = False
|
|
|
@@ -245,12 +252,12 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
|
|
|
#: Fill this in with a function to invoke when the user "exits"
|
|
|
#: the program by closing the main window.
|
|
|
- self.exitFunc = None
|
|
|
+ self.exitFunc: Callable[[], object] | None = None
|
|
|
|
|
|
#: Add final-exit callbacks to this list. These will be called
|
|
|
#: when sys.exit() is called, after Panda has unloaded, and
|
|
|
#: just before Python is about to shut down.
|
|
|
- self.finalExitCallbacks = []
|
|
|
+ self.finalExitCallbacks: list[Callable[[], object]] = []
|
|
|
|
|
|
# Set up the TaskManager to reset the PStats clock back
|
|
|
# whenever we resume from a pause. This callback function is
|
|
|
@@ -268,7 +275,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
self.__configAspectRatio = ConfigVariableDouble('aspect-ratio', 0).value
|
|
|
# This variable is used to see if the aspect ratio has changed when
|
|
|
# we get a window-event.
|
|
|
- self.__oldAspectRatio = None
|
|
|
+ self.__oldAspectRatio: float | None = None
|
|
|
|
|
|
#: This is set to the value of the window-type config variable, but may
|
|
|
#: optionally be overridden in the Showbase constructor. Should either
|
|
|
@@ -279,68 +286,68 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
self.requireWindow = ConfigVariableBool('require-window', True).value
|
|
|
|
|
|
#: This is the main, or only window; see `winList` for a list of *all* windows.
|
|
|
- self.win = None
|
|
|
- self.frameRateMeter = None
|
|
|
- self.sceneGraphAnalyzerMeter = None
|
|
|
+ self.win: GraphicsOutput | None = None
|
|
|
+ self.frameRateMeter: FrameRateMeter | None = None
|
|
|
+ self.sceneGraphAnalyzerMeter: SceneGraphAnalyzerMeter | None = None
|
|
|
#: A list of all windows opened via `openWindow()`.
|
|
|
- self.winList = []
|
|
|
- self.winControls = []
|
|
|
- self.mainWinMinimized = 0
|
|
|
- self.mainWinForeground = 0
|
|
|
+ self.winList: list[GraphicsEngine] = []
|
|
|
+ self.winControls: list[WindowControls] = []
|
|
|
+ self.mainWinMinimized = False
|
|
|
+ self.mainWinForeground = False
|
|
|
#: Contains the :class:`~panda3d.core.GraphicsPipe` object created by
|
|
|
#: `makeDefaultPipe()`.
|
|
|
- self.pipe = None
|
|
|
+ self.pipe: GraphicsPipe | None = None
|
|
|
#: The full list of :class:`~panda3d.core.GraphicsPipe` objects,
|
|
|
#: including any auxiliary pipes. Filled by `makeAllPipes()`.
|
|
|
- self.pipeList = []
|
|
|
- self.mouse2cam = None
|
|
|
- self.buttonThrowers = None
|
|
|
- self.mouseWatcher = None
|
|
|
+ self.pipeList: list[GraphicsPipe] = []
|
|
|
+ self.mouse2cam: NodePath | None = None
|
|
|
+ self.buttonThrowers: list[ButtonThrower] | None = None
|
|
|
+ self.mouseWatcher: NodePath | None = None
|
|
|
#: The :class:`~panda3d.core.MouseWatcher` object, created by
|
|
|
#: `setupMouse()`.
|
|
|
- self.mouseWatcherNode = None
|
|
|
- self.pointerWatcherNodes = None
|
|
|
- self.mouseInterface = None
|
|
|
- self.drive = None
|
|
|
- self.trackball = None
|
|
|
- self.texmem = None
|
|
|
- self.showVertices = None
|
|
|
- self.deviceButtonThrowers = []
|
|
|
+ self.mouseWatcherNode: MouseWatcher | None = None
|
|
|
+ self.pointerWatcherNodes: list[MouseWatcher] | None = None
|
|
|
+ self.mouseInterface: NodePath | None = None
|
|
|
+ self.drive: NodePath | None = None
|
|
|
+ self.trackball: NodePath | None = None
|
|
|
+ self.texmem: Any | None = None
|
|
|
+ self.showVertices: NodePath | None = None
|
|
|
+ self.deviceButtonThrowers: list[NodePath] = []
|
|
|
|
|
|
#: This is a :class:`~panda3d.core.NodePath` pointing to the
|
|
|
#: :class:`~panda3d.core.Camera` object set up for the 3D scene.
|
|
|
#: Usually a child of `camera`.
|
|
|
- self.cam = None
|
|
|
+ self.cam: NodePath | None = None
|
|
|
#: Same as `cam`, but for the 2D scene graph.
|
|
|
- self.cam2d = None
|
|
|
+ self.cam2d: NodePath | None = None
|
|
|
#: Same as `cam2d`, but for the 2D overlay scene graph.
|
|
|
- self.cam2dp = None
|
|
|
+ self.cam2dp: NodePath | None = None
|
|
|
|
|
|
#: This is the :class:`~panda3d.core.NodePath` that should be used to
|
|
|
#: manipulate the camera. It points at the node to which the default
|
|
|
#: camera (`cam`, `camNode`) is attached.
|
|
|
- self.camera = None
|
|
|
+ self.camera: NodePath | None = None
|
|
|
#: Same as `camera`, but for the 2D scene graph. Parent of `cam2d`.
|
|
|
- self.camera2d = None
|
|
|
+ self.camera2d: NodePath | None = None
|
|
|
#: Same as `camera2d`, but for the 2D overlay scene graph. Parent of
|
|
|
#: `cam2dp`.
|
|
|
- self.camera2dp = None
|
|
|
+ self.camera2dp: NodePath | None = None
|
|
|
|
|
|
#: A list of all cameras created with `makeCamera()`, including `cam`.
|
|
|
- self.camList = []
|
|
|
+ self.camList: list[NodePath] = []
|
|
|
#: Convenience accessor for base.cam.node(), containing a
|
|
|
#: :class:`~panda3d.core.Camera` object.
|
|
|
- self.camNode = None
|
|
|
+ self.camNode: Camera | None = None
|
|
|
#: Convenience accessor for base.camNode.get_lens(), containing a
|
|
|
#: :class:`~panda3d.core.Lens` object.
|
|
|
- self.camLens = None
|
|
|
- self.camFrustumVis = None
|
|
|
+ self.camLens: Lens | None = None
|
|
|
+ self.camFrustumVis: NodePath | None = None
|
|
|
self.direct = None
|
|
|
#: This is used to store the wx.Application object used when want-wx is
|
|
|
#: set or `startWx()` is called.
|
|
|
- self.wxApp = None
|
|
|
+ self.wxApp: Any | None = None
|
|
|
self.wxAppCreated = False
|
|
|
- self.tkRoot = None
|
|
|
+ self.tkRoot: Any | None = None
|
|
|
self.tkRootCreated = False
|
|
|
|
|
|
# This is used for syncing multiple PCs in a distributed cluster
|
|
|
@@ -371,11 +378,11 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
#: traverse it automatically in the collisionLoop task, so you won't
|
|
|
#: need to call :meth:`~panda3d.core.CollisionTraverser.traverse()`
|
|
|
#: yourself every frame.
|
|
|
- self.cTrav = 0
|
|
|
- self.shadowTrav = 0
|
|
|
+ self.cTrav: CollisionTraverser | Literal[0] = 0
|
|
|
+ self.shadowTrav: CollisionTraverser | Literal[0] = 0
|
|
|
self.cTravStack = Stack()
|
|
|
# Ditto for an AppTraverser.
|
|
|
- self.appTrav = 0
|
|
|
+ self.appTrav: Any | Literal[0] = 0
|
|
|
|
|
|
# This is the DataGraph traverser, which we might as well
|
|
|
# create now.
|
|
|
@@ -383,7 +390,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
|
|
|
# Maybe create a RecorderController to record and/or play back
|
|
|
# the user session.
|
|
|
- self.recorder = None
|
|
|
+ self.recorder: RecorderController | None = None
|
|
|
playbackSession = ConfigVariableFilename('playback-session', '')
|
|
|
recordSession = ConfigVariableFilename('record-session', '')
|
|
|
if not playbackSession.empty():
|
|
|
@@ -448,22 +455,22 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
#: If `enableParticles()` has been called, this is the particle manager
|
|
|
#: as imported from :mod:`direct.particles.ParticleManagerGlobal`.
|
|
|
self.particleMgr = None
|
|
|
- self.particleMgrEnabled = 0
|
|
|
+ self.particleMgrEnabled = False
|
|
|
|
|
|
#: If `enableParticles()` has been called, this is the physics manager
|
|
|
#: as imported from :mod:`direct.showbase.PhysicsManagerGlobal`.
|
|
|
self.physicsMgr = None
|
|
|
- self.physicsMgrEnabled = 0
|
|
|
- self.physicsMgrAngular = 0
|
|
|
+ self.physicsMgrEnabled = False
|
|
|
+ self.physicsMgrAngular = False
|
|
|
|
|
|
#: This is the global :class:`~panda3d.core.InputDeviceManager`, which
|
|
|
#: keeps track of connected input devices.
|
|
|
self.devices = InputDeviceManager.getGlobalPtr()
|
|
|
- self.__inputDeviceNodes = {}
|
|
|
+ self.__inputDeviceNodes: dict[InputDevice, NodePath] = {}
|
|
|
|
|
|
self.createStats()
|
|
|
|
|
|
- self.AppHasAudioFocus = 1
|
|
|
+ self.AppHasAudioFocus = True
|
|
|
|
|
|
# Get a pointer to Panda's global ClockObject, used for
|
|
|
# synchronizing events between Python and C.
|
|
|
@@ -502,7 +509,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
affinity = ConfigVariableInt('client-cpu-affinity', -1).value
|
|
|
if (affinity in (None, -1)) and autoAffinity:
|
|
|
affinity = 0
|
|
|
- if affinity not in (None, -1):
|
|
|
+ if affinity is not None and affinity != -1:
|
|
|
# Windows XP supports a 32-bit affinity mask
|
|
|
TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 32))
|
|
|
|
|
|
@@ -575,7 +582,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
# Now hang a hook on the window-event from Panda. This allows
|
|
|
# us to detect when the user resizes, minimizes, or closes the
|
|
|
# main window.
|
|
|
- self.__prevWindowProperties = None
|
|
|
+ self.__prevWindowProperties: WindowProperties | None = None
|
|
|
self.__directObject.accept('window-event', self.windowEvent)
|
|
|
|
|
|
# Transition effects (fade, iris, etc)
|
|
|
@@ -658,7 +665,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
#print getDnaPath()
|
|
|
print("}")
|
|
|
|
|
|
- def destroy(self):
|
|
|
+ def destroy(self) -> None:
|
|
|
""" Call this function to destroy the ShowBase and stop all
|
|
|
its tasks, freeing all of the Panda resources. Normally, you
|
|
|
should not need to call it explicitly, as it is bound to the
|
|
|
@@ -704,6 +711,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
self.shutdown()
|
|
|
|
|
|
if getattr(self, 'musicManager', None):
|
|
|
+ assert self.musicManager is not None
|
|
|
self.musicManager.shutdown()
|
|
|
self.musicManager = None
|
|
|
for sfxManager in self.sfxManagerList:
|
|
|
@@ -711,12 +719,12 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
self.sfxManagerList = []
|
|
|
if getattr(self, 'loader', None):
|
|
|
self.loader.destroy()
|
|
|
- self.loader = None
|
|
|
+ del self.loader
|
|
|
if getattr(self, 'graphicsEngine', None):
|
|
|
self.graphicsEngine.removeAllWindows()
|
|
|
|
|
|
try:
|
|
|
- self.direct.panel.destroy()
|
|
|
+ self.direct.panel.destroy() # type: ignore[attr-defined]
|
|
|
except Exception:
|
|
|
pass
|
|
|
|
|
|
@@ -1185,7 +1193,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
self.setSceneGraphAnalyzerMeter(flag.value)
|
|
|
return success
|
|
|
|
|
|
- def setSleep(self, amount):
|
|
|
+ def setSleep(self, amount: float) -> None:
|
|
|
"""
|
|
|
Sets up a task that calls python 'sleep' every frame. This is a simple
|
|
|
way to reduce the CPU usage (and frame rate) of a panda program.
|
|
|
@@ -1205,7 +1213,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
#time.sleep(self.clientSleep)
|
|
|
return Task.cont
|
|
|
|
|
|
- def setFrameRateMeter(self, flag):
|
|
|
+ def setFrameRateMeter(self, flag: bool) -> None:
|
|
|
"""
|
|
|
Turns on or off (according to flag) a standard frame rate
|
|
|
meter in the upper-right corner of the main window.
|
|
|
@@ -1219,7 +1227,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
self.frameRateMeter.clearWindow()
|
|
|
self.frameRateMeter = None
|
|
|
|
|
|
- def setSceneGraphAnalyzerMeter(self, flag):
|
|
|
+ def setSceneGraphAnalyzerMeter(self, flag: bool) -> None:
|
|
|
"""
|
|
|
Turns on or off (according to flag) a standard frame rate
|
|
|
meter in the upper-right corner of the main window.
|
|
|
@@ -1242,7 +1250,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
mouseKeyboard = self.dataRoot.find("**/*"))
|
|
|
self.winControls.append(winCtrl)
|
|
|
|
|
|
- def setupRender(self):
|
|
|
+ def setupRender(self) -> None:
|
|
|
"""
|
|
|
Creates the render scene graph, the primary scene graph for
|
|
|
rendering 3-d geometry.
|
|
|
@@ -1252,11 +1260,11 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
self.render.setAttrib(RescaleNormalAttrib.makeDefault())
|
|
|
|
|
|
self.render.setTwoSided(0)
|
|
|
- self.backfaceCullingEnabled = 1
|
|
|
- self.textureEnabled = 1
|
|
|
- self.wireframeEnabled = 0
|
|
|
+ self.backfaceCullingEnabled = True
|
|
|
+ self.textureEnabled = True
|
|
|
+ self.wireframeEnabled = False
|
|
|
|
|
|
- def setupRender2d(self):
|
|
|
+ def setupRender2d(self) -> None:
|
|
|
"""
|
|
|
Creates the render2d scene graph, the primary scene graph for
|
|
|
2-d objects and gui elements that are superimposed over the
|
|
|
@@ -1355,7 +1363,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
if xsize > 0 and ysize > 0:
|
|
|
self.pixel2d.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
|
|
|
|
|
|
- def setupRender2dp(self):
|
|
|
+ def setupRender2dp(self) -> None:
|
|
|
"""
|
|
|
Creates a render2d scene graph, the secondary scene graph for
|
|
|
2-d objects and gui elements that are superimposed over the
|
|
|
@@ -1677,7 +1685,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
|
|
|
return camera2dp
|
|
|
|
|
|
- def setupDataGraph(self):
|
|
|
+ def setupDataGraph(self) -> None:
|
|
|
"""
|
|
|
Creates the data graph and populates it with the basic input
|
|
|
devices.
|
|
|
@@ -2006,7 +2014,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
self.physicsMgr.doPhysics(dt)
|
|
|
return Task.cont
|
|
|
|
|
|
- def createStats(self, hostname=None, port=None):
|
|
|
+ def createStats(self, hostname: str | None = None, port: int | None = None) -> bool:
|
|
|
"""
|
|
|
If want-pstats is set in Config.prc, or the `wantStats` member is
|
|
|
otherwise set to True, connects to the PStats server.
|
|
|
@@ -2323,7 +2331,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
throw_new_frame()
|
|
|
return Task.cont
|
|
|
|
|
|
- def restart(self, clusterSync=False, cluster=None):
|
|
|
+ def restart(self, clusterSync: bool = False, cluster=None) -> None:
|
|
|
self.shutdown()
|
|
|
# __resetPrevTransform goes at the very beginning of the frame.
|
|
|
self.taskMgr.add(
|
|
|
@@ -2354,7 +2362,7 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
self.taskMgr.add(self.__audioLoop, 'audioLoop', sort = 60)
|
|
|
self.eventMgr.restart()
|
|
|
|
|
|
- def shutdown(self):
|
|
|
+ def shutdown(self) -> None:
|
|
|
self.taskMgr.remove('audioLoop')
|
|
|
self.taskMgr.remove('igLoop')
|
|
|
self.taskMgr.remove('shadowCollisionLoop')
|
|
|
@@ -3195,14 +3203,14 @@ class ShowBase(DirectObject.DirectObject):
|
|
|
# If anybody needs to update their GUI, put a callback on this event
|
|
|
messenger.send("aspectRatioChanged")
|
|
|
|
|
|
- def userExit(self):
|
|
|
+ def userExit(self) -> NoReturn:
|
|
|
# The user has requested we exit the program. Deal with this.
|
|
|
if self.exitFunc:
|
|
|
self.exitFunc()
|
|
|
self.notify.info("Exiting ShowBase.")
|
|
|
self.finalizeExit()
|
|
|
|
|
|
- def finalizeExit(self):
|
|
|
+ def finalizeExit(self) -> NoReturn:
|
|
|
"""
|
|
|
Called by `userExit()` to quit the application. The default
|
|
|
implementation just calls `sys.exit()`.
|