class ExportViewTarget(object): def __init__(self, project, filename, parent): self.mutex = QMutex() self.project = project self.filename = filename self.parent = parent self.surface = QOffscreenSurface() self.surface.setFormat(QSurfaceFormat.defaultFormat()) self.surface.create() def destroy(self): self.surface.destroy() def render(self, view, uniforms=dict()): self.project.setCameraMode('view') self.project.setCameraViewRef(view) self.project.setCameraAtOrigin() self.project.render(self.ctx.functions(), view.info.width, view.info.height, uniforms) depth = self.project.renderer.depthmap(self.ctx.functions(), view.info.width, view.info.height) return depth def __enter__(self): self.mutex.lock() self.ctx = QOpenGLContext() self.ctx.setShareContext(self.parent) self.ctx.create() if not self.ctx.makeCurrent(self.surface): raise Exception("cannot make context current") self.project.renderer.lock() def __exit__(self, type, value, tb): self.project.renderer.unlock() self.ctx.doneCurrent() del self.ctx self.mutex.unlock()
def initialize(self, size: QSize, shareContext: QOpenGLContext) -> None: """ Initialize offscreen renderer. Args: size: The size of the area available for rendering. shareContext: OpenGL context used as a share context. Raises: RuntimeError: If the renderer has already been initialized. """ print(f'QmlOffscreenRenderer.initialize: {size}') if self.initialized: raise RuntimeError('Already initialized') context = QOpenGLContext() context.setShareContext(shareContext) context.setFormat(get_default_format(gles=False)) context.create() assert not context.isOpenGLES(), "We need glGetTexImage from OpenGL" self.size = size # Create offscreen surface with initialized format surface = QOffscreenSurface() surface.setFormat(context.format()) surface.create() self.ctx = RenderContext(context, surface) # Set up quick rendering self._control = control = QQuickRenderControl() self._window = window = QQuickWindow(control) self._cursor = self._window.cursor() # Don't polish/sync/render immediately for better performance, use a timer self._renderTimer = renderTimer = QTimer() renderTimer.setSingleShot(True) renderTimer.setInterval(5) renderTimer.timeout.connect(self._onRenderTimer) self._syncTimer = syncTimer = QTimer() syncTimer.setSingleShot(True) syncTimer.setInterval(5) syncTimer.timeout.connect(self._onSyncTimer) syncTimer.destroyed.connect(self._onSyncTimerDestroyed) # Request to create frame buffer window.sceneGraphInitialized.connect(self._onSceneGraphInitialized) # Request to release frame buffer window.sceneGraphInvalidated.connect(self._onSceneGraphInvalidated) # Only render is needed control.renderRequested.connect(self._onRenderRequested) # Polish, sync & render control.sceneChanged.connect(self._onSceneChanged) self.initialized = True # Attach root item self.rootItem.setParentItem(self._window.contentItem()) self._window.contentItem().forceActiveFocus() self._updateSizes() self.ctx.makeCurrent() self._control.initialize(self.ctx.glContext)
def initialize(self, size: QSize, shareContext: QOpenGLContext) -> None: """ Initialize offscreen renderer. Args: size: The size of the area available for rendering. shareContext: OpenGL context used as a share context. Raises: RuntimeError: If the renderer has already been initialized. """ print(f'QmlOffscreenRenderer.initialize: {size}') if self.initialized: raise RuntimeError('Already initialized') format = QSurfaceFormat() format.setDepthBufferSize(16) format.setStencilBufferSize(8) context = QOpenGLContext() context.setFormat(format) context.setShareContext(shareContext) context.create() self.size = size self.context = context # Create offscreen surface with initialized format self._surface = surface = QOffscreenSurface() surface.setFormat(context.format()) surface.create() # Set up quick rendering self._control = control = QQuickRenderControl() self._window = window = QQuickWindow(control) self._engine = engine = QQmlEngine() if not engine.incubationController(): engine.setIncubationController(window.incubationController()) # Don't polish/sync/render immediately for better performance, use a timer self._renderTimer = renderTimer = QTimer() renderTimer.setSingleShot(True) renderTimer.setInterval(5) renderTimer.timeout.connect(self._onRenderTimer) self._syncTimer = syncTimer = QTimer() syncTimer.setSingleShot(True) syncTimer.setInterval(5) syncTimer.timeout.connect(self._onSyncTimer) syncTimer.destroyed.connect(self._onSyncTimerDestroyed) # Request to create frame buffer window.sceneGraphInitialized.connect(self._onSceneGraphInitialized) # Request to release frame buffer window.sceneGraphInvalidated.connect(self._onSceneGraphInvalidated) # Only render is needed control.renderRequested.connect(self._onRenderRequested) # Polish, sync & render control.sceneChanged.connect(self._onSceneChanged) self.initialized = True # Load QML component self._component = component = QQmlComponent(self._engine, self.qmlUrl) if component.isLoading(): component.statusChanged.connect(self._onComponentStatusChanged) else: self._attachRootItem()