|
|
@@ -0,0 +1,243 @@
|
|
|
+"""
|
|
|
+Contains classes useful for 3D viewports.
|
|
|
+
|
|
|
+Originally written by pro-rsoft,
|
|
|
+Modified by gjeon.
|
|
|
+"""
|
|
|
+
|
|
|
+__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 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(wx.Panel, 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)
|
|
|
+ wx.Panel.__init__(self, *args, **kwargs)
|
|
|
+
|
|
|
+ ViewportManager.viewports.append(self)
|
|
|
+ self.win = None
|
|
|
+ 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()
|
|
|
+ wp = WindowProperties()
|
|
|
+ wp.setOrigin(0, 0)
|
|
|
+ wp.setSize(self.ClientSize.GetWidth(), self.ClientSize.GetHeight())
|
|
|
+ assert self.GetHandle() != 0
|
|
|
+ wp.setParentWindow(self.GetHandle())
|
|
|
+
|
|
|
+ # initializing panda window
|
|
|
+ base.windowType = "onscreen"
|
|
|
+ props = WindowProperties.getDefault()
|
|
|
+ props.addProperties(wp)
|
|
|
+ self.win = base.openWindow(props = props, gsg = ViewportManager.gsg)
|
|
|
+ if self.win:
|
|
|
+ self.cam2d = base.makeCamera2d(self.win)
|
|
|
+ self.cam2d.node().setCameraMask(LE_CAM_MASKS[self.name])
|
|
|
+
|
|
|
+ if ViewportManager.gsg == None:
|
|
|
+ ViewportManager.gsg = self.win.getGsg()
|
|
|
+ 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:
|
|
|
+ Window.close(self)
|
|
|
+ ViewportManager.viewports.remove(self)
|
|
|
+
|
|
|
+ def onSize(self, evt):
|
|
|
+ """Invoked when the viewport is resized."""
|
|
|
+ if self.win != None:
|
|
|
+ wp = WindowProperties()
|
|
|
+ wp.setOrigin(0, 0)
|
|
|
+ newWidth = self.ClientSize.GetWidth()
|
|
|
+ newHeight = self.ClientSize.GetHeight()
|
|
|
+ wp.setSize(newWidth, newHeight)
|
|
|
+ self.win.requestProperties(wp)
|
|
|
+
|
|
|
+ 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)
|
|
|
+ v.collPlane = NodePath(collPlane)
|
|
|
+ v.collPlane.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))
|
|
|
+
|