Пример #1
0
class ButtonWatcher(DirectObject):
    def __init__(self, keys):
        self.modKeys = ModifierButtons()

        for key in keys:
            self.modKeys.addButton(key)
            self.accept(key.getName(), self.modKeys.buttonDown, [key])
            self.accept(key.getName()+'-up', self.modKeys.buttonUp, [key])

    def getKeys(self):
        return self.modKeys

    def destroy(self):
        self.ignoreAll()
Пример #2
0
class ButtonWatcher(DirectObject):
    def __init__(self, keys):
        self.modKeys = ModifierButtons()

        for key in keys:
            self.modKeys.addButton(key)
            self.accept(key.getName(), self.modKeys.buttonDown, [key])
            self.accept(key.getName() + '-up', self.modKeys.buttonUp, [key])

    def getKeys(self):
        return self.modKeys

    def destroy(self):
        self.ignoreAll()
Пример #3
0
    def setup_bindings_for_sensors(self):
        modifiers = ModifierButtons()

        modifiers.addButton(KeyboardButton.lshift())
        modifiers.addButton(KeyboardButton.rshift())
        modifiers.addButton(KeyboardButton.lcontrol())
        modifiers.addButton(KeyboardButton.rcontrol())
        modifiers.addButton(KeyboardButton.lalt())
        modifiers.addButton(KeyboardButton.ralt())
        modifiers.addButton(KeyboardButton.meta())

        # For supporting "use_all_keys" and modifier keys
        button_node = base.buttonThrowers[0].node()
        button_node.setButtonDownEvent('buttonDown')
        button_node.setButtonUpEvent('buttonUp')
        button_node.setModifierButtons(modifiers)
Пример #4
0
class World(DirectObject):
    instance = None

    def __init__(self):
        render.setAntialias(AntialiasAttrib.MAuto)

        # Enable physics - perhaps this should go someplace else, but it must
        # be done before the Vehicle is initialized.
        base.enableParticles()
        aei = AngularEulerIntegrator()
        base.physicsMgr.attachAngularIntegrator(aei)

        SelectionEngine.getDefault().enable()
        SelectionManager.getDefault().enable()

        # Make the environment and the vehicle model.
        makeEnvironment()
        self.vehicle = Vehicle(render)

        MissionElement.loadElementConfig('mission_elements.plist')

        #layoutName = AppPreferences.get('last_layout', 'defaultLayout.plist')
        if len(sys.argv) == 2:
            layoutName = sys.argv[1]
            print "Using command line argument %s for layout" % layoutName
        else:
            print "Using default layout file"
            print "Use ./sim2.py [layout file] to use a different layout"
            print "Or press Ctrl+O to open a new layout in the simulator"
            layoutName = 'defaultLayout.plist'

        self.layout = MissionLayout.loadLayout(layoutName)
        render.attachNewNode(self.layout)

        self.vehicle.setLayout(self.layout)  #Link the layout

        # Set up render buffer viewer, to aide debugging.
        self.accept("v", base.bufferViewer.toggleEnable)
        self.accept("V", base.bufferViewer.toggleEnable)
        base.bufferViewer.setPosition("llcorner")

        # Set up file saver
        self.accept('s', self._saveLayout)
        self.accept('o', self._openLayout)
        self.accept('f', self._setFreq)
        root = Tk()
        root.withdraw()
        self.modButtons = ModifierButtons()
        self.modButtons.addButton(KeyboardButton.control())
        self.accept('control', self.modButtons.buttonDown,
                    [KeyboardButton.control()])
        self.accept('control-up', self.modButtons.buttonUp,
                    [KeyboardButton.control()])
        # Add GUI Controls
        '''
        buttonReady = makeGeom('button_ready.png')
        b = DirectButton(geom = (buttonReady,
                                 makeGeom('button_click.png'),
                                 makeGeom('button_rollover.png'),
                                 buttonReady),
                          relief = None)
        b.reparentTo(pixel2d)
        b.hide()
        b.setPos(base.win.getXSize()/2, 0, -base.win.getYSize()/2)
        b.setScale(1, 1, 1)
        b.bind(DirectGuiGlobals.ACCEPT, eventHandler, ['accept'])
        b.bind(DirectGuiGlobals.ACCEPTFAILED, eventHandler, ['accept failed'])
        b.bind(DirectGuiGlobals.ADJUST, eventHandler, ['adjust'])
        b.bind(DirectGuiGlobals.B1CLICK, eventHandler, ['b1click'])
        b.bind(DirectGuiGlobals.B1PRESS, eventHandler, ['b1press'])
        b.bind(DirectGuiGlobals.B1RELEASE, eventHandler, ['b1release'])
        b.bind(DirectGuiGlobals.B2CLICK, eventHandler, ['b2click'])
        b.bind(DirectGuiGlobals.B2PRESS, eventHandler, ['b2press'])
        b.bind(DirectGuiGlobals.B2RELEASE, eventHandler, ['b2release'])
        b.bind(DirectGuiGlobals.B3CLICK, eventHandler, ['b3click'])
        b.bind(DirectGuiGlobals.B3PRESS, eventHandler, ['b3press'])
        b.bind(DirectGuiGlobals.B3RELEASE, eventHandler, ['b3release'])
        b.bind(DirectGuiGlobals.ENTER, eventHandler, ['enter'])
        b.bind(DirectGuiGlobals.EXIT, eventHandler, ['exit'])
        b.bind(DirectGuiGlobals.WITHIN, eventHandler, ['within'])
        b.bind(DirectGuiGlobals.WITHOUT, eventHandler, ['without'])
        b.bind(DirectGuiGlobals.CURSORMOVE, eventHandler, ['cursormove'])
        # b['frameSize'] = (3, 3, 3, 3)
        '''

    @classmethod
    def getInstance(cls):
        if cls.instance == None:
            cls.instance = World()
        return cls.instance

    def _saveLayout(self):
        if self.modButtons.isDown(KeyboardButton.control()):
            self.modButtons.buttonUp(KeyboardButton.control())
            self.modButtons.buttonUp(KeyboardButton.asciiKey('s'))
            filename = asksaveasfilename(filetypes=[('plist files',
                                                     '*.plist')])
            if filename:
                self.layout.save(filename)
                AppPreferences.set('last_layout', filename)

    def _setFreq(self):
        #TODO: Check pinger selected

        pinger = None
        for element in self.layout.elements:
            if element.getTypeName() == "Pinger" and element.isSelected():
                pinger = element
                break

        if pinger is None:
            return

        newfreq = askinteger("Set Pinger Frequency",
                             "Set this pinger to which frequency? (in Hz)",
                             initialvalue=pinger.pinger_frequency,
                             minvalue=10000,
                             maxvalue=50000)
        if newfreq is None:
            print "No frequency specified, aborting"
            return

        pinger.pinger_frequency = newfreq
        print "Frequency of pinger set to %d Hz" % newfreq

    def _openLayout(self):
        if self.modButtons.isDown(KeyboardButton.control()):
            self.modButtons.buttonUp(KeyboardButton.control())
            self.modButtons.buttonUp(KeyboardButton.asciiKey('o'))
            filename = askopenfilename(filetypes=[('plist files', '*.plist')])
            if filename:
                if self.layout:
                    NodePath(self.layout).detachNode()
                self.layout = MissionLayout.loadLayout(filename)
                render.attachNewNode(self.layout)
                AppPreferences.set('last_layout', filename)
