| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753 |
- # This module redefines the builtin import function with one
- # that prints out every import it does in a hierarchical form
- # Annoying and very noisy, but sometimes useful
- # import VerboseImport
- from PandaModules import *
- from DirectNotifyGlobal import *
- from MessengerGlobal import *
- from TaskManagerGlobal import *
- from EventManagerGlobal import *
- from PythonUtil import *
- from ParticleManagerGlobal import *
- from PhysicsManagerGlobal import *
- import Task
- import EventManager
- import math
- import sys
- import Transitions
- import Loader
- import time
- import FSM
- import State
- import __builtin__
- __builtin__.FADE_SORT_INDEX = 1000
- __builtin__.NO_FADE_SORT_INDEX = 2000
- globalClock = ClockObject.getGlobalClock()
- class ShowBase:
- notify = directNotify.newCategory("ShowBase")
- def __init__(self):
- # Get the dconfig object
- self.config = ConfigConfigureGetConfigConfigShowbase
- # Store dconfig variables
- self.wantTk = self.config.GetBool('want-tk', 0)
- self.wantAnySound = self.config.GetBool('want-sound', 1)
- self.wantSfx = self.config.GetBool('audio-sfx-active', 1)
- self.wantMusic = self.config.GetBool('audio-music-active', 1)
- self.wantFog = self.config.GetBool('want-fog', 1)
- if not (self.wantSfx or self.wantMusic):
- self.wantAnySound = None
- if not self.wantAnySound:
- self.wantSfx = None
- self.wantMusic = None
- self.musicManager = None
- self.sfxManager = None
- self.wantDIRECT = self.config.GetBool('want-directtools', 0)
- self.wantStats = self.config.GetBool('want-stats', 0)
- taskMgr.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
- taskMgr.pStatsTasks = self.config.GetBool('pstats-tasks', 0)
- # Set up the TaskManager to reset the PStats clock back
- # whenever we resume from a pause. This callback function is
- # a little hacky, but we can't call it directly from within
- # the TaskManager because he doesn't know about PStats (and
- # has to run before libpanda is even loaded).
- taskMgr.resumeFunc = PStatClient.resumeAfterPause
- fsmRedefine = self.config.GetBool('fsm-redefine', 0)
- State.FsmRedefine = fsmRedefine
- self.renderTop = NodePath(NamedNode('renderTop'))
- self.render = self.renderTop.attachNewNode('render')
- # Set a default "off color" (i.e. use poly color) for color transitions
- self.render.setColorOff()
- self.hidden = NodePath(NamedNode('hidden'))
-
- self.dataRoot = NodePath(NamedNode('dataRoot'), DataRelation.getClassType())
- # Cache the node so we do not ask for it every frame
- self.dataRootNode = self.dataRoot.node()
- self.dataUnused = NodePath(NamedNode('dataUnused'), DataRelation.getClassType())
- self.pipe = makeGraphicsPipe()
- chanConfig = makeGraphicsWindow(self.pipe, self.render.arc())
- self.win = chanConfig.getWin()
- # Now that we've assigned a window, assign an exitfunc.
- self.oldexitfunc = getattr(sys, 'exitfunc', None)
- sys.exitfunc = self.exitfunc
- # cameraList is a list of camera group nodes. There may
- # be more than one display region/camera node beneath each
- # one.
- self.cameraList = []
- for i in range(chanConfig.getNumGroups()):
- self.cameraList.append(self.render.attachNewNode(
- chanConfig.getGroupNode(i)))
- # this is how we know which display region cameras belong to which
- # camera group. display region i belongs to group self.groupList[i]
- self.groupList = []
- for i in range(chanConfig.getNumDrs()):
- self.groupList.append(chanConfig.getGroupMembership(i))
- self.camera = self.cameraList[0]
- # This is a placeholder for a CollisionTraverser. If someone
- # stores a CollisionTraverser pointer here, we'll traverse it
- # in the igloop task.
- self.cTrav = 0
- # This is a list of cams associated with the display region's cameras
- self.camList = []
- for camera in self.cameraList:
- self.camList.append( camera.find('**/+Camera') )
- # Set the default camera
- self.cam = self.camera.find('**/+Camera')
- # If you need to get a handle to the camera node itself, use
- # self.camNode.
- self.camNode = self.cam.node()
- # If you need to adjust camera parameters, like fov or
- # near/far clipping planes, use self.camLens
- self.camLens = self.camNode.getLens()
- # Set up a 2-d layer for drawing things behind Gui labels.
- self.render2d = NodePath(setupPanda2d(self.win, "render2d"))
- # The normal 2-d layer 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.
- # For now, we assume that the window will have an aspect ratio
- # matching that of a traditional PC screen.
- self.aspectRatio = 4.0 / 3.0
- self.aspect2d = self.render2d.attachNewNode(PGTop("aspect2d"))
- self.aspect2d.setScale(1.0 / self.aspectRatio, 1.0, 1.0)
- # And let's enforce that aspect ratio on the camera.
- self.camLens.setAspectRatio(self.aspectRatio)
- # It's important to know the bounds of the aspect2d screen.
- self.a2dTop = 1.0
- self.a2dBottom = -1.0
- self.a2dLeft = -self.aspectRatio
- self.a2dRight = self.aspectRatio
- # We create both a MouseAndKeyboard object and a MouseWatcher object
- # for the window. The MouseAndKeyboard generates mouse events and
- # mouse button/keyboard events; the MouseWatcher passes them through
- # unchanged when the mouse is not over a 2-d button, and passes
- # nothing through when the mouse *is* over a 2-d button. Therefore,
- # objects that don't want to get events when the mouse is over a
- # button, like the driveInterface, should be parented to
- # mouseWatcher, while objects that want events in all cases, like the
- # chat interface, should be parented to mak.
- self.mak = self.dataRoot.attachNewNode(MouseAndKeyboard(self.win, 0, 'mak'))
- self.mouseWatcherNode = MouseWatcher('mouseWatcher')
- self.mouseWatcher = self.mak.attachNewNode(self.mouseWatcherNode)
- mb = self.mouseWatcherNode.getModifierButtons()
- mb.addButton(KeyboardButton.shift())
- mb.addButton(KeyboardButton.control())
- mb.addButton(KeyboardButton.alt())
- self.mouseWatcherNode.setModifierButtons(mb)
- # We also create a DataValve object above the trackball/drive
- # interface, which will allow us to switch some of the mouse
- # control, without switching all of it, to another object
- # later (for instance, to enable OOBE mode--see oobe(),
- # below.)
- self.mouseValve = self.mouseWatcher.attachNewNode(DataValve('mouseValve'))
- # This Control object can be used to turn on and off mouse &
- # keyboard messages to the DriveInterface.
- self.mouseControl = DataValve.Control()
- self.mouseValve.node().setControl(0, self.mouseControl)
- # This Control object is always kept on, handy to have.
- self.onControl = DataValve.Control()
- # Now we have the main trackball & drive interfaces.
- # useTrackball() and useDrive() switch these in and out; only
- # one is in use at a given time.
- self.trackball = self.dataUnused.attachNewNode(Trackball('trackball'))
- self.drive = self.dataUnused.attachNewNode(DriveInterface('drive'))
- self.mouse2cam = self.dataUnused.attachNewNode(Transform2SG('mouse2cam'))
- self.mouse2cam.node().setArc(self.camera.arc())
- self.useDrive()
- self.buttonThrower = self.mouseWatcher.attachNewNode(ButtonThrower())
- # Set up gui mouse watcher
- self.aspect2d.node().setMouseWatcher(self.mouseWatcherNode)
- self.mouseWatcherNode.addRegion(PGMouseWatcherBackground())
- self.loader = Loader.Loader(self)
- self.eventMgr = eventMgr
- self.messenger = messenger
- self.taskMgr = taskMgr
- # Particle manager
- self.particleMgr = particleMgr
- self.particleMgr.setFrameStepping(1)
- self.particleMgrEnabled = 0
- # Physics manager
- self.physicsMgr = physicsMgr
- integrator = LinearEulerIntegrator()
- self.physicsMgr.attachLinearIntegrator(integrator)
- self.physicsMgrEnabled = 0
- self.physicsMgrAngular = 0
- self.createAudioManager()
- self.createStats()
- # Transition effects (fade, iris, etc)
- self.transitions = Transitions.Transitions(self.loader)
- self.AppHasAudioFocus = 1
- __builtin__.base = self
- __builtin__.render2d = self.render2d
- __builtin__.aspect2d = self.aspect2d
- __builtin__.render = self.render
- __builtin__.hidden = self.hidden
- __builtin__.camera = self.camera
- __builtin__.loader = self.loader
- __builtin__.taskMgr = self.taskMgr
- __builtin__.eventMgr = self.eventMgr
- __builtin__.messenger = self.messenger
- __builtin__.config = self.config
- __builtin__.run = self.run
- __builtin__.ostream = Notify.out()
- __builtin__.directNotify = directNotify
- # Tk
- if self.wantTk:
- import TkGlobal
- if self.wantDIRECT:
- import DirectSession
- direct.enable()
- else:
- __builtin__.direct = self.direct = None
- self.restart()
- def exitfunc(self):
- """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.win.closeWindow()
- del self.win
- del self.pipe
- if self.oldexitfunc:
- self.oldexitfunc()
- def getAlt(self):
- return base.mouseWatcherNode.getModifierButtons().isDown(
- KeyboardButton.alt())
- def getShift(self):
- return base.mouseWatcherNode.getModifierButtons().isDown(
- KeyboardButton.shift())
- def getControl(self):
- return base.mouseWatcherNode.getModifierButtons().isDown(
- KeyboardButton.control())
- def addAngularIntegrator(self):
- """addAngularIntegrator(self)"""
- if (self.physicsMgrAngular == 0):
- self.physicsMgrAngular = 1
- integrator = AngularEulerIntegrator()
- self.physicsMgr.attachAngularIntegrator(integrator)
- def enableParticles(self):
- """enableParticles(self)"""
- self.particleMgrEnabled = 1
- self.physicsMgrEnabled = 1
- self.taskMgr.removeTasksNamed('manager-update')
- self.taskMgr.spawnTaskNamed(Task.Task(self.updateManagers),
- 'manager-update')
- def disableParticles(self):
- """enableParticles(self)"""
- self.particleMgrEnabled = 0
- self.physicsMgrEnabled = 0
- self.taskMgr.removeTasksNamed('manager-update')
- def toggleParticles(self):
- if self.particleMgrEnabled == 0:
- self.enableParticles()
- else:
- self.disableParticles()
- def isParticleMgrEnabled(self):
- return self.particleMgrEnabled
- def isPhysicsMgrEnabled(self):
- return self.physicsMgrEnabled
- def updateManagers(self, state):
- """updateManagers(self)"""
- dt = min(globalClock.getDt(), 0.1)
- if (self.particleMgrEnabled == 1):
- self.particleMgr.doParticles(dt)
- if (self.physicsMgrEnabled == 1):
- self.physicsMgr.doPhysics(dt)
- return Task.cont
- def createStats(self):
- # You must specify a pstats-host in your configrc
- # The default is localhost
- if self.wantStats:
- PStatClient.connect()
- def createAudioManager(self):
- if self.wantAnySound:
- if self.wantSfx:
- self.sfxManager = AudioManager.createAudioManager()
- if not self.sfxManager.isValid():
- self.wantSfx=None
- if self.wantMusic:
- self.musicManager = AudioManager.createAudioManager()
- # Turn down the music globally
- # Eventually we may want to control this in the options page
- self.musicManager.setVolume(0.7)
- if not self.musicManager.isValid():
- self.wantMusic=None
- if not (self.wantSfx or self.wantMusic):
- self.wantAnySound=None
- def loadSfx(self, name):
- if (name and base.wantSfx):
- sound=self.sfxManager.getSound(name)
- if sound == None:
- self.notify.warning("Could not load sound file %s." % name)
- return sound
- def loadMusic(self, name):
- if (name and base.wantMusic):
- sound=self.musicManager.getSound(name)
- if sound == None:
- self.notify.warning("Could not load music file %s." % name)
- return sound
- def unloadSfx(self, sfx):
- if sfx:
- del sfx
- def unloadMusic(self, music):
- if music:
- del music
- def playSfx(self, sfx, looping = 0, interupt = 1, volume = None,
- time = 0.):
- if (sfx and base.wantSfx):
- if volume != None:
- sfx.setVolume(volume)
- if interupt or (sfx.status() != AudioSound.PLAYING):
- sfx.setTime(time)
- sfx.setLoop(looping)
- sfx.play()
- def playMusic(self, music, looping = 0, interupt = 1, volume = None,
- time = 0.0):
- if (music and base.wantMusic):
- if volume != None:
- music.setVolume(volume)
- if interupt or (music.status() != AudioSound.PLAYING):
- music.setTime(time)
- music.setLoop(looping)
- music.play()
- def stopSfx(self, sfx):
- if (sfx and base.wantSfx):
- sfx.stop()
- def stopMusic(self, music):
- if (music and base.wantMusic):
- music.stop()
- def dataloop(self, state):
- # traverse the data graph. This reads all the control
- # inputs (from the mouse and keyboard, for instance) and also
- # directly acts upon them (for instance, to move the avatar).
- traverseDataGraph(self.dataRootNode)
- return Task.cont
- def igloop(self, state):
- # run the collision traversal if we have a
- # CollisionTraverser set.
- if self.cTrav:
- self.cTrav.traverse(self.render)
- # Finally, render the frame.
- self.win.update()
- globalClock.tick()
- return Task.cont
- def restart(self):
- self.shutdown()
- # give the igloop task a reasonably "late" priority,
- # so that it will get run after most tasks
- self.taskMgr.spawnTaskNamed(Task.Task(self.igloop, 50), 'igloop')
- # give the dataloop task a reasonably "early" priority,
- # so that it will get run before most tasks
- self.taskMgr.spawnTaskNamed(Task.Task(self.dataloop, -50), 'dataloop')
- self.eventMgr.restart()
- def shutdown(self):
- self.taskMgr.removeTasksNamed('igloop')
- self.taskMgr.removeTasksNamed('dataloop')
- self.eventMgr.shutdown()
- def toggleBackface(self):
- return toggleBackface(self.render.arc())
- def backfaceCullingOn(self):
- if self.toggleBackface():
- self.toggleBackface()
- def backfaceCullingOff(self):
- if not self.toggleBackface():
- self.toggleBackface()
- def toggleTexture(self):
- return toggleTexture(self.render.arc())
- def textureOn(self):
- if not self.toggleTexture():
- self.toggleTexture()
- def textureOff(self):
- if self.toggleTexture():
- self.toggleTexture()
- def toggleWireframe(self):
- return toggleWireframe(self.render.arc())
- def wireframeOn(self):
- if not self.toggleWireframe():
- self.toggleWireframe()
- def wireframeOff(self):
- if self.toggleWireframe():
- self.toggleWireframe()
- def disableMouse(self):
- """
- Temporarily disable the mouse control of the camera, either
- via the drive interface or the trackball, whichever is
- currently in use.
- """
- # We don't reparent the drive interface or the trackball;
- # whichever one was there before will remain in the data graph
- # and active. This way they won't lose button events while
- # the mouse is disabled. However, we do move the mouse2cam
- # object out of there, so we won't be updating the camera any
- # more.
- self.mouse2cam.reparentTo(self.dataUnused)
- def enableMouse(self):
- """
- Reverse the effect of a previous call to disableMouse().
- useDrive() also implicitly enables the mouse.
- """
- self.mouse2cam.reparentTo(self.mouseInterface)
- def setMouseOnArc(self, newArc):
- self.mouse2cam.node().setArc(newArc)
- def useDrive(self):
- """
- Switch mouse action to drive mode
- """
- # Get rid of the trackball
- self.trackball.reparentTo(self.dataUnused)
- # Update the mouseInterface to point to the drive
- self.mouseInterface = self.drive
- self.mouseInterfaceNode = self.mouseInterface.node()
- self.drive.node().reset()
- # Hookup the drive to the camera. Make sure it is first in
- # the list of children of the mouseValve.
- self.drive.reparentTo(self.mouseValve, 0)
- self.mouse2cam.reparentTo(self.drive)
- # Set the height to a good eyeheight
- self.drive.node().setZ(4.0)
- def useTrackball(self):
- """
- Switch mouse action to trackball mode
- """
- # Get rid of the drive
- self.drive.reparentTo(self.dataUnused)
- # Update the mouseInterface to point to the trackball
- self.mouseInterface = self.trackball
- self.mouseInterfaceNode = self.mouseInterface.node()
- # Hookup the trackball to the camera. Make sure it is first
- # in the list of children of the mouseValve.
- self.trackball.reparentTo(self.mouseValve, 0)
- self.mouse2cam.reparentTo(self.trackball)
- def oobe(self):
- """
- Enable a special "out-of-body experience" mouse-interface
- mode. This can be used when a "god" camera is needed; it
- moves the camera node out from under its normal node and sets
- the world up in trackball state. Button events are still sent
- to the normal mouse action node (e.g. the DriveInterface), and
- mouse events, if needed, may be sent to the normal node by
- holding down the Control key.
- This is different than useTrackball(), which simply changes
- the existing mouse action to a trackball interface. In fact,
- OOBE mode doesn't care whether useDrive() or useTrackball() is
- in effect; it just temporarily layers a new trackball
- interface on top of whatever the basic interface is. You can
- even switch between useDrive() and useTrackball() while OOBE
- mode is in effect.
- This is a toggle; the second time this function is called, it
- disables the mode.
- """
- # If oobeMode was never set, set it to false and create the
- # structures we need to implement OOBE.
- try:
- self.oobeMode
- except:
- self.oobeMode = 0
- self.oobeCamera = self.hidden.attachNewNode('oobeCamera')
- self.oobeCameraTrackball = self.oobeCamera.attachNewNode('oobeCameraTrackball')
- self.oobeLens = PerspectiveLens()
- self.oobeLens.setAspectRatio(self.aspectRatio)
- self.oobeLens.setNearFar(0.1, 10000.0)
- self.oobeLens.setFov(52.0)
- self.oobeControl = DataValve.Control()
- self.mouseValve.node().setControl(1, self.oobeControl)
- self.oobeTrackball = self.mouseValve.attachNewNode(Trackball('oobeTrackball'), 1)
- self.oobe2cam = self.oobeTrackball.attachNewNode(Transform2SG('oobe2cam'))
- self.oobe2cam.node().setArc(self.oobeCameraTrackball.arc())
- self.oobeButtonEventsType = TypeRegistry.ptr().findType('ButtonEvents_ButtonEventDataTransition')
- self.oobeVis = loader.loadModelOnce('models/misc/camera')
- if self.oobeVis:
- self.oobeVis.arc().setFinal(1)
- self.oobeCullFrustum = None
- self.oobeCullFrustumVis = None
- # Make sure the MouseValve is monitoring the Control key.
- mods = ModifierButtons(self.mouseValve.node().getModifierButtons())
- mods.addButton(KeyboardButton.control())
- self.mouseValve.node().setModifierButtons(mods)
- if self.oobeMode:
- # Disable OOBE mode.
- if self.oobeCullFrustum != None:
- # First, disable OOBE cull mode.
- self.oobeCull()
-
- self.oobeControl.setOff()
- self.mouseControl.setOn()
- if self.oobeVis:
- self.oobeVis.reparentTo(self.hidden)
- self.cam.reparentTo(self.camera)
- self.camNode.setLens(self.camLens)
- self.oobeCamera.reparentTo(self.hidden)
- self.oobeMode = 0
- else:
- # Enable OOBE mode.
- mods = ModifierButtons(self.mouseValve.node().getModifierButtons())
- # We're in OOBE control mode without the control key.
- mods.allButtonsUp()
- self.oobeControl.setButtons(mods)
- # We're in traditional control mode with the control key.
- mods.buttonDown(KeyboardButton.control())
- self.mouseControl.setButtons(mods)
- # However, keyboard buttons always make it through to the
- # traditional controller, regardless of the control key.
- self.mouseValve.node().setFineControl(0, self.oobeButtonEventsType, self.onControl)
- # Make oobeCamera be a sibling of wherever camera is now.
- cameraParent = self.camera.getParent()
- self.oobeCamera.reparentTo(cameraParent)
- self.oobeCamera.clearMat()
- # Set our initial OOB position to be just behind the camera.
- mat = Mat4.translateMat(0, -10, 3) * self.camera.getMat(cameraParent)
- mat.invertInPlace()
- self.oobeTrackball.node().setMat(mat)
- self.cam.reparentTo(self.oobeCameraTrackball)
- self.camNode.setLens(self.oobeLens)
- if self.oobeVis:
- self.oobeVis.reparentTo(self.camera)
- self.oobeMode = 1
- def oobeCull(self):
- """
- While in OOBE mode (see above), cull the viewing frustum as if
- it were still attached to our original camera. This allows us
- to visualize the effectiveness of our bounding volumes.
- """
- # First, make sure OOBE mode is enabled.
- try:
- if not self.oobeMode:
- self.oobe()
- except:
- self.oobe()
- if self.oobeCullFrustum == None:
- # Enable OOBE culling.
- pnode = LensNode('oobeCull')
- pnode.setLens(self.camLens)
- self.oobeCullFrustum = self.camera.attachNewNode(pnode)
- # Create a visible representation of the frustum.
- geom = self.camLens.makeGeometry()
- if geom != None:
- gn = GeomNode('frustum')
- gn.addGeom(geom)
- self.oobeCullFrustumVis = self.oobeVis.attachNewNode(gn)
- # Assign each DisplayRegion shared by the camera to use
- # this cull frustum.
- numDrs = self.camNode.getNumDrs()
- for d in range(0, numDrs):
- dr = self.camNode.getDr(d)
- dr.setCullFrustum(pnode)
- else:
- # Disable OOBE culling.
- # Assign each DisplayRegion shared by the camera to use
- # the default cull frustum, the camera itself.
- numDrs = self.camNode.getNumDrs()
- for d in range(0, numDrs):
- dr = self.camNode.getDr(d)
- dr.setCullFrustum(self.camNode)
- self.oobeCullFrustum.removeNode()
- self.oobeCullFrustum = None
- if self.oobeCullFrustumVis != None:
- self.oobeCullFrustumVis.removeNode()
- self.oobeCullFrustumVis = None
- def screenshot(self, namePrefix='screenshot'):
- # Get the current date and time to uniquify the image (down to the second)
- date = time.ctime(time.time())
- # Get the current frame count to uniqify it even more
- frameCount = globalClock.getFrameCount()
- # Replace spaces with dashes because unix does not like spaces in the filename
- date = date.replace(' ', '-')
- date = date.replace(':', '-')
- imageName = (namePrefix + '-' + date + '-' + str(frameCount) + '.bmp')
- self.notify.info("Taking screenshot: " + imageName)
- takeSnapshot(self.win, imageName)
- def movie(self, namePrefix = 'movie', duration = 1.0, fps = 30,
- format = 'rgb', sd = 4):
- """
- movie(namePrefix = 'movie', duration=1.0, fps=30, format='rgb', sd=4)
- Spawn a task to capture a movie using the takeSnapshot function.
- - namePrefix will be used to form output file names (can include
- path information (e.g. 'I:/beta/frames/myMovie')
- - duration is the length of the movie in seconds
- - fps is the frame rate of the resulting movie
- - format specifies output file format (e.g. rgb, bmp)
- - sd specifies number of significant digits for frame count in the
- output file name (e.g. if sd = 4, movie_0001.rgb)
- """
- globalClock.setMode(ClockObject.MNonRealTime)
- globalClock.setDt(1.0/float(fps))
- t = taskMgr.spawnMethodNamed(self._movieTask, namePrefix + '_task')
- t.endT = globalClock.getFrameTime() + duration
- t.frameIndex = 1
- t.outputString = namePrefix + '_%0' + `sd` + 'd.' + format
- t.uponDeath = lambda state: globalClock.setMode(ClockObject.MNormal)
- def _movieTask(self, state):
- currT = globalClock.getFrameTime()
- if currT >= state.endT:
- return Task.done
- else:
- frameName = state.outputString % state.frameIndex
- self.notify.info("Capturing frame: " + frameName)
- takeSnapshot(self.win, frameName )
- state.frameIndex += 1
- return Task.cont
- # these are meant to be called in response to a user request
- def EnableMusic(self, bEnableMusic):
- if(self.musicManager == None):
- # would need to createaudiomanager/loadsfx for this to work. would that be safe after startup?
- self.notify.warning("Cant toggle music, must set audio-music-active #t in Configrc at startup")
- return 0
- self.wantMusic = bEnableMusic
- # dont setActive(1) if no audiofocus
- if(not (self.wantMusic and not self.AppHasAudioFocus)):
- self.musicManager.setActive(bEnableMusic)
- if(self.wantMusic):
- self.notify.debug("Enabling music")
- else:
- self.notify.debug("Disabling music")
- return 1
- def EnableSoundEffects(self, bEnableSoundEffects):
- if(self.sfxManager == None):
- # would need to createaudiomanager/loadsfx for this to work. would that be safe after startup?
- self.notify.warning("Cant toggle music, must set audio-music-active #t in Configrc at startup")
- return 0
- self.wantSfx = bEnableSoundEffects
- # dont setActive(1) if no audiofocus
- if(not (self.wantSfx and not self.AppHasAudioFocus)):
- self.sfxManager.setActive(bEnableSoundEffects)
- if(self.wantSfx):
- self.notify.debug("Enabling sound effects")
- else:
- self.notify.debug("Disabling sound effects")
- return 1
- # these are meant to be called by the sw when app loses audio focus (switched out)
- def DisableAudio(self):
- self.AppHasAudioFocus = 0
- if (self.wantSfx and (self.sfxManager != None)):
- self.sfxManager.setActive(0)
- if (self.wantMusic and (self.musicManager != None)):
- self.musicManager.setActive(0)
- self.notify.debug("Disabling audio")
- def EnableAudio(self):
- self.AppHasAudioFocus = 1
- if (self.wantSfx and (self.sfxManager != None)):
- self.sfxManager.setActive(1)
- if (self.wantMusic and (self.musicManager != None)):
- self.musicManager.setActive(1)
- self.notify.debug("Enabling audio")
- def run(self):
- self.taskMgr.run()
|