#!/bin/env python # Copyright (C) 2002-2003 Gideon May (gideon@computer.org) # # Permission to copy, use, sell and distribute this software is granted # provided this copyright notice appears in all copies. # Permission to modify the code and to distribute modified code is granted # provided this copyright notice appears in all copies, and a notice # that the code was modified is included with the copyright notice. # # This software is provided "as is" without express or implied warranty, # and with no claim as to its suitability for any purpose. # -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield # # This application is open source and may be redistributed and/or modified # freely and without restriction, both in commericial and non commericial applications, # as long as this copyright notice is maintained. # # This application 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. # from PyOSG import osg from PyOSG import osgGA import math class TestManipulator(osgGA.MatrixManipulator): def __init__(self): osgGA.MatrixManipulator.__init__(self) self._ga_t1 = osg.ref() self._ga_t0 = osg.ref() self._node = None self._modelScale = 0.01 self._minimumZoomScale = 0.05 self._thrown = False self._distance = 1.0 self._rotation = osg.Quat() self._camera = None def __del__(self): pass def setCamera(self, camera): self._camera = camera def setNode(self, node): self._node = node if self._node: boundingSphere=self._node.getBound() self._modelScale = boundingSphere.radius() def getNode(self): return self._node def home(self, ea, us): if self._node and self._camera : boundingSphere=self._node.getBound() self._camera.setView(boundingSphere.center()+osg.Vec3(0.0, 0.0, 20.0), boundingSphere.center()+osg.Vec3(0.0, 1.0, 20.0), osg.Vec3(0.0, 0.0, 1.0)) self._velocity = boundingSphere.radius()*0.01 self.computeLocalDataFromCamera() us.requestRedraw() def init(self, ea, us): self.flushMouseEventStack() self.computeLocalDataFromCamera() def handle(self, ea, us): if self._camera == None: return 0 eType = ea.getEventType() if eType == osgGA.GUIEventAdapter.PUSH: self.flushMouseEventStack() self.addMouseEvent(ea) if self.calcMovement(): us.requestRedraw() us.requestContinuousUpdate(False) self._thrown = False return True elif eType == osgGA.GUIEventAdapter.RELEASE: if ea.getButtonMask() == 0: if self.isMouseMoving(): if self.calcMovement(): us.requestRedraw() us.requestContinuousUpdate(1) self._thrown = False else: self.flushMouseEventStack() self.addMouseEvent(ea) if self.calcMovement(): us.requestRedraw() us.requestContinuousUpdate(False) self._thrown = False else: self.flushMouseEventStack() self.addMouseEvent(ea) if self.calcMovement(): us.requestRedraw() us.requestContinuousUpdate(False) self._thrown = False return False elif eType == osgGA.GUIEventAdapter.DRAG: self.addMouseEvent(ea) if (self.calcMovement()): us.requestRedraw() us.requestContinuousUpdate(False) self._thrown = False return 1 elif eType == osgGA.GUIEventAdapter.MOVE: return False elif eType == osgGA.GUIEventAdapter.KEYDOWN: if ea.getKey()==ord(' '): self.flushMouseEventStack() self._thrown = False self.home(ea,us) us.requestRedraw() us.requestContinuousUpdate(0) return True elif ea.getKey()==ord('+'): self._camera.setFusionDistanceRatio(self._camera.getFusionDistanceRatio()*1.25) return True elif ea.getKey()==ord('-'): self._camera.setFusionDistanceRatio(self._camera.getFusionDistanceRatio()/1.25) return True return False elif eType == osgGA.GUIEventAdapter.FRAME: self._camera.setFusionDistanceMode(osg.Camera.PROPORTIONAL_TO_LOOK_DISTANCE); if self._thrown: if (self.calcMovement()): us.requestRedraw() return True return False else: return False def isMouseMoving(self): if self._ga_t0() == None or self._ga_t1() == None: return False velocity = 100.0 dx = self._ga_t0().getX()-self._ga_t1().getX() dy = self._ga_t0().getY()-self._ga_t1().getY() ln = math.sqrt(dx*dx+dy*dy) dt = self._ga_t0().time()-self._ga_t1().time() return ln>dt*velocity def flushMouseEventStack(self): """Reset the internal GUIEvent stack.""" self._ga_t1.set(None) self._ga_t0.set(None) def addMouseEvent(self, ea): """Add the current mouse GUIEvent to internal stack.""" # see flushMouseEventStack for the reason of ref/unref self._ga_t1.set(self._ga_t0()) self._ga_t0.set(ea) def computeLocalDataFromCamera(self): # maths from gluLookAt/osg.Matrix.makeLookAt f = self._camera.getCenterPoint()-self._camera.getEyePoint() f.normalize(); s = f^self._camera.getUpVector() s.normalize(); u = s^f u.normalize(); rotation_matrix = osg.Matrix() rotation_matrix.set((s[0], u[0], -f[0], 0.0, s[1], u[1], -f[1], 0.0, s[2], u[2], -f[2], 0.0, 0.0, 0.0, 0.0, 1.0)) self._center = self._camera.getCenterPoint() self._distance = self._camera.getLookDistance() self._rotation.set(rotation_matrix) self._rotation = self._rotation.inverse() def computeCameraFromLocalData(self): new_rotation = osg.Matrix() new_rotation.makeRotate(self._rotation) # FIXME up = osg.Vec3(0.0,1.0,0.0) * new_rotation up = new_rotation.preMult(osg.Vec3(0.0,1.0,0.0)) # FIXME eye = osg.Vec3(0.0,0.0,self._distance) * new_rotation + self._center eye = new_rotation.preMult(osg.Vec3(0.0,0.0,self._distance)) + self._center self._camera.setLookAt(eye,self._center,up); def calcMovement(self): # return if less then two events have been added. if self._ga_t0() == None or self._ga_t1() == None: return 0 dx = self._ga_t0().getX()-self._ga_t1().getX(); dy = self._ga_t0().getY()-self._ga_t1().getY(); # return if there is no movement. if dx==0 and dy==0: return False buttonMask = self._ga_t1().getButtonMask() if buttonMask==osgGA.GUIEventAdapter.LEFT_MOUSE_BUTTON: # rotate camera. rx0 = (self._ga_t0().getXmax()-self._ga_t0().getXmin())/2.0 new_rotate = osg.Quat() xRot = dx / rx0 new_rotate.makeRotate(xRot / 5.0, osg.Vec3(0.0, 0.0, 1.0)) self._rotation = self._rotation*new_rotate self.computeCameraFromLocalData() return True elif buttonMask==osgGA.GUIEventAdapter.MIDDLE_MOUSE_BUTTON: # pan model. dv = osg.Vec3(0.0, 0.0, 1.0) * dy self._center += dv self.computeCameraFromLocalData() return True; elif buttonMask==osgGA.GUIEventAdapter.RIGHT_MOUSE_BUTTON: uv = self._camera.getUpVector() sv = self._camera.getSideVector() fv = uv ^ sv dv = fv*dy-sv*dx self._center += dv self.computeCameraFromLocalData() return True; return False; if __name__ == "__main__": import sys from PyOSG import Producer from PyOSG import osgDB from PyOSG import osgUtil from PyOSG import osgProducer viewer = osgProducer.Viewer() viewer.setUpViewer(osgProducer.Viewer.STANDARD_SETTINGS) rootnode = osgDB.readNodeFile("cow.osg") if rootnode == None: sys.exit(1) viewer.setSceneData(rootnode) pos = viewer.addCameraManipulator(TestManipulator()) viewer.selectCameraManipulator(pos) viewer.realize() while not viewer.done(): viewer.sync() viewer.update() viewer.frame() viewer.sync() sys.exit(0)