Пример #5
0
class World(DirectObject):
    instance = None

    def __init__(self):
        render.setAntialias(AntialiasAttrib.MAuto)

        # Enable physics - perhaps this should go someplace else, but it must
        # be done before the Vehicle is initialized.
        base.enableParticles()
        aei = AngularEulerIntegrator()
        base.physicsMgr.attachAngularIntegrator(aei)

        SelectionEngine.getDefault().enable()
        SelectionManager.getDefault().enable()
        
        # Make the environment and the vehicle model.
        makeEnvironment()
        self.vehicle = Vehicle(render)

        MissionElement.loadElementConfig('mission_elements.plist')

        #layoutName = AppPreferences.get('last_layout', 'defaultLayout.plist')
        if len(sys.argv) == 2:
            layoutName = sys.argv[1]
            print "Using command line argument %s for layout" %layoutName
        else:
            print "Using default layout file"
            print "Use ./sim2.py [layout file] to use a different layout"
            print "Or press Ctrl+O to open a new layout in the simulator"
            layoutName = 'defaultLayout.plist'

        self.layout = MissionLayout.loadLayout(layoutName)
        render.attachNewNode(self.layout)

        self.vehicle.setLayout(self.layout) #Link the layout 

        # Set up render buffer viewer, to aide debugging.
        self.accept("v", base.bufferViewer.toggleEnable)
        self.accept("V", base.bufferViewer.toggleEnable)
        base.bufferViewer.setPosition("llcorner")
        
        # Set up file saver
        self.accept('s', self._saveLayout)
        self.accept('o', self._openLayout)
        self.accept('f', self._setFreq)
        root = Tk()
        root.withdraw()
        self.modButtons = ModifierButtons()
        self.modButtons.addButton(KeyboardButton.control())
        self.accept('control', self.modButtons.buttonDown,
                [KeyboardButton.control()])
        self.accept('control-up', self.modButtons.buttonUp,
                [KeyboardButton.control()])
        # Add GUI Controls
        '''
        buttonReady = makeGeom('button_ready.png')
        b = DirectButton(geom = (buttonReady,
                                 makeGeom('button_click.png'),
                                 makeGeom('button_rollover.png'),
                                 buttonReady),
                          relief = None)
        b.reparentTo(pixel2d)
        b.hide()
        b.setPos(base.win.getXSize()/2, 0, -base.win.getYSize()/2)
        b.setScale(1, 1, 1)
        b.bind(DirectGuiGlobals.ACCEPT, eventHandler, ['accept'])
        b.bind(DirectGuiGlobals.ACCEPTFAILED, eventHandler, ['accept failed'])
        b.bind(DirectGuiGlobals.ADJUST, eventHandler, ['adjust'])
        b.bind(DirectGuiGlobals.B1CLICK, eventHandler, ['b1click'])
        b.bind(DirectGuiGlobals.B1PRESS, eventHandler, ['b1press'])
        b.bind(DirectGuiGlobals.B1RELEASE, eventHandler, ['b1release'])
        b.bind(DirectGuiGlobals.B2CLICK, eventHandler, ['b2click'])
        b.bind(DirectGuiGlobals.B2PRESS, eventHandler, ['b2press'])
        b.bind(DirectGuiGlobals.B2RELEASE, eventHandler, ['b2release'])
        b.bind(DirectGuiGlobals.B3CLICK, eventHandler, ['b3click'])
        b.bind(DirectGuiGlobals.B3PRESS, eventHandler, ['b3press'])
        b.bind(DirectGuiGlobals.B3RELEASE, eventHandler, ['b3release'])
        b.bind(DirectGuiGlobals.ENTER, eventHandler, ['enter'])
        b.bind(DirectGuiGlobals.EXIT, eventHandler, ['exit'])
        b.bind(DirectGuiGlobals.WITHIN, eventHandler, ['within'])
        b.bind(DirectGuiGlobals.WITHOUT, eventHandler, ['without'])
        b.bind(DirectGuiGlobals.CURSORMOVE, eventHandler, ['cursormove'])
        # b['frameSize'] = (3, 3, 3, 3)
        '''

    @classmethod
    def getInstance(cls):
        if cls.instance == None:
            cls.instance = World()
        return cls.instance

    def _saveLayout(self):
        if self.modButtons.isDown(KeyboardButton.control()):
            self.modButtons.buttonUp(KeyboardButton.control())
            self.modButtons.buttonUp(KeyboardButton.asciiKey('s'))
            filename = asksaveasfilename(filetypes=[('plist files', '*.plist')])
            if filename:
                self.layout.save(filename)
                AppPreferences.set('last_layout', filename)

    def _setFreq(self):
        #TODO: Check pinger selected

        pinger = None
        for element in self.layout.elements:
            if element.getTypeName() == "Pinger" and element.isSelected():
                pinger = element
                break

        if pinger is None:
            return

        newfreq = askinteger("Set Pinger Frequency", "Set this pinger to which frequency? (in Hz)", initialvalue=pinger.pinger_frequency, minvalue=10000, maxvalue=50000)
        if newfreq is None:
            print "No frequency specified, aborting"
            return

        pinger.pinger_frequency = newfreq
        print "Frequency of pinger set to %d Hz" % newfreq


    def _openLayout(self):
        if self.modButtons.isDown(KeyboardButton.control()):
            self.modButtons.buttonUp(KeyboardButton.control())
            self.modButtons.buttonUp(KeyboardButton.asciiKey('o'))
            filename = askopenfilename(filetypes=[('plist files', '*.plist')])
            if filename:
                if self.layout:
                    NodePath(self.layout).detachNode()
                self.layout = MissionLayout.loadLayout(filename)
                render.attachNewNode(self.layout)
                AppPreferences.set('last_layout', filename)
