瀏覽代碼

Added generic wx panda frame

Gyedo Jeon 15 年之前
父節點
當前提交
3b7c98a5e1
共有 3 個文件被更改,包括 462 次插入0 次删除
  1. 243 0
      direct/src/wxwidgets/ViewPort.py
  2. 216 0
      direct/src/wxwidgets/WxPandaShell.py
  3. 3 0
      direct/src/wxwidgets/WxPandaStart.py

+ 243 - 0
direct/src/wxwidgets/ViewPort.py

@@ -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))
+

+ 216 - 0
direct/src/wxwidgets/WxPandaShell.py

@@ -0,0 +1,216 @@
+import wx
+import os
+from wx.lib.agw import fourwaysplitter as FWS
+
+from pandac.PandaModules import *
+from direct.showbase.ShowBase import *
+from direct.directtools.DirectGlobals import *
+
+base = ShowBase(False)
+
+from WxAppShell import *
+from ViewPort import *
+
+ID_FOUR_VIEW = 401
+ID_TOP_VIEW = 402
+ID_FRONT_VIEW = 403
+ID_LEFT_VIEW = 404
+ID_PERSP_VIEW = 405
+
+class WxPandaShell(WxAppShell):
+    """ Class for Panda3D LevelEditor """ 
+    frameWidth = 800
+    frameHeight = 600
+    appversion      = '1.0'
+    appname         = 'Panda3D Generic WX Frame'
+    copyright       = ('Copyright 2010 Disney Online Studios.' +
+                       '\nAll Rights Reserved.')
+    
+    MENU_TEXTS = {
+        ID_FOUR_VIEW : ("Four Views", None),
+        ID_TOP_VIEW : ("Top View", None),        
+        ID_FRONT_VIEW : ("Front View", None),
+        ID_LEFT_VIEW : ("Left View", None),
+        ID_PERSP_VIEW : ("Persp View", None),
+        }
+
+    def __init__(self, fStartDirect = False):
+        fDirect = (base.config.GetBool('want-directtools', 0) or
+                   (base.config.GetString("cluster-mode", '') != ''))
+
+        self.fStartDirect = fStartDirect or fDirect
+
+        # Create the Wx app
+        self.wxApp = wx.App(redirect = False)
+        self.wxApp.SetAppName(self.appname)
+        WxAppShell.__init__(self, size=wx.Size(self.frameWidth, self.frameHeight))
+        self.initialize()
+
+    def createMenu(self):
+        self.menuView = wx.Menu()
+        self.menuBar.Insert(self.menuBar.GetMenuCount() - 1, self.menuView, "&View")
+
+        menuItem = self.menuView.AppendRadioItem(ID_FOUR_VIEW, self.MENU_TEXTS[ID_FOUR_VIEW][0])
+        self.Bind(wx.EVT_MENU, lambda p0=None, p1=-1:self.onViewChange(p0, p1), menuItem)
+
+        menuItem = self.menuView.AppendRadioItem(ID_TOP_VIEW, self.MENU_TEXTS[ID_TOP_VIEW][0])
+        self.Bind(wx.EVT_MENU, lambda p0=None, p1=0:self.onViewChange(p0, p1), menuItem)
+
+        menuItem = self.menuView.AppendRadioItem(ID_FRONT_VIEW, self.MENU_TEXTS[ID_FRONT_VIEW][0])
+        self.Bind(wx.EVT_MENU, lambda p0=None, p1=1:self.onViewChange(p0, p1), menuItem)
+
+        menuItem = self.menuView.AppendRadioItem(ID_LEFT_VIEW, self.MENU_TEXTS[ID_LEFT_VIEW][0])
+        self.Bind(wx.EVT_MENU, lambda p0=None, p1=2:self.onViewChange(p0, p1), menuItem)
+
+        menuItem = self.menuView.AppendRadioItem(ID_PERSP_VIEW, self.MENU_TEXTS[ID_PERSP_VIEW][0])
+        self.Bind(wx.EVT_MENU, lambda p0=None, p1=3:self.onViewChange(p0, p1), menuItem)
+
+    def createInterface(self):
+        self.createMenu()
+        self.mainFrame = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_BORDER)
+        self.leftFrame = wx.SplitterWindow(self.mainFrame, style = wx.SP_3D | wx.SP_BORDER)
+        self.baseFrame = wx.SplitterWindow(self.mainFrame, style = wx.SP_3D | wx.SP_BORDER)
+        self.viewFrame = FWS.FourWaySplitter(self.baseFrame, style=wx.SP_LIVE_UPDATE)
+        self.rightFrame = wx.SplitterWindow(self.baseFrame, style = wx.SP_3D | wx.SP_BORDER)
+
+        self.topView = Viewport.makeTop(self.viewFrame)
+        self.viewFrame.AppendWindow(self.topView)
+
+        self.frontView = Viewport.makeFront(self.viewFrame)
+        self.viewFrame.AppendWindow(self.frontView)
+
+        self.leftView = Viewport.makeLeft(self.viewFrame)
+        self.viewFrame.AppendWindow(self.leftView)
+
+        self.perspView = Viewport.makePerspective(self.viewFrame)
+        self.viewFrame.AppendWindow(self.perspView)
+
+        self.leftBarUpPane = wx.Panel(self.leftFrame)
+        self.leftBarDownPane = wx.Panel(self.leftFrame)
+        self.rightBarUpPane = wx.Panel(self.rightFrame)
+        self.rightBarDownPane = wx.Panel(self.rightFrame)        
+
+        self.leftFrame.SplitHorizontally(self.leftBarUpPane, self.leftBarDownPane)
+        self.rightFrame.SplitHorizontally(self.rightBarUpPane, self.rightBarDownPane)
+        self.mainFrame.SplitVertically(self.leftFrame, self.baseFrame, 200)
+        self.baseFrame.SplitVertically(self.viewFrame, self.rightFrame, 600)
+        
+        self.leftFrame.SetSashGravity(0.5)
+        self.rightFrame.SetSashGravity(0.5)        
+        self.baseFrame.SetSashGravity(1.0)
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self.mainFrame, 1, wx.EXPAND, 0)
+        self.SetSizer(sizer); self.Layout()
+
+    def initialize(self):
+        """Initializes the viewports and editor."""
+        self.Update()
+        ViewportManager.updateAll()
+        self.wxStep()
+        ViewportManager.initializeAll()
+        # Position the camera
+        if base.trackball != None:
+          base.trackball.node().setPos(0, 30, 0)
+          base.trackball.node().setHpr(0, 15, 0)
+
+        # initializing direct
+        if self.fStartDirect:
+            base.startDirect(fWantTk = 0, fWantWx = 0)
+
+            base.direct.disableMouseEvents()
+            newMouseEvents = map(lambda x: "_le_per_%s"%x, base.direct.mouseEvents) +\
+                             map(lambda x: "_le_fro_%s"%x, base.direct.mouseEvents) +\
+                             map(lambda x: "_le_lef_%s"%x, base.direct.mouseEvents) +\
+                             map(lambda x: "_le_top_%s"%x, base.direct.mouseEvents)
+            base.direct.mouseEvents = newMouseEvents
+            base.direct.enableMouseEvents()
+
+            base.direct.disableKeyEvents()
+            keyEvents = map(lambda x: "_le_per_%s"%x, base.direct.keyEvents) +\
+                             map(lambda x: "_le_fro_%s"%x, base.direct.keyEvents) +\
+                             map(lambda x: "_le_lef_%s"%x, base.direct.keyEvents) +\
+                             map(lambda x: "_le_top_%s"%x, base.direct.keyEvents)
+            base.direct.keyEvents = keyEvents
+            base.direct.enableKeyEvents()
+
+            base.direct.disableModifierEvents()
+            modifierEvents = map(lambda x: "_le_per_%s"%x, base.direct.modifierEvents) +\
+                             map(lambda x: "_le_fro_%s"%x, base.direct.modifierEvents) +\
+                             map(lambda x: "_le_lef_%s"%x, base.direct.modifierEvents) +\
+                             map(lambda x: "_le_top_%s"%x, base.direct.modifierEvents)
+            base.direct.modifierEvents = modifierEvents
+            base.direct.enableModifierEvents()
+
+            base.direct.cameraControl.lockRoll = True
+            base.direct.setFScaleWidgetByCam(1)
+
+            unpickables = [
+                "z-guide",
+                "y-guide",
+                "x-guide",
+                "x-disc-geom",
+                "x-ring-line",
+                "x-post-line",
+                "y-disc-geom",
+                "y-ring-line",
+                "y-post-line",
+                "z-disc-geom",
+                "z-ring-line",
+                "z-post-line",
+                "centerLines",
+                "majorLines",
+                "minorLines",
+                "Sphere",]
+
+            for unpickable in unpickables:
+                base.direct.addUnpickable(unpickable)
+
+            base.direct.manipulationControl.optionalSkipFlags |= SKIP_UNPICKABLE
+            base.direct.manipulationControl.fAllowMarquee = 1
+            base.direct.manipulationControl.supportMultiView()
+            base.direct.cameraControl.useMayaCamControls = 1
+            base.direct.cameraControl.perspCollPlane = self.perspView.collPlane
+            for widget in base.direct.manipulationControl.widgetList:
+                widget.setBin('gui-popup', 0)
+                widget.setDepthTest(0)
+
+            # [gjeon] to intercept messages here
+            base.direct.ignore('DIRECT-delete')
+            base.direct.ignore('DIRECT-select')
+            base.direct.ignore('DIRECT-preDeselectAll')
+            base.direct.ignore('DIRECT-toggleWidgetVis')
+            base.direct.fIgnoreDirectOnlyKeyMap = 1
+
+            # [gjeon] do not use the old way of finding current DR
+            base.direct.drList.tryToGetCurrentDr = False
+
+        else:
+            base.direct=None
+        base.closeWindow(base.win)
+        base.win = base.winList[3]        
+
+    def wxStep(self, task = None):
+        """A step in the WX event loop. You can either call this yourself or use as task."""
+        while self.evtLoop.Pending():
+          self.evtLoop.Dispatch()
+        self.wxApp.ProcessIdle()
+        if task != None: return task.cont
+
+    def appInit(self):
+        """Overridden from WxAppShell.py."""
+        # Create a new event loop (to overide default wxEventLoop)
+        self.evtLoop = wx.EventLoop()
+        self.oldLoop = wx.EventLoop.GetActive()
+        wx.EventLoop.SetActive(self.evtLoop)
+        taskMgr.add(self.wxStep, "evtLoopTask")
+                
+    def onViewChange(self, evt, viewIdx):
+        for i in range(4):
+            if viewIdx >=0 and\
+               i != viewIdx:
+                base.winList[i].setActive(0)
+            else:
+                base.winList[i].setActive(1)
+
+        self.viewFrame.SetExpanded(viewIdx)

+ 3 - 0
direct/src/wxwidgets/WxPandaStart.py

@@ -0,0 +1,3 @@
+from WxPandaShell import *
+base.app = WxPandaShell()
+