""" Contains classes useful for 3D viewports. Originally written by pro-rsoft, Modified by gjeon. Modified by Summer 2010 Carnegie Mellon University ETC PandaLE team: fixed a bug in Viewport.Close """ __all__ = ["Viewport", "ViewportManager"] from direct.showbase.DirectObject import DirectObject from direct.directtools.DirectGrid import DirectGrid from direct.showbase.ShowBase import WindowControls from direct.directtools.DirectGlobals import * from WxPandaWindow import WxPandaWindow from pandac.PandaModules import WindowProperties, OrthographicLens, Point3, Plane, CollisionPlane, CollisionNode, NodePath import wx HORIZONTAL = wx.SPLIT_HORIZONTAL VERTICAL = wx.SPLIT_VERTICAL CREATENEW = 99 VPLEFT = 10 VPFRONT = 11 VPTOP = 12 VPPERSPECTIVE = 13 class ViewportManager: """Manages the global viewport stuff.""" viewports = [] gsg = None @staticmethod def initializeAll(*args, **kwargs): """Calls initialize() on all the viewports.""" for v in ViewportManager.viewports: v.initialize(*args, **kwargs) @staticmethod def updateAll(*args, **kwargs): """Calls Update() on all the viewports.""" for v in ViewportManager.viewports: v.Update(*args, **kwargs) @staticmethod def layoutAll(*args, **kwargs): """Calls Layout() on all the viewports.""" for v in ViewportManager.viewports: v.Layout(*args, **kwargs) class Viewport(WxPandaWindow, DirectObject): """Class representing a 3D Viewport.""" CREATENEW = CREATENEW VPLEFT = VPLEFT VPFRONT = VPFRONT VPTOP = VPTOP VPPERSPECTIVE = VPPERSPECTIVE def __init__(self, name, *args, **kwargs): self.name = name DirectObject.__init__(self) kwargs['gsg'] = ViewportManager.gsg WxPandaWindow.__init__(self, *args, **kwargs) ViewportManager.viewports.append(self) if ViewportManager.gsg == None: ViewportManager.gsg = self.win.getGsg() self.camera = None self.lens = None self.camPos = None self.camLookAt = None self.initialized = False self.grid = None self.collPlane = None def initialize(self): self.Update() if self.win: self.cam2d = base.makeCamera2d(self.win) self.cam2d.node().setCameraMask(LE_CAM_MASKS[self.name]) self.cam = base.camList[-1] self.camera = render.attachNewNode(self.name) #self.camera.setName(self.name) #self.camera.reparentTo(render) self.cam.reparentTo(self.camera) self.camNode = self.cam.node() self.camNode.setCameraMask(LE_CAM_MASKS[self.name]) self.bt = base.setupMouse(self.win, True) self.bt.node().setPrefix('_le_%s_'%self.name[:3]) mw = self.bt.getParent() mk = mw.getParent() winCtrl = WindowControls( self.win, mouseWatcher=mw, cam=self.camera, camNode = self.camNode, cam2d=None, mouseKeyboard =mk, grid = self.grid) base.setupWindowControls(winCtrl) self.initialized = True if self.lens != None: self.cam.node().setLens(self.lens) if self.camPos != None: self.camera.setPos(self.camPos) if self.camLookAt != None: self.camera.lookAt(self.camLookAt) self.camLens = self.camNode.getLens() if self.name in ['top', 'front', 'left']: x = self.ClientSize.GetWidth() * 0.1 y = self.ClientSize.GetHeight() * 0.1 self.camLens.setFilmSize(x, y) self.Bind(wx.EVT_SIZE, self.onSize) ## self.accept("wheel_down", self.zoomOut) ## self.accept("wheel_up", self.zoomIn) ## self.accept("page_down", self.zoomOut) ## self.accept("page_down-repeat", self.zoomOut) ## self.accept("page_up", self.zoomIn) ## self.accept("page_up-repeat", self.zoomIn) #self.accept("mouse3", self.onRightDown) def Close(self): """Closes the viewport.""" if self.initialized: wx.Window.Close(self) #base.closeWindow(self.win) ViewportManager.viewports.remove(self) def onSize(self, evt): """Invoked when the viewport is resized.""" WxPandaWindow.onSize(self, evt) if self.win != None: newWidth = self.ClientSize.GetWidth() newHeight = self.ClientSize.GetHeight() if hasattr(base, "direct") and base.direct: for dr in base.direct.drList: if dr.camNode == self.camNode: dr.updateFilmSize(newWidth, newHeight) break def onRightDown(self, evt = None): """Invoked when the viewport is right-clicked.""" if evt == None: mpos = wx.GetMouseState() mpos = self.ScreenToClient((mpos.x, mpos.y)) else: mpos = evt.GetPosition() self.Update() #self.PopupMenu(self.menu, mpos) #self.menu.Destroy() def zoomOut(self): self.camera.setY(self.camera, -MOUSE_ZOO_SPEED) def zoomIn(self): self.camera.setY(self.camera, MOUSE_ZOOM_SPEED) @staticmethod def make(parent, vpType = None): """Safe constructor that also takes CREATENEW, VPLEFT, VPTOP, etc.""" if vpType == None or vpType == CREATENEW: return Viewport(parent) if isinstance(vpType, Viewport): return vpType if vpType == VPLEFT: return Viewport.makeLeft(parent) if vpType == VPFRONT: return Viewport.makeFront(parent) if vpType == VPTOP: return Viewport.makeTop(parent) if vpType == VPPERSPECTIVE: return Viewport.makePerspective(parent) raise TypeError, "Unknown viewport type: %s" % vpType @staticmethod def makeOrthographic(parent, name, campos): v = Viewport(name, parent) v.lens = OrthographicLens() v.lens.setFilmSize(30) v.camPos = campos v.camLookAt = Point3(0, 0, 0) v.grid = DirectGrid(parent=render) if name == 'left': v.grid.setHpr(0, 0, 90) collPlane = CollisionNode('LeftGridCol') collPlane.addSolid(CollisionPlane(Plane(1, 0, 0, 0))) collPlane.setIntoCollideMask(BitMask32.bit(21)) v.collPlane = NodePath(collPlane) v.collPlane.wrtReparentTo(v.grid) #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_leftViewGridBack") LE_showInOneCam(v.grid, name) elif name == 'front': v.grid.setHpr(90, 0, 90) collPlane = CollisionNode('FrontGridCol') collPlane.addSolid(CollisionPlane(Plane(0, -1, 0, 0))) collPlane.setIntoCollideMask(BitMask32.bit(21)) v.collPlane = NodePath(collPlane) v.collPlane.wrtReparentTo(v.grid) #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_frontViewGridBack") LE_showInOneCam(v.grid, name) else: collPlane = CollisionNode('TopGridCol') collPlane.addSolid(CollisionPlane(Plane(0, 0, 1, 0))) collPlane.setIntoCollideMask(BitMask32.bit(21)) v.collPlane = NodePath(collPlane) v.collPlane.reparentTo(v.grid) #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_topViewGridBack") LE_showInOneCam(v.grid, name) return v @staticmethod def makePerspective(parent): v = Viewport('persp', parent) v.camPos = Point3(-19, -19, 19) v.camLookAt = Point3(0, 0, 0) v.grid = DirectGrid(parent=render) collPlane = CollisionNode('PerspGridCol') collPlane.addSolid(CollisionPlane(Plane(0, 0, 1, 0))) #oldBitmask = collPlane.getIntoCollideMask() #collPlane.setIntoCollideMask(BitMask32.bit(21)|oldBitmask) collPlane.setIntoCollideMask(BitMask32.bit(21)) v.collPlane = NodePath(collPlane) v.collPlane.reparentTo(v.grid) collPlane2 = CollisionNode('PerspGridCol2') collPlane2.addSolid(CollisionPlane(Plane(0, 0, -1, 0))) #oldBitmask = collPlane2.getIntoCollideMask() #collPlane2.setIntoCollideMask(BitMask32.bit(21)|oldBitmask) collPlane2.setIntoCollideMask(BitMask32.bit(21)) v.collPlane2 = NodePath(collPlane2) v.collPlane2.reparentTo(v.grid) #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_perspViewGridBack") LE_showInOneCam(v.grid, 'persp') return v @staticmethod def makeLeft(parent): return Viewport.makeOrthographic(parent, 'left', Point3(600, 0, 0)) @staticmethod def makeFront(parent): return Viewport.makeOrthographic(parent, 'front', Point3(0, -600, 0)) @staticmethod def makeTop(parent): return Viewport.makeOrthographic(parent, 'top', Point3(0, 0, 600))