diff options
Diffstat (limited to 'src/python/appstarter.py')
-rw-r--r-- | src/python/appstarter.py | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/src/python/appstarter.py b/src/python/appstarter.py new file mode 100644 index 0000000..aca4fe0 --- /dev/null +++ b/src/python/appstarter.py @@ -0,0 +1,396 @@ +# libavg - Media Playback Engine. +# Copyright (C) 2003-2014 Ulrich von Zadow +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Current versions can be found at www.libavg.de +# +# Original author of this file is Martin Heistermann <mh at sponc dot de> +# + +import os +import gc +import math + +from libavg import avg, Point2D, player +import graph +from mtemu import MTemu +import apphelpers + + +DEFAULT_RESOLUTION = (640, 480) + +g_KbManager = apphelpers.KeyboardManager.get() + + +class AppStarter(object): + '''Starts an AVGApp''' + def __init__(self, appClass, resolution=DEFAULT_RESOLUTION, + debugWindowSize=None, fakeFullscreen=False): + + resolution = Point2D(resolution) + testMode = not 'AVG_DEPLOY' in os.environ + + if testMode and debugWindowSize is not None: + debugWindowSize = Point2D(debugWindowSize) + else: + debugWindowSize = Point2D(0, 0) + + if fakeFullscreen: + if os.name != 'nt': + raise RuntimeError('Fakefullscreen is supported only on windows') + elif not testMode: + self.__enableFakeFullscreen() + + fullscreen = False + else: + fullscreen = not testMode + + player.enableMouse(not 'AVG_DISABLE_MOUSE' in os.environ) + player.showCursor(testMode) + self._setupBaseDivs(resolution) + + player.setResolution( + fullscreen, + int(debugWindowSize.x), int(debugWindowSize.y), + 0 # color depth + ) + + self._startApp(appClass) + + def _startApp(self, appClass): + self._onBeforePlay() + player.setTimeout(0, self._onStart) + self._appInstance = appClass(self._appNode) + g_KbManager.setup( + self._appInstance.onKeyDown, + self._appInstance.onKeyUp) + + self._setupDefaultKeys() + + self._appInstance.setStarter(self) + player.play() + self._appInstance.exit() + g_KbManager.teardown() + + def _setupBaseDivs(self, resolution): + player.loadString(''' +<?xml version="1.0"?> +<!DOCTYPE avg SYSTEM "../../libavg/doc/avg.dtd"> +<avg width="%s" height="%s"> +</avg>''' % (resolution.x, resolution.y)) + + rootNode = player.getRootNode() + self._appNode = avg.DivNode(opacity=0, sensitive=False, + size=rootNode.size, parent=rootNode) + + def _setupDefaultKeys(self): + pass + + def _onBeforePlay(self): + pass + + def _onStart(self): + self._appInstance.init() + self._appNode.opacity = 1 + self._appNode.sensitive = True + self._activeApp = self._appInstance + self._appInstance.enter() + + def __enableFakeFullscreen(self): + player.setWindowPos(0, 0) + player.setWindowFrame(False) + + +class AVGAppStarter(AppStarter): + def __init__(self, *args, **kwargs): + self.__graphs = [] + self._mtEmu = None + self.__memGraph = None + self.__vidMemGraph = None + self.__frGraph = None + self.__notifyNode = None + self.__debugTouchVisOverlay = None + + super(AVGAppStarter, self).__init__(*args, **kwargs) + + def _setupDefaultKeys(self): + super(AVGAppStarter, self)._setupDefaultKeys() + g_KbManager.bindKey('o', self.__dumpObjects, 'Dump objects') + g_KbManager.bindKey('m', self.showMemoryUsage, 'Show memory usage graph') + + g_KbManager.bindKey('f', self.showFrameRate, 'Show framerate graph') + g_KbManager.bindKey('t', self.__switchMtemu, 'Activate multitouch emulation') + g_KbManager.bindKey('e', self.__switchShowMTEvents, 'Show multitouch events') + g_KbManager.bindKey('s', self.__screenshot, 'Take screenshot') + + def _onStart(self): + try: + player.getVideoMemUsed() + g_KbManager.bindKey('v', self.showVideoMemoryUsage, + 'Show video memory usage graph') + except RuntimeError: + # Video memory query not supported. + pass + + AppStarter._onStart(self) + + def __dumpObjects(self): + gc.collect() + testHelper = player.getTestHelper() + testHelper.dumpObjects() + print 'Num anims: ', avg.getNumRunningAnims() + print 'Num python objects: ', len(gc.get_objects()) + + def showMemoryUsage(self): + if self.__memGraph: + self.__memGraph.unlink(True) + self.__graphs.remove(self.__memGraph) + self.__memGraph = None + else: + size = (self._appNode.width, self._appNode.height/6.0) + self.__memGraph = graph.AveragingGraph(title = 'Memory Usage', + getValue = avg.getMemoryUsage, parent=player.getRootNode(), size=size) + self.__graphs.append(self.__memGraph) + self.__positionGraphs() + + def showVideoMemoryUsage(self): + if self.__vidMemGraph: + self.__vidMemGraph.unlink(True) + self.__graphs.remove(self.__vidMemGraph) + self.__vidMemGraph = None + else: + size = (self._appNode.width, self._appNode.height/6.0) + self.__vidMemGraph = graph.AveragingGraph(title='Video Memory Usage', + getValue=player.getVideoMemUsed, parent=player.getRootNode(), + size=size) + self.__graphs.append(self.__vidMemGraph) + self.__positionGraphs() + + def showFrameRate(self): + if self.__frGraph: + self.__frGraph.unlink(True) + self.__graphs.remove(self.__frGraph) + self.__frGraph = None + else: + size = (self._appNode.width, self._appNode.height/6.0) + self.__frGraph = graph.SlidingGraph(title = 'Time per Frame', + getValue = player.getFrameTime, parent = self._appNode, size=size) + self.__graphs.append(self.__frGraph) + self.__positionGraphs() + + def __positionGraphs(self): + ypos = 10 + for gr in self.__graphs: + gr.y = ypos + ypos += gr.height + 10 + + def __switchMtemu(self): + if self._mtEmu is None: + self._mtEmu = MTemu() + g_KbManager.bindKey('left shift', self._mtEmu.toggleDualTouch, + 'Toggle Multitouch Emulation') + g_KbManager.bindKey('right shift', self._mtEmu.toggleDualTouch, + 'Toggle Multitouch Emulation') + g_KbManager.bindKey('left ctrl', self._mtEmu.toggleSource, + 'Toggle Touch Source') + g_KbManager.bindKey('right ctrl', self._mtEmu.toggleSource, + 'Toggle Touch Source') + else: + self._mtEmu.deinit() + g_KbManager.unbindKey('left ctrl') + g_KbManager.unbindKey('right ctrl') + g_KbManager.unbindKey('left shift') + g_KbManager.unbindKey('right shift') + + del self._mtEmu + self._mtEmu = None + + def __switchShowMTEvents(self): + if self.__debugTouchVisOverlay is None: + rootNode = player.getRootNode() + self.__debugTouchVisOverlay = apphelpers.TouchVisualizationOverlay( + isDebug=True, visClass=apphelpers.DebugTouchVisualization, + size=self._appNode.size, parent=rootNode) + else: + self.__debugTouchVisOverlay.unlink(True) + del self.__debugTouchVisOverlay + self.__debugTouchVisOverlay = None + + def __killNotifyNode(self): + if self.__notifyNode: + self.__notifyNode.unlink() + self.__notifyNode = None + + def __screenshot(self): + fnum = 0 + fnameTemplate = 'screenshot-%03d.png' + while os.path.exists(fnameTemplate % fnum): + fnum += 1 + + try: + player.screenshot().save('screenshot-%03d.png' % fnum) + except RuntimeError: + text = 'Cannot save snapshot file' + else: + text = 'Screenshot saved as ' + fnameTemplate % fnum + + self.__killNotifyNode() + + self.__notifyNode = avg.WordsNode( + text=text, x=player.getRootNode().width - 50, + y=player.getRootNode().height - 50, alignment='right', fontsize=20, + sensitive=False, parent=player.getRootNode()) + + player.setTimeout(2000, self.__killNotifyNode) + + +class AVGMTAppStarter(AVGAppStarter): + + def __init__(self, *args, **kwargs): + self.__touchVisOverlay = None + super(AVGMTAppStarter, self).__init__(*args, **kwargs) + + def setTouchVisualization(self, visClass): + if not(self.__touchVisOverlay is None): + self.__touchVisOverlay.unlink(True) + del self.__touchVisOverlay + self.__touchVisOverlay = None + if not(visClass is None): + rootNode = player.getRootNode() + self.__touchVisOverlay = apphelpers.TouchVisualizationOverlay( + isDebug=False, visClass=visClass, size=self._appNode.size, + parent=rootNode) + + def toggleTrackerImage(self): + if self.__showTrackerImage: + self.hideTrackerImage() + else: + self.showTrackerImage() + + def showTrackerImage(self): + if self.__showTrackerImage: + return + self.__showTrackerImage = True + self.__updateTrackerImageInterval = \ + player.subscribe(player.ON_FRAME, self.__updateTrackerImage) + self.__trackerImageNode.opacity = 1 + self.tracker.setDebugImages(False, True) + + def hideTrackerImage(self): + if not self.__showTrackerImage: + return + self.__showTrackerImage = False + if self.__updateTrackerImageInterval: + player.clearInterval(self.__updateTrackerImageInterval) + self.__updateTrackerImageInterval = None + self.__trackerImageNode.opacity = 0 + self.tracker.setDebugImages(False, False) + + def __updateTrackerImage(self): + def transformPos((x,y)): + if self.trackerFlipX: + x = 1 - x + if self.trackerFlipY: + y = 1 - y + return (x, y) + + fingerBitmap = self.tracker.getImage(avg.IMG_FINGERS) + node = self.__trackerImageNode + node.setBitmap(fingerBitmap) + node.pos = self.tracker.getDisplayROIPos() + node.size = self.tracker.getDisplayROISize() + + grid = node.getOrigVertexCoords() + grid = [ [ transformPos(pos) for pos in line ] for line in grid] + node.setWarpedVertexCoords(grid) + + def _onStart(self): + from camcalibrator import Calibrator + + # we must add the tracker first, calibrator depends on it + try: + player.enableMultitouch() + except RuntimeError, err: + avg.logger.warning(str(err)) + + self.tracker = player.getTracker() + + if self.tracker: + if Calibrator: + self.__calibratorNode = player.createNode('div',{ + 'opacity': 0, + 'active': False, + }) + rootNode = player.getRootNode() + rootNode.appendChild(self.__calibratorNode) + self.__calibratorNode.size = rootNode.size + self.__calibrator = Calibrator(self.__calibratorNode, appStarter=self) + self.__calibrator.setOnCalibrationSuccess(self.__onCalibrationSuccess) + self.__calibrator.init() + else: + self.__calibrator = None + + self.__showTrackerImage = False + self.__updateTrackerImageInterval = None + self.__trackerImageNode = player.createNode('image', {'sensitive': False}) + player.getRootNode().appendChild(self.__trackerImageNode) + + self.__updateTrackerImageFixup() + + g_KbManager.bindKey('h', self.tracker.resetHistory, 'RESET tracker history') + g_KbManager.bindKey('d', self.toggleTrackerImage, 'toggle tracker image') + + if self.__calibrator: + g_KbManager.bindKey('c', self.__enterCalibrator, 'enter calibrator') + AVGAppStarter._onStart(self) + + def __updateTrackerImageFixup(self): + # finger bitmap might need to be rotated/flipped + trackerAngle = float(self.tracker.getParam('/transform/angle/@value')) + angle = round(trackerAngle/math.pi) * math.pi + self.__trackerImageNode.angle = angle + self.trackerFlipX = (float(self.tracker.getParam('/transform/displayscale/@x')) + < 0) + self.trackerFlipY = (float(self.tracker.getParam('/transform/displayscale/@y')) + < 0) + + def __onCalibrationSuccess(self): + self.__updateTrackerImageFixup() + + def __enterCalibrator(self): + + def leaveCalibrator(): + g_KbManager.unbindKey('e') + self._activeApp = self._appInstance + self._appInstance.enter() + self.__calibrator.leave() + self._appNode.opacity = 1 + self._appNode.active = True + self.__calibratorNode.opacity = 0 + self.__calibratorNode.active = False + + if self.__calibrator.isRunning(): + print "calibrator already running!" + return + + self._activeApp = self.__calibrator + self.__calibrator.enter() + g_KbManager.bindKey('e', leaveCalibrator, 'leave Calibrator') + self._appInstance.leave() + self.__calibratorNode.opacity = 1 + self.__calibratorNode.active = True + self._appNode.opacity = 0 + self._appNode.active = False |