Пример #6
0
def windowMaker(base, label):
    # find an open slot, if none, return false
    windict = dict()
    grid = None
    for i in range(grid_size[0]):
        for j in range(grid_size[1]):
            if occupied[i][j] == False:
                grid = (i, j)
                occupied[i][j] = True
                break
        else:
            continue
        break
    if not grid: return False
    windict['grid'] = grid
    position = grid_to_screen_pos(*grid)

    #open window
    newwin = base.openWindow(name=label)
    newwin.setWindowEvent(label + "-event")
    listener.accept(newwin.getWindowEvent(), windowEvent)
    windict['win'] = newwin

    #format window
    wp = WindowProperties()
    wp.setOrigin(*position)
    wp.setSize(*ws)
    newwin.requestProperties(wp)

    #make 3d-mousewatcher display region
    displayRegion = newwin.getDisplayRegion(0)
    displayRegion.setDimensions(.3, 1, 0, 1)
    mkNode = MouseAndKeyboard(newwin, 0, label + "_keyboard_mouse")
    mk = base.dataRoot.attachNewNode(mkNode)
    windict['mk'] = mk
    modis = ModifierButtons()
    modis.addButton(ButtonHandle('shift'))
    modis.addButton(ButtonHandle('control'))
    mwNode = MouseWatcher(label)
    mwNode.setModifierButtons(modis)
    mwNode.setDisplayRegion(displayRegion)
    mw = mk.attachNewNode(mwNode)
    windict['mw'] = mw
    bt = ButtonThrower(label + "_button_thrower")
    bt.setModifierButtons(modis)
    windict['bt'] = bt
    bt.setPrefix(label + "_")
    mw.attachNewNode(bt)
    #listen for default button events
    for button in buttons:
        listener.accept(bt.prefix + button, buttons[button])

    #format render display region
    render_dr = newwin.getDisplayRegion(1)
    windict['render_dr'] = render_dr
    render_dr.setDimensions(.3, 1, 0, 1)

    #create a display region for Gui Elements
    gui_dr = newwin.makeDisplayRegion(0, .3, .3, 1)
    # gui_dr.setSort(20)
    mwNodegui = MouseWatcher(label + "gui")
    mwNodegui.setDisplayRegion(gui_dr)
    mwgui = mk.attachNewNode(mwNodegui)

    #create a 2d render/aspect for gui
    rendergui = NodePath('render2d')
    rendergui.setDepthWrite(0)
    rendergui.setMaterialOff(1)
    rendergui.setTwoSided(1)
    #set up aspect2d
    aspectgui = rendergui.attachNewNode(PGTop('aspectgui'))
    aspectgui.node().setMouseWatcher(mwgui.node())
    #set up camera
    camNodegui = Camera("camNode2d")
    cameragui = rendergui.attachNewNode(camNodegui)
    cameragui.setPos(0, 0, 0)
    cameragui.setDepthTest(False)
    cameragui.setDepthWrite(False)
    lens = OrthographicLens()
    lens.setFilmSize(2, 2)
    lens.setNearFar(-1000, 1000)
    cameragui.node().setLens(lens)
    gui_dr.setCamera(cameragui)
    #make frame for gui
    frame = DirectFrame(frameSize=(-1, 1, -1, 1),
                        frameColor=(.5, .5, .5, 1),
                        relief='ridge')
    frame.reparentTo(aspectgui)
    frame.setTransparency(0)
    windict['gui_frame'] = frame

    #create Gui elements
    guibuttons = dict()
    # guibuttons['Create'] = label+"_mode_create"
    guibuttons['Preview'] = label + "_preview"
    # createButton(base, frame, .7, "Create", label+"_mode_create")
    createButton(base, frame, .7, "Preview", label + "_preview")
    windict['guibuttons'] = guibuttons

    #create a display region for math data preview
    preview_dr = newwin.makeDisplayRegion(0, .3, 0, .3)
    windict['preview_dr'] = preview_dr
    # preview_label = label+"_preview"
    # preview_mwNode = MouseWatcher(preview_label)
    # preview_mwNode.setDisplayRegion(preview_dr)
    # preview_mw = mk.attachNewNode(preview_mwNode)
    # preview_bt = ButtonThrower(preview_label+"_button_thrower")
    # preview_bt.setPrefix(preview_label+"_")
    # preview_mw.attachNewNode(preview_bt)
    # preview_dr.setSort(30)

    win_to_windict[newwin] = windict

    return windict
