CEF and CEFPython are new BSD license libraries for render to texture chromium. The most simple implementation renders webpages into panda3d textures. Using javascript and callbacks CEF can be used to create powerful UI tools.
Installation: I’ve only tested this with panda3d cvs for 1.9 on Arch Linux 64. From CEFPython click on the Download CEF3 link for your appropriate OS. I installed via disutils.
Basic script. Gist with additional demos (3 as of this post)
from cefpython3 import cefpython
import os
import sys
from panda3d.core import loadPrcFileData
loadPrcFileData("", "Panda3D example")
loadPrcFileData("", "fullscreen 0")
loadPrcFileData("", "win-size 1024 768")
import direct.directbase.DirectStart
from panda3d.core import CardMaker, Texture
settings = {
"log_severity": cefpython.LOGSEVERITY_INFO, # LOGSEVERITY_VERBOSE
#"log_file": GetApplicationPath("debug.log"), # Set to "" to disable.
"release_dcheck_enabled": True, # Enable only when debugging.
# This directories must be set on Linux
"locales_dir_path": cefpython.GetModuleDirectory()+"/locales",
"resources_dir_path": cefpython.GetModuleDirectory(),
"browser_subprocess_path": "%s/%s" % (
cefpython.GetModuleDirectory(), "subprocess")
}
class ClientHandler:
"""A client handler is required for the browser to do built in callbacks back into the application."""
browser = None
texture = None
def __init__(self, browser, texture):
self.browser = browser
self.texture = texture
def OnPaint(self, browser, paintElementType, dirtyRects, buffer, width, height):
img = self.texture.modifyRamImage()
if paintElementType == cefpython.PET_POPUP:
print("width=%s, height=%s" % (width, height))
elif paintElementType == cefpython.PET_VIEW:
img.setData(buffer.GetString(mode="rgba", origin="bottom-left"))
else:
raise Exception("Unknown paintElementType: %s" % paintElementType)
def GetViewRect(self, browser, rect):
width = self.texture.getXSize()
height = self.texture.getYSize()
rect.append(0)
rect.append(0)
rect.append(width)
rect.append(height)
return True
def GetScreenPoint(self, browser, viewX, viewY, screenCoordinates):
#return False
print("GetScreenPoint()")
return False
def OnLoadEnd(self, browser, frame, httpStatusCode):
return
self._saveImage()
def OnLoadError(self, browser, frame, errorCode, errorText, failedURL):
print("load error", browser, frame, errorCode, errorText, failedURL)
'''def setBrowserSize(window=None):
"""Use something like this for a full screen UI. Texture and browser size should equal window size. Also remember to set panda textures to ignore power of 2"""
width = int(round(base.win.getXSize() * 0.75))
height = int(round(base.win.getYSize() * 0.75))
texture.setXSize(width)
texture.setYSize(height)
browser.WasResized()
#browser.SetSize(cefpython.PET_VIEW, width, height)'''
def messageLoop(task):
cefpython.MessageLoopWork()
return task.cont
cefpython.g_debug = True
cefpython.Initialize(settings)
texture = Texture()
texture.setXSize(1024)
texture.setYSize(1024)
texture.setCompression(Texture.CMOff)
texture.setComponentType(Texture.TUnsignedByte)
texture.setFormat(Texture.FRgba4)
cardMaker = CardMaker("browser2d")
cardMaker.setFrame(-0.75, 0.75, -0.75, 0.75)
node = cardMaker.generate()
#For UI attach to render2d
nodePath = render.attachNewNode(node)
nodePath.setTexture(texture)
windowHandle = base.win.getWindowHandle().getIntHandle()
windowInfo = cefpython.WindowInfo()
#You can pass 0 to parentWindowHandle, but then some things like context menus and plugins may not display correctly.
windowInfo.SetAsOffscreen(windowHandle)
#windowInfo.SetAsOffscreen(0)
# By default window rendering is 30 fps, let's change
# it to 60 for better user experience when scrolling.
browserSettings = {}
# Using non about:blank in constructor results in error before render handler callback is set.
# Either set it before/during construction, or set it after then call LoadURL after it is set.
browser = cefpython.CreateBrowserSync(
windowInfo, browserSettings,
navigateUrl="http://www.panda3d.org")
browser.SendFocusEvent(True)
browser.SetClientHandler(ClientHandler(browser, texture))
def on_load_end(*args, **kwargs): return # Example of one kind of call back
browser.SetClientCallback("OnLoadEnd", on_load_end)
browser.WasResized()
''' IMPORTANT: there is a bug in CEF 3 that causes js bindings to be removed when LoadUrl() is called (see http://www.magpcss.org/ceforum/viewtopic.php?f=6&t=11009). A temporary fix to this bug is to do the navigation through javascript by calling: GetMainFrame().ExecuteJavascript('window.location="http://google.com/"'). '''
#browser.GetMainFrame().ExecuteJavascript('window.location="http://www.panda3d.org"')
#browser.GetMainFrame().LoadUrl("http://wwww.panda3d.org")
#base.accept("window-event", setBrowserSize)
taskMgr.add(messageLoop, "CefMessageLoop")
run()
cefpython.Shutdown()