Deprecate DirectStart and run(), allow clean ShowBase teardown, docstrings for ShowBase members

This commit is contained in:
rdb 2015-03-15 13:06:49 +01:00
parent 78c3593d2c
commit 753b1c623d
4 changed files with 123 additions and 84 deletions

View File

@ -1,4 +1,5 @@
print 'DirectStart: Starting the game.'
__all__ = []
print('Using deprecated DirectStart interface.')
from direct.showbase import ShowBase
base = ShowBase.ShowBase()

View File

@ -1,5 +1,7 @@
"""instantiate global DirectNotify used in Direct"""
__all__ = ['directNotify', 'giveNotify']
import DirectNotify
directNotify = DirectNotify.DirectNotify()

View File

@ -187,3 +187,8 @@ class EventManager:
def shutdown(self):
taskMgr.remove('eventManager')
# Flush the event queue. We do this after removing the task
# since the task removal itself might also fire off an event.
if self.eventQueue is not None:
self.eventQueue.clear()

View File

@ -14,12 +14,12 @@ from panda3d.direct import get_config_showbase, throw_new_frame, init_app_for_gu
import __builtin__
__builtin__.config = get_config_showbase()
from direct.directnotify.DirectNotifyGlobal import *
from MessengerGlobal import *
from BulletinBoardGlobal import *
from direct.task.TaskManagerGlobal import *
from JobManagerGlobal import *
from EventManagerGlobal import *
from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify
from MessengerGlobal import messenger
from BulletinBoardGlobal import bulletinBoard
from direct.task.TaskManagerGlobal import taskMgr
from JobManagerGlobal import jobMgr
from EventManagerGlobal import eventMgr
from PythonUtil import *
from direct.showbase import PythonUtil
#from direct.interval.IntervalManager import ivalMgr
@ -29,11 +29,11 @@ from direct.showbase.BufferViewer import BufferViewer
from direct.task import Task
from direct.directutil import Verify
from direct.showbase import GarbageReport
import EventManager
import math,sys,os
import Loader
import time
import gc
import atexit
from direct.fsm import ClassicFSM
from direct.fsm import State
from direct.showbase import ExceptionVarDump
@ -47,6 +47,14 @@ import AppRunnerGlobal
__builtin__.FADE_SORT_INDEX = 1000
__builtin__.NO_FADE_SORT_INDEX = 2000
def legacyRun():
__builtin__.base.notify.warning("run() is deprecated, use base.run() instead")
__builtin__.base.run()
@atexit.register
def exitfunc():
if getattr(__builtin__, 'base', None) is not None:
__builtin__.base.destroy()
# Now ShowBase is a DirectObject. We need this so ShowBase can hang
# hooks on messages, particularly on window-event. This doesn't
@ -65,11 +73,12 @@ class ShowBase(DirectObject.DirectObject):
if logStackDump or uploadStackDump:
ExceptionVarDump.install(logStackDump, uploadStackDump)
# Locate the directory containing the main program
## The directory containing the main Python file of this application.
self.mainDir = ExecutionEnvironment.getEnvironmentVariable("MAIN_DIR")
# The appRunner should have been created by the time ShowBase
# has been.
## This contains the global appRunner instance, as imported from
## AppRunnerGlobal. This will be None if we are not running in the
## runtime environment (ie. from a .p3d file).
self.appRunner = AppRunnerGlobal.appRunner
#debug running multiplier
@ -108,13 +117,13 @@ class ShowBase(DirectObject.DirectObject):
self.wantTk = False
self.wantWx = False
# Fill this in with a function to invoke when the user "exits"
# the program by closing the main window.
## Fill this in with a function to invoke when the user "exits"
## the program by closing the main window.
self.exitFunc = 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.
## 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 = []
Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
@ -139,13 +148,15 @@ class ShowBase(DirectObject.DirectObject):
# we get a window-event.
self.__oldAspectRatio = None
## This is set to the value of the window-type config variable, but may
## optionally be overridden in the Showbase constructor. Should either be
## 'onscreen' (the default), 'offscreen' or 'none'.
self.windowType = windowType
if self.windowType is None:
self.windowType = self.config.GetString('window-type', 'onscreen')
self.requireWindow = self.config.GetBool('require-window', 1)
# base.win is the main, or only window; base.winList is a list of
# *all* windows. Similarly with base.camList.
## This is the main, or only window; see winList for a list of *all* windows.
self.win = None
self.frameRateMeter = None
self.sceneGraphAnalyzerMeter = None
@ -165,17 +176,29 @@ class ShowBase(DirectObject.DirectObject):
self.trackball = None
self.texmem = None
self.showVertices = None
## This is a NodePath pointing to the Camera object set up for the 3D scene.
## This is usually a child of self.camera.
self.cam = None
self.cam2d = None
self.cam2dp = None
## This is the NodePath that should be used to manipulate the camera. This
## is the node to which the default camera is attached.
self.camera = None
self.camera2d = None
self.camera2dp = None
## This is a list of all cameras created with makeCamera, including base.cam.
self.camList = []
## Convenience accessor for base.cam.node()
self.camNode = None
## Convenience accessor for base.camNode.get_lens()
self.camLens = None
self.camFrustumVis = None
self.direct = None
## This is used to store the wx.Application object used when want-wx is
## set or base.startWx() is called.
self.wxApp = None
self.tkRoot = None
@ -189,6 +212,7 @@ class ShowBase(DirectObject.DirectObject):
self.hidden = NodePath('hidden')
## The global graphics engine, ie. GraphicsEngine.getGlobalPtr()
self.graphicsEngine = GraphicsEngine.getGlobalPtr()
self.setupRender()
self.setupRender2d()
@ -198,11 +222,11 @@ class ShowBase(DirectObject.DirectObject):
self.setupRender2dp()
# This is a placeholder for a CollisionTraverser. If someone
# stores a CollisionTraverser pointer here, we'll traverse it
# in the collisionLoop task.
self.shadowTrav = 0
## This is a placeholder for a CollisionTraverser. If someone
## stores a CollisionTraverser pointer here, we'll traverse it
## in the collisionLoop task.
self.cTrav = 0
self.shadowTrav = 0
self.cTravStack = Stack()
# Ditto for an AppTraverser.
self.appTrav = 0
@ -233,10 +257,6 @@ class ShowBase(DirectObject.DirectObject):
random.seed(seed)
#whrandom.seed(seed & 0xff, (seed >> 8) & 0xff, (seed >> 16) & 0xff)
# Now that we've set up the window structures, assign an exitfunc.
self.oldexitfunc = getattr(sys, 'exitfunc', None)
sys.exitfunc = self.exitfunc
# Open the default rendering window.
if self.windowType != 'none':
props = WindowProperties.getDefault()
@ -254,17 +274,22 @@ class ShowBase(DirectObject.DirectObject):
self.loader = Loader.Loader(self)
self.graphicsEngine.setDefaultLoader(self.loader.loader)
## The global event manager, as imported from EventManagerGlobal.
self.eventMgr = eventMgr
## The global messenger, as imported from MessengerGlobal.
self.messenger = messenger
## The global bulletin board, as imported from BulletinBoardGlobal.
self.bboard = bulletinBoard
## The global task manager, as imported from TaskManagerGlobal.
self.taskMgr = taskMgr
## The global job manager, as imported from JobManagerGlobal.
self.jobMgr = jobMgr
# Particle manager
## Particle manager
self.particleMgr = None
self.particleMgrEnabled = 0
# Physics manager
## Physics manager
self.physicsMgr = None
self.physicsMgrEnabled = 0
self.physicsMgrAngular = 0
@ -316,6 +341,8 @@ class ShowBase(DirectObject.DirectObject):
if 'base' in __builtin__.__dict__:
raise StandardError, "Attempt to spawn multiple ShowBase instances!"
# DO NOT ADD TO THIS LIST. We're trying to phase out the use of
# built-in variables by ShowBase. Use a Global module if necessary.
__builtin__.base = self
__builtin__.render2d = self.render2d
__builtin__.aspect2d = self.aspect2d
@ -331,7 +358,7 @@ class ShowBase(DirectObject.DirectObject):
__builtin__.bboard = self.bboard
# Config needs to be defined before ShowBase is constructed
#__builtin__.config = self.config
__builtin__.run = self.run
__builtin__.run = legacyRun
__builtin__.ostream = Notify.out()
__builtin__.directNotify = directNotify
__builtin__.giveNotify = giveNotify
@ -426,7 +453,7 @@ class ShowBase(DirectObject.DirectObject):
self.cTrav = self.cTravStack.pop()
def __setupProfile(self):
""" Sets up the Python profiler, if avaialable, according to
""" Sets up the Python profiler, if available, according to
some Panda config settings. """
try:
@ -445,8 +472,7 @@ class ShowBase(DirectObject.DirectObject):
return 0
def printEnvDebugInfo(self):
"""
Print some information about the environment that we are running
"""Print some information about the environment that we are running
in. Stuff like the model paths and other paths. Feel free to
add stuff to this.
"""
@ -470,11 +496,18 @@ class ShowBase(DirectObject.DirectObject):
for cb in self.finalExitCallbacks[:]:
cb()
# Remove the built-in base reference
if getattr(__builtin__, 'base', None) is self:
del __builtin__.base
del __builtin__.loader
del __builtin__.taskMgr
# [gjeon] restore sticky key settings
if self.config.GetBool('disable-sticky-keys', 0):
allowAccessibilityShortcutKeys(True)
taskMgr.destroy()
self.ignoreAll()
self.shutdown()
if getattr(self, 'musicManager', None):
self.musicManager.shutdown()
@ -501,19 +534,6 @@ class ShowBase(DirectObject.DirectObject):
vfs = VirtualFileSystem.getGlobalPtr()
vfs.unmountAll()
def exitfunc(self):
"""
This should be assigned to sys.exitfunc to be called just
before Python shutdown. It guarantees that the Panda window
is closed cleanly, so that we free system resources, restore
the desktop and keyboard functionality, etc.
"""
self.destroy()
if self.oldexitfunc:
self.oldexitfunc()
def makeDefaultPipe(self, printPipeTypes = True):
"""
Creates the default GraphicsPipe, which will be used to make
@ -1022,6 +1042,7 @@ class ShowBase(DirectObject.DirectObject):
Creates the render scene graph, the primary scene graph for
rendering 3-d geometry.
"""
## This is the root of the 3-D scene graph.
self.render = NodePath('render')
self.render.setAttrib(RescaleNormalAttrib.makeDefault())
@ -1037,6 +1058,7 @@ class ShowBase(DirectObject.DirectObject):
2-d objects and gui elements that are superimposed over the
3-d geometry in the window.
"""
## This is the root of the 2-D scene graph.
self.render2d = NodePath('render2d')
# Set up some overrides to turn off certain properties which
@ -1057,22 +1079,26 @@ class ShowBase(DirectObject.DirectObject):
self.render2d.setMaterialOff(1)
self.render2d.setTwoSided(1)
# The normal 2-d DisplayRegion has an aspect ratio that
# matches the window, but its coordinate system is square.
# This means anything we parent to render2d gets stretched.
# For things where that makes a difference, we set up
# aspect2d, which scales things back to the right aspect
# ratio.
aspectRatio = self.getAspectRatio()
## The normal 2-d DisplayRegion has an aspect ratio that
## matches the window, but its coordinate system is square.
## This means anything we parent to render2d gets stretched.
## For things where that makes a difference, we set up
## aspect2d, which scales things back to the right aspect
## ratio along the X axis (Z is still from -1 to 1)
self.aspect2d = self.render2d.attachNewNode(PGTop("aspect2d"))
aspectRatio = self.getAspectRatio()
self.aspect2d.setScale(1.0 / aspectRatio, 1.0, 1.0)
self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")
# It's important to know the bounds of the aspect2d screen.
## The Z position of the top border of the aspect2d screen.
self.a2dTop = 1.0
## The Z position of the bottom border of the aspect2d screen.
self.a2dBottom = -1.0
## The X position of the left border of the aspect2d screen.
self.a2dLeft = -aspectRatio
## The X position of the right border of the aspect2d screen.
self.a2dRight = aspectRatio
self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
@ -1112,12 +1138,12 @@ class ShowBase(DirectObject.DirectObject):
self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)
# This special root, pixel2d, uses units in pixels that are relative
# to the window. The upperleft corner of the window is (0, 0),
# the lowerleft corner is (xsize, -ysize), in this coordinate system.
xsize, ysize = self.getSize()
## This special root, pixel2d, uses units in pixels that are relative
## to the window. The upperleft corner of the window is (0, 0),
## the lowerleft corner is (xsize, -ysize), in this coordinate system.
self.pixel2d = self.render2d.attachNewNode(PGTop("pixel2d"))
self.pixel2d.setPos(-1, 0, 1)
xsize, ysize = self.getSize()
if xsize > 0 and ysize > 0:
self.pixel2d.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
@ -1144,25 +1170,27 @@ class ShowBase(DirectObject.DirectObject):
self.render2dp.setMaterialOff(1)
self.render2dp.setTwoSided(1)
# The normal 2-d DisplayRegion has an aspect ratio that
# matches the window, but its coordinate system is square.
# This means anything we parent to render2d gets stretched.
# For things where that makes a difference, we set up
# aspect2d, which scales things back to the right aspect
# ratio.
aspectRatio = self.getAspectRatio()
## The normal 2-d DisplayRegion has an aspect ratio that
## matches the window, but its coordinate system is square.
## This means anything we parent to render2dp gets stretched.
## For things where that makes a difference, we set up
## aspect2dp, which scales things back to the right aspect
## ratio along the X axis (Z is still from -1 to 1)
self.aspect2dp = self.render2dp.attachNewNode(PGTop("aspect2dp"))
self.aspect2dp.node().setStartSort(16384)
aspectRatio = self.getAspectRatio()
self.aspect2dp.setScale(1.0 / aspectRatio, 1.0, 1.0)
# It's important to know the bounds of the aspect2d screen.
## The Z position of the top border of the aspect2dp screen.
self.a2dpTop = 1.0
## The Z position of the bottom border of the aspect2dp screen.
self.a2dpBottom = -1.0
## The X position of the left border of the aspect2dp screen.
self.a2dpLeft = -aspectRatio
## The X position of the right border of the aspect2dp screen.
self.a2dpRight = aspectRatio
self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
self.a2dpBottomCenter = self.aspect2dp.attachNewNode("a2dpBottomCenter")
self.a2dpLeftCenter = self.aspect2dp.attachNewNode("a2dpLeftCenter")
@ -1184,13 +1212,13 @@ class ShowBase(DirectObject.DirectObject):
self.a2dpBottomLeft.setPos(self.a2dpLeft, 0, self.a2dpBottom)
self.a2dpBottomRight.setPos(self.a2dpRight, 0, self.a2dpBottom)
# This special root, pixel2d, uses units in pixels that are relative
# to the window. The upperleft corner of the window is (0, 0),
# the lowerleft corner is (xsize, -ysize), in this coordinate system.
xsize, ysize = self.getSize()
## This special root, pixel2d, uses units in pixels that are relative
## to the window. The upperleft corner of the window is (0, 0),
## the lowerleft corner is (xsize, -ysize), in this coordinate system.
self.pixel2dp = self.render2dp.attachNewNode(PGTop("pixel2dp"))
self.pixel2dp.node().setStartSort(16384)
self.pixel2dp.setPos(-1, 0, 1)
xsize, ysize = self.getSize()
if xsize > 0 and ysize > 0:
self.pixel2dp.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
@ -1502,12 +1530,14 @@ class ShowBase(DirectObject.DirectObject):
np = mw.getParent().attachNewNode(mouseRecorder)
mw.reparentTo(np)
# A special ButtonThrower to generate keyboard events and
# include the time from the OS. This is separate only to
# support legacy code that did not expect a time parameter; it
# will eventually be folded into the normal ButtonThrower,
# above.
mw = self.buttonThrowers[0].getParent()
## A special ButtonThrower to generate keyboard events and
## include the time from the OS. This is separate only to
## support legacy code that did not expect a time parameter; it
## will eventually be folded into the normal ButtonThrower,
## above.
self.timeButtonThrower = mw.attachNewNode(ButtonThrower('timeButtons'))
self.timeButtonThrower.node().setPrefix('time-')
self.timeButtonThrower.node().setTimeFlag(1)
@ -1931,7 +1961,7 @@ class ShowBase(DirectObject.DirectObject):
throw_new_frame()
return Task.cont
def restart(self,clusterSync=False,cluster=None):
def restart(self, clusterSync=False, cluster=None):
self.shutdown()
# __resetPrevTransform goes at the very beginning of the frame.
self.taskMgr.add(
@ -1970,7 +2000,7 @@ class ShowBase(DirectObject.DirectObject):
self.taskMgr.remove('dataLoop')
self.taskMgr.remove('resetPrevTransform')
self.taskMgr.remove('ivalLoop')
self.taskMgr.remove('garbage_collect')
self.taskMgr.remove('garbageCollectStates')
self.eventMgr.shutdown()
def getBackgroundColor(self, win = None):
@ -2931,11 +2961,12 @@ class ShowBase(DirectObject.DirectObject):
self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx)
def run(self):
# This method runs the TaskManager when self.appRunner is
# None, which is to say, when we are not running from within a
# p3d file. When we *are* within a p3d file, the Panda
# runtime has to be responsible for running the main loop, so
# we can't allow the application to do it.
""" This method runs the TaskManager when self.appRunner is
None, which is to say, when we are not running from within a
p3d file. When we *are* within a p3d file, the Panda
runtime has to be responsible for running the main loop, so
we can't allow the application to do it. """
if self.appRunner is None or self.appRunner.dummy or \
(self.appRunner.interactiveConsole and not self.appRunner.initialAppImport):
self.taskMgr.run()