Пример #7
0
    def initialize(self):
        self.lens = self.makeLens()
        self.camera = self.doc.render.attachNewNode(
            ModelNode("viewportCameraParent"))
        self.camNode = Camera("viewportCamera")
        self.camNode.setLens(self.lens)
        self.camNode.setCameraMask(self.getViewportMask())
        self.cam = self.camera.attachNewNode(self.camNode)

        winprops = WindowProperties.getDefault()
        winprops.setParentWindow(int(self.winId()))
        winprops.setForeground(False)
        winprops.setUndecorated(True)

        gsg = self.doc.gsg

        output = base.graphicsEngine.makeOutput(
            base.pipe, "viewportOutput", 0, FrameBufferProperties.getDefault(),
            winprops,
            (GraphicsPipe.BFFbPropsOptional | GraphicsPipe.BFRequireWindow),
            gsg)

        self.qtWindow = QtGui.QWindow.fromWinId(
            output.getWindowHandle().getIntHandle())
        self.qtWidget = QtWidgets.QWidget.createWindowContainer(
            self.qtWindow, self, QtCore.Qt.WindowDoesNotAcceptFocus
            | QtCore.Qt.WindowTransparentForInput
            | QtCore.Qt.WindowStaysOnBottomHint
            | QtCore.Qt.BypassWindowManagerHint | QtCore.Qt.SubWindow)  #,
        #(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowDoesNotAcceptFocus
        #| QtCore.Qt.WindowTransparentForInput | QtCore.Qt.BypassWindowManagerHint
        #| QtCore.Qt.SubWindow | QtCore.Qt.WindowStaysOnBottomHint))
        self.qtWidget.setFocusPolicy(QtCore.Qt.NoFocus)

        self.inputDevice = output.getInputDevice(0)

        assert output is not None, "Unable to create viewport output!"

        dr = output.makeDisplayRegion()
        dr.disableClears()
        dr.setCamera(self.cam)
        self.displayRegion = dr

        output.disableClears()
        output.setClearColor(Viewport.ClearColor)
        output.setClearColorActive(True)
        output.setClearDepthActive(True)
        output.setActive(True)

        self.win = output

        # keep track of the mouse in this viewport
        mak = MouseAndKeyboard(self.win, 0, "mouse")
        mouse = base.dataRoot.attachNewNode(mak)
        self.mouseAndKeyboard = mouse
        self.mouseWatcher = MouseWatcher()
        self.mouseWatcher.setDisplayRegion(self.displayRegion)
        mw = mouse.attachNewNode(self.mouseWatcher)
        self.mouseWatcherNp = mw

        # listen for keyboard and mouse events in this viewport
        bt = ButtonThrower("kbEvents")
        bt.setButtonDownEvent("btndown")
        bt.setButtonUpEvent("btnup")
        mods = ModifierButtons()
        mods.addButton(KeyboardButton.shift())
        mods.addButton(KeyboardButton.control())
        mods.addButton(KeyboardButton.alt())
        mods.addButton(KeyboardButton.meta())
        bt.setModifierButtons(mods)
        self.buttonThrower = mouse.attachNewNode(bt)

        # collision objects for clicking on objects from this viewport
        self.clickRay = CollisionRay()
        self.clickNode = CollisionNode("viewportClickRay")
        self.clickNode.addSolid(self.clickRay)
        self.clickNp = NodePath(self.clickNode)
        self.clickQueue = CollisionHandlerQueue()

        self.setupRender2d()
        self.setupCamera2d()

        self.gizmo = ViewportGizmo(self)

        self.doc.viewportMgr.addViewport(self)

        self.makeGrid()
