Transparent window and ....

I have lots of questinos about how to create a transparent window.

1\ Is there a direct way to create a transparent background window in panda?
2\ If (1) is not. So when I used wxPython creating a transparent background window, How do I put my panda model into that window? Pls give me some codes. I don’t know how to deal with the loop. Although there is a chapter in manual named “Main loop”, it doesn’t descrip wxpython control the mainloop,and panda’s loop is controlled in the wx’s loop.
3\ If I put my panda model into wxPython window, can the mousetask work? I used CollisionRay to pick my model. So in wxPython window ,can I also pick it?

Thanks a lot!

Haha, befor I try and answer do you mean transparent the windows as in the screen/app. or do you mean transparent a window you see into like a door?

I mean the first one.

What I want is just a pet in the desktop. No window, just a jumping\running pet(cat or a little dog). So I want a transparent window, which my 3D’s pet could be in.

And when I press right mouse button on it, there will be a menu.(So I asked the CollisionRay about pick on it)

Beg for a answer

I think the only way to do this is to render to an offscreen buffer, then copy the pixels by hand onto a 2-d window. Normally, 3-D windows can’t be transparent to the desktop. Even if you parent the Panda window to a wxPython window, it will still not be transparent.

Some people have tried experiments with this sort of thing before. I don’t have any experience with it myself.

David

I had looked into this some time ago, but never found a solution.

What I did learn is that there are two parts to this problem. First is making only part of the window transparent. Second is passing clicks through the part of the window that isn’t transparent.

I did find a python script that would fade the whole window (without passing any clicks through), but unfortunately I don’t have the bookmark anymore. That’s all I know… There was surprisingly little information on transparent windows with python last time I searched.

Sorry I couldn’t help out more…

Feel free to spread the knowledge if you find a solution :smiley:

Check out this thread:

discourse.panda3d.org/viewtopic.php?t=4323

Can’t give you any code for this, I only have experience with doing this in PyQT and it was only partially succesful. If you want to do this in wxPython, the first step is to learn wxPython. A few minutes of digging gives me this pretty old code sample from a mailing list. I suspect wxPython might also come with a sample script showing how to do masked regions.

Idk maybe silly but if you do set it up to a wxpython window, wouldnt just calling

import wx
frame=wx.GetTopLevelParent(shell)
frame.SetTransparent(200)

Work?

copying pixels around is a slow. but working sollution.
you can check the already existing open-source windowsitters like macopix to see how it’s done. dont expect high frame-rates or big drawing areas.
upcomming rendering interfaces (especially for linux) have the possibility to directly render such stuff, which would allow equally good performance as in a “normal” window (once panda supports those new techniques).
QT4 is another promising project with simmilar capabilities, thought i dont know about the details there. there is cairo which is used to render opengl grafics into 2d-content, including stuff like dekstop applets.

Here is the sample code. It uses the Shaped Frame feature in wxPython, not sure if it is supported on Linux platform or not.

One problem about this program, if the panda main window is hidden by other windows, the texture is not updated. May be it can be easily fixed ?

import wx, wx.aui
from    wx.lib import masked
import sys, StringIO
from pandac.PandaModules import *
import direct.directbase.DirectStart
from direct.filter.CommonFilters import CommonFilters
from direct.showbase.DirectObject import DirectObject
from direct.actor.Actor import Actor


MODEL_WIDTH=100
MODEL_HEIGHT=150
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

class Container(DirectObject):
    def __init__(self, wxApp):
        self.wxApp = wxApp
        self.InitScene()

    def InitScene(self):
        self.LoadModel()
        self.SetupTexture()

    def SetupTexture(self):
        self.screenTexture = Texture()
        self.screenTexture.setMinfilter(Texture.FTLinear)
        self.screenTexture.setFormat(Texture.FRgba32)
        base.win.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):
        base.setBackgroundColor(255, 0, 0)
        base.disableMouse()
        base.cam.setPos(0, -5, 1.5)
        self.actor= Actor('panda.egg', {'walk' : 'panda-walk.egg'})
        self.actor.setScale(0.25,0.25,0.25)
        self.actor.reparentTo(render)
        self.actor.loop("walk")
        base.camera.lookAt(self.actor.getPos())

        dlight = NodePath(DirectionalLight('dlight'))
        dlight.reparentTo(base.cam)
        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():
    wp = WindowProperties().getDefault()
    wp.setOrigin(100,100)
    wp.setSize(MODEL_WIDTH, MODEL_HEIGHT)
    base.win.requestProperties(wp)
    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()

Cool! I didn’t even think of using PNMImage.write to get an image into wxPython. Note that 1.6 will have the getRamImageAs function which makes that a lot easier (probably faster, too)

I believe you can hide the main window by making it an offscreen buffer:

loadPrcFileData("", "window-type offscreen")

(before importing DirectStart)

“window-type offscreen” failed before in my PyQT tests. Has it been fixed in 1.6.0? Is a possible work around could be setting window-type to none and making your own offscreen buffer?

Thanks for so many warmhearted people helped me.

Thank you very much for all.

to pro-rsoft: when will 1.6 release? Is there a schedule?

I tested :

from pandac.PandaModules import loadPrcFileData
loadPrcFileData("", "window-type offscreen")

Not in wx, just in panda 1.5.4, the error information:
C:\3D\filename>python Pet.py
DirectStart: Starting the game.
Warning: DirectNotify: category ‘Interval’ already exists
Known pipe types:
wglGraphicsPipe
(all display modules loaded.)
:ShowBasewarning: Unable to open ‘offscreen’ window.
Traceback (most recent call last):
File “Pet.py”, line 6, in
import direct.directbase.DirectStart
File “C:\Panda3D-1.5.4\direct\src\directbase\DirectStart.py”, line 4, in
ShowBase.ShowBase()
File “C:\Panda3D-1.5.4\direct\src\showbase\ShowBase.py”, line 241, in init

self.openDefaultWindow(startDirect = False, props=props)

File “C:\Panda3D-1.5.4\direct\src\showbase\ShowBase.py”, line 706, in openDefa
ultWindow
raise StandardError, ‘Could not open window.’
StandardError: Could not open window.

Is it a bug of panda? If not ,how to fix it?

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()

Oops.

Change it line
self.cam = base.makeCamera2d(self.buffer)
to
self.cam = base.makeCamera(self.buffer)

Now it is ok.

I have seen it.

1–When I minimize the panda window ,the wx window’s panda won’t walk.
How to keep it walking?

2–What I want is just the shaped window,so how to hide the panda main window(at the same time the shaped window also run)?

Well. Then I am not sure how to do it.

The first example will need the main window of panda to display normally for the animation to run.

The second example I post, is supposed to work like what you describe. It is working well on my machine, Windows XP, OpenGL driver, with NVIDIA 9500GT.

OK. Thank you very much.

Could you give me your prc file? Maybe something in it influence the result.