Hi all,
I did never get the examples here working, so I went experimenting and did get something thats working. This I wanted to share with you all. Also did some experimenting to get panda working with QGLWidget. Its working, but the Panda window stay’s open wathever I try. So I hope with these examples that we can have some desent QGLWidget without the Panda window.
without QGLWidget, eg with a normal QWidget
import platform
if platform.architecture()[0] != "32bit":
raise Exception("Only 32bit architecture is supported")
from pandac.PandaModules import loadPrcFileData
#loadPrcFileData("", "window-type offscreen") # Set Panda to draw its main window in an offscreen buffer
loadPrcFileData("", "load-display pandagl")
loadPrcFileData("", "model-path c:/Panda3D-1.8.1/models")
loadPrcFileData("", "win-size 800 600")
loadPrcFileData("", "show-frame-rate-meter #t")
# PyQt imports
from PyQt4 import QtGui
from PyQt4 import QtCore
import os, sys
# Panda imports
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import WindowProperties, GraphicsOutput, Texture, StringStream, PNMImage
from direct.interval.LerpInterval import LerpHprInterval
from pandac.PandaModules import Point3
# Set up Panda environment
import direct.directbase.DirectStart
from struct import *
P3D_WIN_WIDTH = 800
P3D_WIN_HEIGHT = 600
def GetApplicationPath(file=None):
import re, os
# If file is None return current directory without trailing slash.
if file is None:
file = ""
# Only when relative path.
if not file.startswith("/") and not file.startswith("\\") and (
not re.search(r"^[\w-]+:", file)):
if hasattr(sys, "frozen"):
path = os.path.dirname(sys.executable)
elif "__file__" in globals():
path = os.path.dirname(os.path.realpath(__file__))
else:
path = os.getcwd()
path = path + os.sep + file
path = re.sub(r"[/\\]+", re.escape(os.sep), path)
path = re.sub(r"[/\\]+$", "", path)
return path
return str(file)
def ExceptHook(excType, excValue, traceObject):
import traceback, os, time, codecs
# This hook does the following: in case of exception write it to
# the "error.log" file, display it to the console, shutdown CEF
# and exit application immediately by ignoring "finally" (_exit()).
errorMsg = "\n".join(traceback.format_exception(excType, excValue, traceObject))
errorFile = GetApplicationPath("error.log")
try:
appEncoding = cefpython.g_applicationSettings["string_encoding"]
except:
appEncoding = "utf-8"
if type(errorMsg) == bytes:
errorMsg = errorMsg.decode(encoding=appEncoding, errors="replace")
try:
with codecs.open(errorFile, mode="a", encoding=appEncoding) as fp:
fp.write("\n[%s] %s\n" % (time.strftime("%Y-%m-%d %H:%M:%S"), errorMsg))
except:
print("WARNING: failed writing to error file: %s" % (errorFile))
# Convert error message to ascii before printing, otherwise
# you may get error like this:
# | UnicodeEncodeError: 'charmap' codec can't encode characters
errorMsg = errorMsg.encode("ascii", errors="replace")
errorMsg = errorMsg.decode("ascii", errors="replace")
print("\n"+errorMsg+"\n")
os._exit(1)
class MainWindow(QtGui.QMainWindow):
mainFrame = None
def __init__(self):
super(MainWindow, self).__init__(None)
panHandler = PandaHandler()
self.mainFrame = MainFrame(panHandler.screenTexture)
panHandler.bindToWindow(int(self.mainFrame.winId()))
self.setCentralWidget(self.mainFrame)
self.resize(800, 600)
self.setWindowTitle('PyQT example')
self.setFocusPolicy(QtCore.Qt.StrongFocus)
class MainFrame(QtGui.QWidget):
def __init__(self, texture, parent=None):
super(MainFrame, self).__init__(parent)
#self.setGeometry(50, 50, 800, 600)
#self.setWindowTitle("PandaQt")
#self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint) # Setup the window so its frameless
self.pandaTexture = texture
# Setup a timer in Qt that runs taskMgr.step() to simulate Panda's own main loop
pandaTimer = QtCore.QTimer(self)
self.connect(pandaTimer, QtCore.SIGNAL("timeout()"), taskMgr.step)
pandaTimer.start(0)
# Setup another timer that redraws this widget in a specific FPS
redrawTimer = QtCore.QTimer(self)
self.connect(redrawTimer, QtCore.SIGNAL("timeout()"), self, QtCore.SLOT("update()"))
redrawTimer.start(1000/30)
self.paintSurface = QtGui.QPainter()
self.rotate = QtGui.QTransform()
self.rotate.rotate(180)
self.out_image = QtGui.QImage()
def showEvent(self, event):
self.desktopBg = QtGui.QPixmap.grabWindow(QtGui.QApplication.desktop ().winId(), self.geometry().x(),self.geometry().y(), self.rect().width(), self.rect().height())
# Use the paint event to pull the contents of the panda texture to the widget
def paintEvent(self, event):
if self.pandaTexture.mightHaveRamImage():
self.pandaTexture.setFormat(Texture.FRgba32)
#print "Should draw yes?"
data = self.pandaTexture.getRamImage().getData()
img = QtGui.QImage(data, self.pandaTexture.getXSize(), self.pandaTexture.getYSize(), QtGui.QImage.Format_ARGB32).mirrored()
self.paintSurface.begin(self)
self.paintSurface.drawPixmap(0, 0, self.desktopBg)
self.paintSurface.drawImage(0, 0, img)
self.paintSurface.end()
pixmap = QtGui.QPixmap.fromImage(img)
self.setMask(pixmap.mask())
class PandaHandler(DirectObject):
def __init__(self):
base.disableMouse()
base.camera.setPos(0, -28, 6)
self.testModel = loader.loadModel('panda.egg.pz')
self.testModel.reparentTo(render)
self.rotateInterval = LerpHprInterval(self.testModel, 3, Point3(360, 0, 0))
self.rotateInterval.loop()
self.screenTexture = Texture()
self.screenTexture.setMinfilter(Texture.FTLinear)
self.screenTexture.setFormat(Texture.FRgba32)
print "Format is", self.screenTexture.getFormat()
base.win.addRenderTexture(self.screenTexture, GraphicsOutput.RTMCopyRam)
def bindToWindow(self, windowHandle):
gsg = None
wp = WindowProperties().getDefault()
wp.setOrigin(0,0)
wp.setSize(800, 600)
if platform.system() != 'Darwin':
try:
wp.setParentWindow(windowHandle)
except OverflowError:
# Sheesh, a negative value from GetHandle(). This can
# only happen on 32-bit Windows.
wp.setParentWindow(windowHandle & 0xffffffff)
#wp.setParentWindow(windowHandle)
base.openWindow(props = wp, gsg = gsg, type = 'offscreen', unexposedDraw = False)
self.wp = wp
if __name__ == '__main__':
print("PyQt version: %s" % QtCore.PYQT_VERSION_STR)
print("QtCore version: %s" % QtCore.qVersion())
sys.excepthook = ExceptHook
settings = {
"log_file": GetApplicationPath("debug.log"),
"release_dcheck_enabled": False # Enable only when debugging.
}
app = QtGui.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
app.exec_()
# Need to destroy QApplication(), otherwise Shutdown() fails.
# Unset main window also just to be safe.
del mainWindow
del app
sys.exit(0)
and with the QGLWidget
import platform
if platform.architecture()[0] != "32bit":
raise Exception("Only 32bit architecture is supported")
from pandac.PandaModules import loadPrcFileData
#loadPrcFileData("", "window-type offscreen") # Set Panda to draw its main window in an offscreen buffer
loadPrcFileData("", "load-display pandagl")
loadPrcFileData("", "model-path c:/Panda3D-1.8.1/models")
loadPrcFileData("", "win-size 800 600")
loadPrcFileData("", "show-frame-rate-meter #t")
# PyQt imports
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4 import QtOpenGL
import OpenGL
OpenGL.ERROR_CHECKING = True
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL import error
oglError = error
import os, sys, platform
# Panda imports
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import WindowProperties, FrameBufferProperties, CallbackGraphicsWindow, GraphicsOutput, Texture, StringStream, PNMImage
from direct.interval.LerpInterval import LerpHprInterval
from pandac.PandaModules import Point3
# Set up Panda environment
import direct.directbase.DirectStart
from struct import *
P3D_WIN_WIDTH = 800
P3D_WIN_HEIGHT = 600
def GetApplicationPath(file=None):
import re, os
# If file is None return current directory without trailing slash.
if file is None:
file = ""
# Only when relative path.
if not file.startswith("/") and not file.startswith("\\") and (
not re.search(r"^[\w-]+:", file)):
if hasattr(sys, "frozen"):
path = os.path.dirname(sys.executable)
elif "__file__" in globals():
path = os.path.dirname(os.path.realpath(__file__))
else:
path = os.getcwd()
path = path + os.sep + file
path = re.sub(r"[/\\]+", re.escape(os.sep), path)
path = re.sub(r"[/\\]+$", "", path)
return path
return str(file)
def ExceptHook(excType, excValue, traceObject):
import traceback, os, time, codecs
# This hook does the following: in case of exception write it to
# the "error.log" file, display it to the console, shutdown CEF
# and exit application immediately by ignoring "finally" (_exit()).
errorMsg = "\n".join(traceback.format_exception(excType, excValue, traceObject))
errorFile = GetApplicationPath("error.log")
appEncoding = "utf-8"
if type(errorMsg) == bytes:
errorMsg = errorMsg.decode(encoding=appEncoding, errors="replace")
try:
with codecs.open(errorFile, mode="a", encoding=appEncoding) as fp:
fp.write("\n[%s] %s\n" % (time.strftime("%Y-%m-%d %H:%M:%S"), errorMsg))
except:
print("WARNING: failed writing to error file: %s" % (errorFile))
# Convert error message to ascii before printing, otherwise
# you may get error like this:
# | UnicodeEncodeError: 'charmap' codec can't encode characters
errorMsg = errorMsg.encode("ascii", errors="replace")
errorMsg = errorMsg.decode("ascii", errors="replace")
print("\n"+errorMsg+"\n")
os._exit(1)
class MainWindow(QtGui.QMainWindow):
mainFrame = None
def __init__(self):
super(MainWindow, self).__init__(None)
self.mainFrame = EmbeddedPandaWindow()
self.setCentralWidget(self.mainFrame)
self.resize(800, 600)
self.setWindowTitle('PyQT example')
self.setFocusPolicy(QtCore.Qt.StrongFocus)
class EmbeddedPandaWindow(QtOpenGL.QGLWidget):
""" This class implements a Panda3D window that is directly
embedded within the frame. It is fully supported on Windows,
partially supported on Linux, and not at all on OSX. """
def __init__(self, *args, **kw):
gsg = None
if 'gsg' in kw:
gsg = kw['gsg']
del kw['gsg']
fbprops = kw.get('fbprops', None)
if fbprops == None:
fbprops = FrameBufferProperties.getDefault()
QtOpenGL.QGLWidget.__init__(self, *args, **kw)
base.disableMouse()
base.camera.setPos(0, -28, 6)
self.testModel = loader.loadModel('panda.egg.pz')
self.testModel.reparentTo(render)
self.rotateInterval = LerpHprInterval(self.testModel, 3, Point3(360, 0, 0))
self.rotateInterval.loop()
self.callbackWindowDict = {
'Events' : self.__eventsCallback,
'Properties' : self.__propertiesCallback,
'Render' : self.__renderCallback,
}
# Make sure we have an OpenGL GraphicsPipe.
if not base.pipe:
base.makeDefaultPipe()
self.pipe = base.pipe
if self.pipe.getInterfaceName() != 'OpenGL':
base.makeAllPipes()
for self.pipe in base.pipeList:
if self.pipe.getInterfaceName() == 'OpenGL':
break
if self.pipe.getInterfaceName() != 'OpenGL':
raise StandardError, "Couldn't get an OpenGL pipe."
self.win = base.openWindow(callbackWindowDict = self.callbackWindowDict, pipe = self.pipe, gsg = gsg, type = 'none', unexposedDraw = True)
# Setup a timer in Qt that runs taskMgr.step() to simulate Panda's own main loop
pandaTimer = QtCore.QTimer(self)
self.connect(pandaTimer, QtCore.SIGNAL("timeout()"), taskMgr.step)
pandaTimer.start(0)
def closeEvent(self, event):
self.cleanup()
event.Skip()
def cleanup(self):
""" Parent windows should call cleanup() to clean up the
wxPandaWindow explicitly (since we can't catch EVT_CLOSE
directly). """
if self.win:
base.closeWindow(self.win)
self.win = None
def onSize(self, event):
wp = WindowProperties()
wp.setOrigin(0, 0)
wp.setSize(*self.GetClientSize())
self.win.requestProperties(wp)
event.Skip()
def __eventsCallback(self, data):
data.upcall()
def __propertiesCallback(self, data):
data.upcall()
def __renderCallback(self, data):
cbType = data.getCallbackType()
if cbType == CallbackGraphicsWindow.RCTBeginFrame:
if not self.isVisible():
data.setRenderFlag(False)
return
self.updateGL()
# Don't upcall() in this case.
return
elif cbType == CallbackGraphicsWindow.RCTEndFlip:
# Now that we've swapped, ask for a refresh, so we'll
# get another paint message if the window is still
# visible onscreen.
self.updateGL()
data.upcall()
if __name__ == '__main__':
print("PyQt version: %s" % QtCore.PYQT_VERSION_STR)
print("QtCore version: %s" % QtCore.qVersion())
sys.excepthook = ExceptHook
settings = {
"log_file": GetApplicationPath("debug.log"),
"release_dcheck_enabled": False # Enable only when debugging.
}
app = QtGui.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
app.exec_()
# Need to destroy QApplication(), otherwise Shutdown() fails.
# Unset main window also just to be safe.
del mainWindow
del app
sys.exit(0)
I hope that some of you can help to make these examples working, so that beginners can benefit from our work…
Happy Panda coding!!!