Пример #8
0
class CameraController(DirectObject):
    instance = None

    def __init__(self):
        self.instructionText = addInstructions(0.95,
                '[ESC]: Leave Mouselook mode.')
        self.eventDispatcher = EventDispatcher()
        self.cameraMode = None
        self.clickPos = Vec2()
        self.lastMousePos = Vec2()
        self.focus = Vec3()
        self.mouseDown = False
        self.initialPos = Vec3()
        self.initialHpr = Vec3()
        self.initialMat = None

        # Disable the built-in mouse camera control (it sucks).
        base.disableMouse()
        self.setCameraMode(TRACKBALL)

        # Set the camera's initial position.
        base.camera.setPosHpr(0, 12, 30, 180, -70, 0)
        
        # Turn off events generated with modifier buttons, e.g. 'shift-a'
        # This is to keep keyboard control working after you alt-tab out
        # of the app.
        base.mouseWatcherNode.setModifierButtons(ModifierButtons())
        base.buttonThrowers[0].node().setModifierButtons(ModifierButtons())

        # This is a diagonal matrix that keeps track of movement key
        # state. The first three diagonal entries can be 1, 0, or -1.
        self.mouseLookTransMat = Mat4.scaleMat(Vec3(0.0, 0.0, 0.0))
        
        # Keep track of how many movement keys are currently pressed. This
        # lets us short-circuit past a lot of math when no keys are held.
        self.keysHeld = 0

        # Handle events for the movement keys.       
        for key, value in key2MatArgs.items():
            self.accept(key, self._moveKeyHandler, value)

        self.accept('escape', self._escKeyHandler)
        self.accept('m', self._mKeyHandler)
        self.accept('mouse1', self._mouseDownHandler, [1])
        self.accept('mouse1-up', self._mouseUpHandler, [1])
        self.accept('mouse2', self._mouseDownHandler, [2])
        self.accept('mouse2-up', self._mouseUpHandler, [2])
        self.accept('wheel_up', self._mouseWheelHandler, [1])
        self.accept('wheel_down', self._mouseWheelHandler, [-1])

        self.modButtons = ModifierButtons()
        self.modButtons.addButton(KeyboardButton.control())
        self.accept('control', self.modButtons.buttonDown,
                [KeyboardButton.control()])
        self.accept('control-up', self.modButtons.buttonUp,
                [KeyboardButton.control()])

        self.accept(base.win.getWindowEvent(), self._windowHandler)

    @classmethod
    def getInstance(cls):
        if cls.instance == None:
            cls.instance = cls()
        return cls.instance

    def setFocus(self, position):
        self.focus = position
        base.camera.lookAt(render, position)

    def addEventHandler(self, evtType, handler):
        self.eventDispatcher.addHandler(evtType, handler)

    def getCameraMode(self):
        return self.cameraMode

    def setCameraMode(self, mode):
        if mode == self.cameraMode:
            return

        winProps = WindowProperties()
        
        # Tear-down code for the current mode.
        if self.cameraMode == MOUSELOOK:
            winProps.setCursorHidden(False)
            self.removeTask(self.viewTask)
        elif self.cameraMode == TRACKBALL:
            self.removeTask(self.viewTask)

        # Set-up code for the new mode.
        if mode == MOUSELOOK:
            winProps.setCursorHidden(True)
            
            # Mouse accumulator. Whenever the mouse moves, it is reset to the
            # center of the window. The accumulator keeps track of the total
            # movement
            self.mouseAccX = 0
            self.mouseAccY = 0
            self.recenterMouse = True

            # Add a task that moves the camera based on mouse position.
            self.viewTask = taskMgr.add(self._mlViewTask, 'MLViewTask')
            self.lastFrameTime = 0  # Used to calculate dt in mlViewTask.
            self.instructionText.setText('[ESC]: Leave Mouselook Mode')
        
        elif mode == TRACKBALL:
            self.instructionText.setText('[m]: Enter Mouselook Mode')
            self.viewTask = taskMgr.add(self._trackballTask, 'TrackballTask')

        self.cameraMode = mode
        self.eventDispatcher.dispatchEvent(EVT_CAMERA_MODE, self)
        base.win.requestProperties(winProps)

    def _windowHandler(self, window):
        pos = aspect2d.find('a2dTopLeft').getPos()
        self.instructionText.setPos(pos.getX() + 0.05, pos.getZ() - 0.05)
        hasFocus = window.getProperties().getForeground()
        if not hasFocus:
            self.setCameraMode(TRACKBALL)

    def _escKeyHandler(self):
        self.setCameraMode(TRACKBALL)

    def _mKeyHandler(self):
        if self.cameraMode == MOUSELOOK:
            self.setCameraMode(TRACKBALL)
        else:
            self.setCameraMode(MOUSELOOK)

    def _mouseWheelHandler(self, arg):
        deltY = base.camera.getPos().length() * arg * 0.15
        transl = Mat4.translateMat(0, deltY, 0)
        base.camera.setMat(transl * base.camera.getMat())
        self.eventDispatcher.dispatchEvent(EVT_CAMERA_MOVE, base.camera)

    def _mouseDownHandler(self, button):
        if base.mouseWatcherNode.hasMouse():
            if button == 2 or self.modButtons.isDown(KeyboardButton.control()):
                self.clickPos = Vec2(base.mouseWatcherNode.getMouse())
                self.mouseDown = True
                offset = self.focus - base.camera.getPos()
                self.initialTranslation = offset.length()
                self.initialHpr = base.camera.getHpr()

    def _mouseUpHandler(self, button):
        self.mouseDown = False
            
    def _moveKeyHandler(self, *matArgs):
        self.mouseLookTransMat.setCell(*matArgs)
        
        # matArgs[2] is 0 for key release events.
        if (matArgs[2]):
            self.keysHeld += 1
        else:
            self.keysHeld -= 1

    def _trackballTask(self, task):
        if not self.mouseDown:
            return Task.cont

        if (base.mouseWatcherNode.hasMouse()):
            mpos = base.mouseWatcherNode.getMouse()
            if mpos == self.lastMousePos:
                return Task.cont

            mDelta = mpos - self.clickPos

            heading = -mDelta.x * 100 + self.initialHpr.x
            pitch = mDelta.y * 100 + self.initialHpr.y
            if pitch > 90:
                pitch = 90
            elif pitch < -90:
                pitch = -90
            trans1 = Mat4.translateMat(self.focus)
            rotx = Mat4.rotateMat(heading, Vec3(0, 0, 1))
            roty = Mat4.rotateMat(pitch, Vec3(1, 0, 0))
            trans2 = Mat4.translateMat(0, -self.initialTranslation, 0)
            rotation = trans2 * roty * rotx * trans1
            base.camera.setMat(rotation)
            self.eventDispatcher.dispatchEvent(EVT_CAMERA_MOVE, base.camera)
            
            self.lastMousePos = Vec2(mpos)
        return Task.cont

    def _mlViewTask(self, task):
        t = globalClock.getFrameTime()
        dt = t - self.lastFrameTime
        self.lastFrameTime = t
        if (self.keysHeld):
            # Update camera position based on keyboard controls.
            T = Mat4()
            T.invertAffineFrom(base.camera.getMat())
            cameraMoveMat = T*self.mouseLookTransMat
            xDir = cameraMoveMat.getCol3(0)
            yDir = cameraMoveMat.getCol3(1)
            zDir = cameraMoveMat.getCol3(2)
            currentPos = base.camera.getPos()
            nextPos = currentPos + (xDir + yDir + zDir)*(dt*8)
            base.camera.setPos(nextPos)
            self.eventDispatcher.dispatchEvent(EVT_CAMERA_MOVE, base.camera)

        if (base.mouseWatcherNode.hasMouse()):
            halfWidth = base.win.getProperties().getXSize()/2
            halfHeight = base.win.getProperties().getYSize()/2
            if self.recenterMouse:
                # Don't move the camera, but center the pointer. This is
                # useful when entering mouselook mode, to prevent the camera
                # from jumping to the pointer.
                heading, pitch = base.camera.getH(), base.camera.getP()
                self.mouseAccX = int(heading / ML_MULT)
                self.mouseAccY = int(pitch / ML_MULT)
                self.recenterMouse = False # Only do this once.
            else:
                mpos = base.mouseWatcherNode.getMouse()
                x, y = mpos.getX(), mpos.getY()
                
                # short-circuit if mouse hasn't moved or is outside the window.
                if x == 0 and y == 0 or x > 1.0 or y > 1.0:
                    return Task.cont
                # Convert x and y to pixels.
                self.mouseAccX -= int(round(x*halfWidth))
                self.mouseAccY += int(round(y*halfHeight))

                base.camera.setHpr(self.mouseAccX*ML_MULT,
                        self.mouseAccY*ML_MULT, 0.0)
            base.win.movePointer(0, halfWidth, halfHeight)
            
        return Task.cont
