I believe the offscreen window-type code is broken.
I tried also to create my own off-screen buffer. But it looks base.graphicsEngine.makeOutput relies on a valid Gsg to create an offscreen buffer.
The base.graphicsEngine.makeGsg is also not there any more. The manual seems outdated ?
So far I just able to create an off-screen buffer, use it for rendering, and the base.win will not affect it. You can minimize the panda main window and have the animation run on the screen.
Since the Gsg of the offscreen buffer is tied with the base.win, it is not possible to remove base.win at all ? Unless I can create a Gsg…but makeGsg has gone.
The following code still has a problem. I am not able to control the camera, no mater how I position the camera, the rendered image is not changed. Sometime wrong with my code.
Offscreen buffer version:
import wx, wx.aui
from wx.lib import masked
import sys, StringIO
from pandac.PandaModules import *
MODEL_WIDTH=100
MODEL_HEIGHT=150
# not to use parasite, otherwise it will be affected by the original window
loadPrcFileData("", "prefer-parasite-buffer #f")
# offscreen window-type is not working
#loadPrcFileData("", "window-type offscreen")
loadPrcFileData("", "win-size %d %d" % (MODEL_WIDTH,MODEL_HEIGHT))
#loadPrcFileData("", "require-window 0")
import direct.directbase.DirectStart
from direct.filter.CommonFilters import CommonFilters
from direct.showbase.DirectObject import DirectObject
from direct.actor.Actor import Actor
class ControlWindow(wx.Frame):
def __init__(self, title, pos, size, panda, docking):
self.panda = panda
wx.Frame.__init__(self, None, -1, title, pos, size=size, style=wx.FRAME_SHAPED + wx.FRAME_NO_TASKBAR + wx.SIMPLE_BORDER + wx.STAY_ON_TOP)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.bitmap = None
#self.Bind(wx.EVT_MOTION, self.OnMouseMove)
def drawBitmap(self, dc=None):
if self.bitmap == None:
return
if dc == None:
dc = wx.ClientDC(self)
dc.DrawBitmap(self.bitmap, 0, 0, True)
def OnPaint(self, event):
dc = wx.PaintDC(self)
self.drawBitmap(dc)
def newFrame(self):
screenData = self.panda.GetImage()
if screenData == None:
return
data = screenData.getData()
sbuf = StringIO.StringIO(data)
image = wx.ImageFromStream(sbuf)
self.bitmap = wx.BitmapFromImage(image)
#self.bitmap = wx.Bitmap("a.bmp")
self.bitmap.SetMaskColour(wx.Color(255,0,0))
r = wx.RegionFromBitmap(self.bitmap)
self.hasShape = self.SetShape(r)
self.drawBitmap()
class myApp(wx.App):
WIDTH = 1024
HEIGHT = 740
def __init__(self, panda=None):
self.panda = panda
wx.App.__init__(self, 0)
self.running = True
def OnInit(self):
self.evtLoop = wx.EventLoop()
self.oldLoop = wx.EventLoop.GetActive()
wx.EventLoop.SetActive(self.evtLoop)
self.win = ControlWindow("Demo Master", (200,100), wx.Size(self.WIDTH, self.HEIGHT), self.panda, docking=False)
self.SetTopWindow(self.win)
#self.win.CenterOnScreen()
self.win.Show(True)
self.win.Bind(wx.EVT_CLOSE, self.onClose)
#print "main loop is running" , self.IsMainLoopRunning()
return True
def Cleanup(self):
self.running = False
self.win.Destroy()
def onClose(self, event):
self.Cleanup()
#while self.evtLoop.Pending(): self.evtLoop.Dispatch()
try: base.userExit()
except: sys.exit()
sys.exit()
def setPandaWorld(self, panda):
self.panda = panda
self.win.panda = panda
def createOffscreenBuffer(sort, xsize, ysize):
winprops = WindowProperties.size(xsize,ysize)
props = FrameBufferProperties()
props.setRgbColor(1)
props.setAlphaBits(1)
props.setDepthBits(1)
return base.graphicsEngine.makeOutput(
base.pipe, "offscreenBuffer",
sort, props, winprops,
GraphicsPipe.BFFbPropsOptional | GraphicsPipe.BFRefuseWindow,
base.win.getGsg(), base.win)
class Container(DirectObject):
def __init__(self, wxApp):
self.wxApp = wxApp
self.InitScene()
def InitScene(self):
self.buffer = createOffscreenBuffer(0, MODEL_WIDTH, MODEL_HEIGHT)
self.LoadModel()
self.SetupTexture()
# remove the window will also stop the offscreen buffer to come up,
# because the gsg is shared ?
#base.userExit = lambda: None
#base.graphicsEngine.removeWindow(base.win)
# minimize is not implemented in panda
#props = WindowProperties()
#props.setMinimized(True)
#base.win.requestProperties(props)
def SetupTexture(self):
self.screenTexture = Texture()
self.screenTexture.setMinfilter(Texture.FTLinear)
self.screenTexture.setFormat(Texture.FRgba32)
self.buffer.addRenderTexture(self.screenTexture, GraphicsOutput.RTMCopyRam)
self.screenImage = PNMImage()
def GetImage(self):
if self.screenTexture.hasRamImage():
self.screenTexture.store(self.screenImage)
screenData = StringStream()
#self.screenImage.write(Filename("a.bmp"))
self.screenImage.write(screenData, "ppm")
return screenData
return None
def LoadModel(self):
self.buffer.setClearColor(VBase4(1.0,0.0,0.0,0.0))
self.cam = base.makeCamera2d(self.buffer)
self.render = NodePath("render")
self.cam.reparentTo(self.render)
self.cam.node().setScene(self.render)
self.actor= Actor('panda.egg', {'walk' : 'panda-walk.egg'})
self.actor.setScale(0.25,0.25,0.25)
self.actor.reparentTo(self.render)
self.actor.loop("walk")
self.cam.lookAt(self.actor.getPos())
self.cam.setPos(0, -5, 1.5)
dlight = NodePath(DirectionalLight('dlight'))
dlight.reparentTo(self.cam)
#dlight.reparentTo(self.render)
self.render.setLight(dlight)
def handleWxEvents(wxApp, task):
wxApp.win.newFrame()
while wxApp.evtLoop.Pending():
wxApp.evtLoop.Dispatch()
wxApp.ProcessIdle()
if task != None and wxApp.running:
return task.cont
def Start():
base.setFrameRateMeter(False)
FPS = 30
globalClock = ClockObject.getGlobalClock()
globalClock.setMode(ClockObject.MLimited)
globalClock.setFrameRate(FPS)
wxApp = myApp(None)
container = Container(wxApp)
wxApp.setPandaWorld(container)
taskMgr.add(handleWxEvents, 'handleWxEvents', extraArgs=[wxApp], appendTask=True)
run()
Start()