PyOpenGL + CEF Python Demo: Play with the controls to change some properties about the spinning triangle in the background! The triangle rendering uses PyOpenGL, while the UI rendering and input use CEF Python.
December 11, 2016 ยท View on GitHub
from cefpython3 import cefpython as cef import sys import pygame from PIL import Image from OpenGL.GL import * from OpenGL.GLU import * import inspect import math
class CEFSettings: app_settings = { "auto_zooming": "system_dpi", "debug": False, "locales_dir_path": cef.GetModuleDirectory()+"/locales", "resources_dir_path": cef.GetModuleDirectory(), "browser_subprocess_path": "%s/%s" % (cef.GetModuleDirectory(), "subprocess"), "unique_request_context_per_browser": True, "downloads_enabled": False, "remote_debugging_port": 0, "context_menu": { "enabled": False, }, "ignore_certificate_errors": True, }
browser_settings = {
"file_access_from_file_urls_allowed": True,
"universal_access_from_file_urls_allowed": True,
}
command_line_settings = {
"disable-gpu": "",
"disable-gpu-compositing": "",
"enable-begin-frame-scheduling": "",
"disable-d3d11": "",
"off-screen-rendering-enabled": "",
"off-screen-frame-rate": "60",
"disable-gpu-vsync": "",
"disable-web-security": "",
}
class Window: def init(self, title, width, height): self.title = title self.width = width self.height = height cef.DpiAware.SetProcessDpiAware() cef.Initialize(CEFSettings.app_settings, CEFSettings.command_line_settings)#need to call before setting up pygame self.setup_pygame() self.setup_ui_texture() self.setup_cef()
def setup_pygame(self):
size = (self.width, self.height)
flags = 0
flags = pygame.OPENGL | pygame.DOUBLEBUF
pygame.init()
dummy_screen = pygame.display.set_mode((1, 1), flags)
max_msaa = glGetIntegerv(GL_MAX_SAMPLES)#unfortunately works only AFTER creating a dummy window
pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLEBUFFERS, 1)
pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLESAMPLES, max_msaa)
self.screen = pygame.display.set_mode(size, flags)
self.window = pygame.display.get_wm_info()["window"]
self.clock = pygame.time.Clock()
def setup_cef(self):
windowInfo = cef.WindowInfo()
windowInfo.SetAsOffscreen(self.window)
windowInfo.SetTransparentPainting(True)
self.browser = cef.CreateBrowserSync(windowInfo, browserSettings=CEFSettings.browser_settings, navigateUrl="file:///transparent-test.html")
empty_texture = pygame.Surface((self.width, self.height))
self.client = ClientHandler(self.browser, empty_texture)
self.browser.SetClientHandler(self.client)
self.js_bindings = cef.JavascriptBindings()
def setup_ui_texture(self):
self.cef_tex_id = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.cef_tex_id)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glBindTexture(GL_TEXTURE_2D, 0)
def load_html_ui(self, ui_url):
self.browser.LoadUrl(ui_url)
def render_html_ui(self):
glEnable(GL_TEXTURE_2D)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, self.width, self.height, 0, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glBindTexture(GL_TEXTURE_2D, self.cef_tex_id)
tex_surface = pygame.image.tostring(self.client.texture, "RGBA")
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 800, 600, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_surface)
glBegin(GL_QUADS)
glTexCoord(0, 0)
glVertex(0, 0, 0)
glTexCoord(0, 1)
glVertex(0, self.height, 0)
glTexCoord(1, 1)
glVertex(self.width, self.height, 0)
glTexCoord(1, 0)
glVertex(self.width, 0, 0)
glEnd()
glBindTexture(GL_TEXTURE_2D, 0)
def update(self, app_func):
for event in pygame.event.get():
if event.type == pygame.QUIT:
cef.Shutdown()
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = event.pos
if event.button == 1:#left mouse button
self.browser.SendMouseClickEvent(mouse_x, mouse_y, cef.MOUSEBUTTON_LEFT, False, 1)
elif event.type == pygame.MOUSEBUTTONUP:
mouse_x, mouse_y = event.pos
if event.button == 1:
self.browser.SendMouseClickEvent(mouse_x, mouse_y, cef.MOUSEBUTTON_LEFT, True, 1)
elif event.type == pygame.MOUSEMOTION:
mouse_x, mouse_y = event.pos
self.browser.SendMouseMoveEvent(mouse_x, mouse_y, True)
cef.MessageLoopWork()
glClear(GL_COLOR_BUFFER_BIT)
glEnable(GL_BLEND)
glEnable(GL_MULTISAMPLE)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
app_func()
self.render_html_ui()
pygame.display.set_caption("CEF PyOpenGL Demo")
pygame.display.flip()
self.clock.tick(60)
class ClientHandler: def init(self, browser, texture): self.browser = browser self.texture = texture
def OnPaint(self, browser, paintElementType, dirtyRects, buffer, width, height):
data = buffer.GetString(mode="rgba", origin="bottom-left")
img = Image.frombuffer('RGBA', (width, height), data, 'raw', 'BGRA')
img = pygame.image.fromstring(img.tobytes(), (width, height), "RGBA", True)
self.texture = img
def GetViewRect(self, browser, rect):
width, height = self.texture.get_size()
rect.extend([0, 0, width, height])
return True
def toggle_color(value): global tri_colored tri_colored = value
def update_rotation(value): global tri_speed tri_speed = float(value)
def update_scale(scale_value): global tri_scale tri_scale = float(scale_value)
def render_tri(): global tri_colored global tri_speed global tri_rotation global tri_scale glDisable(GL_TEXTURE_2D) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(30, 800/600.0, 1, 1000) #glOrtho(-1, 1, -1, 1, -1, 1) glMatrixMode(GL_MODELVIEW) glLoadIdentity() tri_rotation += tri_speed glRotate(tri_rotation, 0, 0, 1)
glTranslate(0, 0, -10)
glScale(tri_scale, tri_scale, tri_scale)
glBegin(GL_TRIANGLES)
if tri_colored:
glColor(1, 0, 0)
glVertex(-1, -1/math.sqrt(3), 0)
glColor(0, 1, 0)
glVertex(0, 2/math.sqrt(3), 0)
glColor(0, 0, 1)
glVertex(1, -1/math.sqrt(3), 0)
else:
glColor(0.5, 0.5, 0.5)
glVertex(-1, -1/math.sqrt(3), 0)
glVertex(0, 2/math.sqrt(3), 0)
glVertex(1, -1/math.sqrt(3), 0)
glEnd()
glColor(1, 1, 1)
def main_loop(): render_tri()
if name == "main": window = Window("PyOpenGL + CEFPython Test", 800, 600) window.load_html_ui("file:///transparent-test.html") window.js_bindings.SetFunction("toggle_color", toggle_color) window.js_bindings.SetProperty("sources", {"toggle_color": inspect.getsource(toggle_color)}) window.js_bindings.SetFunction("update_rotation", update_rotation) window.js_bindings.SetProperty("sources", {"update_rotation": inspect.getsource(update_rotation)}) window.js_bindings.SetFunction("update_scale", update_scale) window.js_bindings.SetProperty("sources", {"update_scale": inspect.getsource(update_scale)}) window.browser.SetJavascriptBindings(window.js_bindings) tri_rotation = 0 tri_colored = False tri_speed = 0.0 tri_scale = 1.0 while True: window.update(main_loop)