Пример #9
0
class CameraController(DirectObject):
    instance = None

    def __init__(self):
        self.instructionText = addInstructions(0.95,
                                               '[ESC]: Leave Mouselook mode.')
        self.eventDispatcher = EventDispatcher()
        self.cameraMode = None
        self.clickPos = Vec2()
        self.lastMousePos = Vec2()
        self.focus = Vec3()
        self.mouseDown = False
        self.initialPos = Vec3()
        self.initialHpr = Vec3()
        self.initialMat = None

        # Disable the built-in mouse camera control (it sucks).
        base.disableMouse()
        self.setCameraMode(TRACKBALL)

        # Set the camera's initial position.
        base.camera.setPosHpr(0, 12, 30, 180, -70, 0)

        # Turn off events generated with modifier buttons, e.g. 'shift-a'
        # This is to keep keyboard control working after you alt-tab out
        # of the app.
        base.mouseWatcherNode.setModifierButtons(ModifierButtons())
        base.buttonThrowers[0].node().setModifierButtons(ModifierButtons())

        # This is a diagonal matrix that keeps track of movement key
        # state. The first three diagonal entries can be 1, 0, or -1.
        self.mouseLookTransMat = Mat4.scaleMat(Vec3(0.0, 0.0, 0.0))

        # Keep track of how many movement keys are currently pressed. This
        # lets us short-circuit past a lot of math when no keys are held.
        self.keysHeld = 0

        # Handle events for the movement keys.
        for key, value in key2MatArgs.items():
            self.accept(key, self._moveKeyHandler, value)

        self.accept('escape', self._escKeyHandler)
        self.accept('m', self._mKeyHandler)
        self.accept('mouse1', self._mouseDownHandler, [1])
        self.accept('mouse1-up', self._mouseUpHandler, [1])
        self.accept('mouse2', self._mouseDownHandler, [2])
        self.accept('mouse2-up', self._mouseUpHandler, [2])
        self.accept('wheel_up', self._mouseWheelHandler, [1])
        self.accept('wheel_down', self._mouseWheelHandler, [-1])

        self.modButtons = ModifierButtons()
        self.modButtons.addButton(KeyboardButton.control())
        self.accept('control', self.modButtons.buttonDown,
                    [KeyboardButton.control()])
        self.accept('control-up', self.modButtons.buttonUp,
                    [KeyboardButton.control()])

        self.accept(base.win.getWindowEvent(), self._windowHandler)

    @classmethod
    def getInstance(cls):
        if cls.instance == None:
            cls.instance = cls()
        return cls.instance

    def setFocus(self, position):
        self.focus = position
        base.camera.lookAt(render, position)

    def addEventHandler(self, evtType, handler):
        self.eventDispatcher.addHandler(evtType, handler)

    def getCameraMode(self):
        return self.cameraMode

    def setCameraMode(self, mode):
        if mode == self.cameraMode:
            return

        winProps = WindowProperties()

        # Tear-down code for the current mode.
        if self.cameraMode == MOUSELOOK:
            winProps.setCursorHidden(False)
            self.removeTask(self.viewTask)
        elif self.cameraMode == TRACKBALL:
            self.removeTask(self.viewTask)

        # Set-up code for the new mode.
        if mode == MOUSELOOK:
            winProps.setCursorHidden(True)

            # Mouse accumulator. Whenever the mouse moves, it is reset to the
            # center of the window. The accumulator keeps track of the total
            # movement
            self.mouseAccX = 0
            self.mouseAccY = 0
            self.recenterMouse = True

            # Add a task that moves the camera based on mouse position.
            self.viewTask = taskMgr.add(self._mlViewTask, 'MLViewTask')
            self.lastFrameTime = 0  # Used to calculate dt in mlViewTask.
            self.instructionText.setText('[ESC]: Leave Mouselook Mode')

        elif mode == TRACKBALL:
            self.instructionText.setText('[m]: Enter Mouselook Mode')
            self.viewTask = taskMgr.add(self._trackballTask, 'TrackballTask')

        self.cameraMode = mode
        self.eventDispatcher.dispatchEvent(EVT_CAMERA_MODE, self)
        base.win.requestProperties(winProps)

    def _windowHandler(self, window):
        pos = aspect2d.find('a2dTopLeft').getPos()
        self.instructionText.setPos(pos.getX() + 0.05, pos.getZ() - 0.05)
        hasFocus = window.getProperties().getForeground()
        if not hasFocus:
            self.setCameraMode(TRACKBALL)

    def _escKeyHandler(self):
        self.setCameraMode(TRACKBALL)

    def _mKeyHandler(self):
        if self.cameraMode == MOUSELOOK:
            self.setCameraMode(TRACKBALL)
        else:
            self.setCameraMode(MOUSELOOK)

    def _mouseWheelHandler(self, arg):
        deltY = base.camera.getPos().length() * arg * 0.15
        transl = Mat4.translateMat(0, deltY, 0)
        base.camera.setMat(transl * base.camera.getMat())
        self.eventDispatcher.dispatchEvent(EVT_CAMERA_MOVE, base.camera)

    def _mouseDownHandler(self, button):
        if base.mouseWatcherNode.hasMouse():
            if button == 2 or self.modButtons.isDown(KeyboardButton.control()):
                self.clickPos = Vec2(base.mouseWatcherNode.getMouse())
                self.mouseDown = True
                offset = self.focus - base.camera.getPos()
                self.initialTranslation = offset.length()
                self.initialHpr = base.camera.getHpr()

    def _mouseUpHandler(self, button):
        self.mouseDown = False

    def _moveKeyHandler(self, *matArgs):
        self.mouseLookTransMat.setCell(*matArgs)

        # matArgs[2] is 0 for key release events.
        if (matArgs[2]):
            self.keysHeld += 1
        else:
            self.keysHeld -= 1

    def _trackballTask(self, task):
        if not self.mouseDown:
            return Task.cont

        if (base.mouseWatcherNode.hasMouse()):
            mpos = base.mouseWatcherNode.getMouse()
            if mpos == self.lastMousePos:
                return Task.cont

            mDelta = mpos - self.clickPos

            heading = -mDelta.x * 100 + self.initialHpr.x
            pitch = mDelta.y * 100 + self.initialHpr.y
            if pitch > 90:
                pitch = 90
            elif pitch < -90:
                pitch = -90
            trans1 = Mat4.translateMat(self.focus)
            rotx = Mat4.rotateMat(heading, Vec3(0, 0, 1))
            roty = Mat4.rotateMat(pitch, Vec3(1, 0, 0))
            trans2 = Mat4.translateMat(0, -self.initialTranslation, 0)
            rotation = trans2 * roty * rotx * trans1
            base.camera.setMat(rotation)
            self.eventDispatcher.dispatchEvent(EVT_CAMERA_MOVE, base.camera)

            self.lastMousePos = Vec2(mpos)
        return Task.cont

    def _mlViewTask(self, task):
        t = globalClock.getFrameTime()
        dt = t - self.lastFrameTime
        self.lastFrameTime = t
        if (self.keysHeld):
            # Update camera position based on keyboard controls.
            T = Mat4()
            T.invertAffineFrom(base.camera.getMat())
            cameraMoveMat = T * self.mouseLookTransMat
            xDir = cameraMoveMat.getCol3(0)
            yDir = cameraMoveMat.getCol3(1)
            zDir = cameraMoveMat.getCol3(2)
            currentPos = base.camera.getPos()
            nextPos = currentPos + (xDir + yDir + zDir) * (dt * 8)
            base.camera.setPos(nextPos)
            self.eventDispatcher.dispatchEvent(EVT_CAMERA_MOVE, base.camera)

        if (base.mouseWatcherNode.hasMouse()):
            halfWidth = base.win.getProperties().getXSize() / 2
            halfHeight = base.win.getProperties().getYSize() / 2
            if self.recenterMouse:
                # Don't move the camera, but center the pointer. This is
                # useful when entering mouselook mode, to prevent the camera
                # from jumping to the pointer.
                heading, pitch = base.camera.getH(), base.camera.getP()
                self.mouseAccX = int(heading / ML_MULT)
                self.mouseAccY = int(pitch / ML_MULT)
                self.recenterMouse = False  # Only do this once.
            else:
                mpos = base.mouseWatcherNode.getMouse()
                x, y = mpos.getX(), mpos.getY()

                # short-circuit if mouse hasn't moved or is outside the window.
                if x == 0 and y == 0 or x > 1.0 or y > 1.0:
                    return Task.cont
                # Convert x and y to pixels.
                self.mouseAccX -= int(round(x * halfWidth))
                self.mouseAccY += int(round(y * halfHeight))

                base.camera.setHpr(self.mouseAccX * ML_MULT,
                                   self.mouseAccY * ML_MULT, 0.0)
            base.win.movePointer(0, halfWidth, halfHeight)

        return Task.cont