QImage ImageBufferDataPrivateAccelerated::toQImage() const { QOpenGLContext *previousContext = QOpenGLContext::currentContext(); GLSharedContext::makeCurrent(); commitChanges(); QImage image = m_fbo->toImage(); previousContext->makeCurrent(previousContext->surface()); return image; }
void withSavedContext(const std::function<void()>& f) { // Save the original GL context, because creating a QML surface will create a new context QOpenGLContext * savedContext = QOpenGLContext::currentContext(); QSurface * savedSurface = savedContext ? savedContext->surface() : nullptr; f(); if (savedContext) { savedContext->makeCurrent(savedSurface); } }
ImageBuffer::~ImageBuffer() { #if ENABLE(ACCELERATED_2D_CANVAS) QOpenGLContext *previousContext = QOpenGLContext::currentContext(); GLSharedContext::makeCurrent(); #endif m_data.m_painter->end(); #if ENABLE(ACCELERATED_2D_CANVAS) if (previousContext) previousContext->makeCurrent(previousContext->surface()); #endif }
void QuickMozView::clearThreadRenderObject() { QOpenGLContext* ctx = QOpenGLContext::currentContext(); Q_ASSERT(ctx != NULL && ctx->makeCurrent(ctx->surface())); if (gSGRenderer != NULL) { delete gSGRenderer; gSGRenderer = NULL; } QQuickWindow *win = window(); if (!win) return; connect(win, SIGNAL(beforeSynchronizing()), this, SLOT(createThreadRenderObject()), Qt::DirectConnection); }
void QSGTextMaskMaterial::init(QFontEngine::GlyphFormat glyphFormat) { Q_ASSERT(m_font.isValid()); setFlag(Blending, true); QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); Q_ASSERT(ctx != 0); // The following piece of code will read/write to the font engine's caches, // potentially from different threads. However, this is safe because this // code is only called from QQuickItem::updatePaintNode() which is called // only when the GUI is blocked, and multiple threads will call it in // sequence. See also QSGRenderContext::invalidate QRawFontPrivate *fontD = QRawFontPrivate::get(m_font); if (QFontEngine *fontEngine = fontD->fontEngine) { if (glyphFormat == QFontEngine::Format_None) { glyphFormat = fontEngine->glyphFormat != QFontEngine::Format_None ? fontEngine->glyphFormat : QFontEngine::Format_A32; } qreal devicePixelRatio = ctx->surface()->surfaceClass() == QSurface::Window ? static_cast<QWindow *>(ctx->surface())->devicePixelRatio() : ctx->screen()->devicePixelRatio(); QTransform glyphCacheTransform = QTransform::fromScale(devicePixelRatio, devicePixelRatio); if (!fontEngine->supportsTransformation(glyphCacheTransform)) glyphCacheTransform = QTransform(); m_glyphCache = fontEngine->glyphCache(ctx, glyphFormat, glyphCacheTransform); if (!m_glyphCache || int(m_glyphCache->glyphFormat()) != glyphFormat) { m_glyphCache = new QOpenGLTextureGlyphCache(glyphFormat, glyphCacheTransform); fontEngine->setGlyphCache(ctx, m_glyphCache.data()); QSGRenderContext *sg = QSGRenderContext::from(ctx); Q_ASSERT(sg); sg->registerFontengineForCleanup(fontEngine); } } }
GraphicsSurfacePrivate(const PlatformGraphicsContext3D shareContext = 0) : m_display(0) , m_xPixmap(0) , m_glxPixmap(0) , m_glContext(0) , m_detachedContext(0) , m_detachedSurface(0) , m_textureIsYInverted(false) , m_hasAlpha(false) { GLXContext shareContextObject = 0; m_display = XOpenDisplay(0); #if PLATFORM(QT) if (shareContext) { #if 0 // This code path requires QXcbNativeInterface::nativeResourceForContext() which is not availble in Qt5 on the build bots yet. QPlatformNativeInterface* nativeInterface = QGuiApplication::platformNativeInterface(); shareContextObject = static_cast<GLXContext>(nativeInterface->nativeResourceForContext(QByteArrayLiteral("glxcontext"), shareContext)); if (!shareContextObject) return; #else // This code path should be removed as soon as QXcbNativeInterface::nativeResourceForContext() can provide the GLXContext. QOpenGLContext* previousContext = QOpenGLContext::currentContext(); QSurface* previousSurface = previousContext->surface(); QSurface* currentSurface = shareContext->surface(); shareContext->makeCurrent(currentSurface); shareContextObject = glXGetCurrentContext(); previousContext->makeCurrent(previousSurface); #endif } #endif m_display = m_offScreenWindow.display(); int attributes[] = { GLX_LEVEL, 0, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, True, None }; int numReturned; m_fbConfigs = glXChooseFBConfig(m_display, DefaultScreen(m_display), attributes, &numReturned); // Create a GLX context for OpenGL rendering m_glContext = glXCreateNewContext(m_display, m_fbConfigs[0], GLX_RGBA_TYPE, shareContextObject, true); }
uint32_t ImageBufferDataPrivateAccelerated::copyToGraphicsSurface() { QOpenGLContext *previousContext = QOpenGLContext::currentContext(); GLSharedContext::makeCurrent(); if (!m_graphicsSurface) { m_graphicsSurface = GraphicsSurface::create(m_fbo->size(), graphicsSurfaceFlags(), QOpenGLContext::currentContext()); } commitChanges(); m_graphicsSurface->copyFromTexture(m_fbo->texture(), IntRect(IntPoint(), m_fbo->size())); previousContext->makeCurrent(previousContext->surface()); return m_graphicsSurface->frontBuffer(); }
GraphicsSurfaceToken ImageBufferDataPrivateAccelerated::graphicsSurfaceToken() const { if (!m_graphicsSurface) { QOpenGLContext *previousContext = QOpenGLContext::currentContext(); GLSharedContext::makeCurrent(); m_graphicsSurface = GraphicsSurface::create(m_fbo->size(), graphicsSurfaceFlags(), QOpenGLContext::currentContext()); previousContext->makeCurrent(previousContext->surface()); } return m_graphicsSurface->exportToken(); }
void ImageBufferDataPrivateAccelerated::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) { if (textureMapper->accelerationMode() != TextureMapper::OpenGLMode) { return; } QOpenGLContext *previousContext = QOpenGLContext::currentContext(); GLSharedContext::makeCurrent(); commitChanges(); previousContext->makeCurrent(previousContext->surface()); static_cast<TextureMapperGL*>(textureMapper)->drawTexture(m_fbo->texture(), TextureMapperGL::ShouldFlipTexture | TextureMapperGL::ShouldBlend, m_fbo->size(), targetRect, matrix, opacity); }
bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) { if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) { qWarning() << "Too many concurrent web views to create new view"; return false; } qDebug() << "Building web surface"; ++_currentWebCount; // Save the original GL context, because creating a QML surface will create a new context QOpenGLContext * currentContext = QOpenGLContext::currentContext(); QSurface * currentSurface = currentContext->surface(); _webSurface = new OffscreenQmlSurface(); _webSurface->create(currentContext); _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/controls/")); _webSurface->load("WebView.qml"); _webSurface->resume(); _webSurface->getRootItem()->setProperty("url", _sourceUrl); _webSurface->getRootContext()->setContextProperty("desktop", QVariant()); _connection = QObject::connect(_webSurface, &OffscreenQmlSurface::textureUpdated, [&](GLuint textureId) { _texture = textureId; }); // Restore the original GL context currentContext->makeCurrent(currentSurface); auto forwardPointerEvent = [=](const EntityItemID& entityItemID, const PointerEvent& event) { if (entityItemID == getID()) { handlePointerEvent(event); } }; _mousePressConnection = QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardPointerEvent); _mouseReleaseConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardPointerEvent); _mouseMoveConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseMoveOnEntity, forwardPointerEvent); _hoverLeaveConnection = QObject::connect(renderer, &EntityTreeRenderer::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const PointerEvent& event) { if (this->_pressed && this->getID() == entityItemID) { // If the user mouses off the entity while the button is down, simulate a touch end. QTouchEvent::TouchPoint point; point.setId(event.getID()); point.setState(Qt::TouchPointReleased); glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi); QPointF windowPoint(windowPos.x, windowPos.y); point.setPos(windowPoint); QList<QTouchEvent::TouchPoint> touchPoints; touchPoints.push_back(point); QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr, Qt::NoModifier, Qt::TouchPointReleased, touchPoints); QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent); } }); return true; }
void Web3DOverlay::render(RenderArgs* args) { if (!_visible || !getParentVisible()) { return; } QOpenGLContext * currentContext = QOpenGLContext::currentContext(); QSurface * currentSurface = currentContext->surface(); if (!_webSurface) { _webSurface = new OffscreenQmlSurface(); _webSurface->create(currentContext); _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); _webSurface->load("WebEntity.qml"); _webSurface->resume(); _webSurface->getRootItem()->setProperty("url", _url); _webSurface->resize(QSize(_resolution.x, _resolution.y)); _connection = QObject::connect(_webSurface, &OffscreenQmlSurface::textureUpdated, [&](GLuint textureId) { _texture = textureId; }); currentContext->makeCurrent(currentSurface); } vec2 size = _resolution / _dpi * INCHES_TO_METERS; vec2 halfSize = size / 2.0f; vec4 color(toGlm(getColor()), getAlpha()); applyTransformTo(_transform, true); Transform transform = _transform; if (glm::length2(getDimensions()) != 1.0f) { transform.postScale(vec3(getDimensions(), 1.0f)); } Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; if (_texture) { batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _texture); } else { batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture()); } batch.setModelTransform(transform); DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, true, false, false, true); DependencyManager::get<GeometryCache>()->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color); batch.setResourceTexture(0, args->_whiteTexture); // restore default white color after me }
void ImageBufferDataPrivateAccelerated::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale, bool ownContext) { if (destContext->isAcceleratedContext()) { QOpenGLContext *previousContext = QOpenGLContext::currentContext(); GLSharedContext::makeCurrent(); commitChanges(); previousContext->makeCurrent(previousContext->surface()); QOpenGL2PaintEngineEx* acceleratedPaintEngine = static_cast<QOpenGL2PaintEngineEx*>(destContext->platformContext()->paintEngine()); FloatRect flippedSrc = srcRect; flippedSrc.setY(m_fbo->size().height() - flippedSrc.height() - flippedSrc.y()); acceleratedPaintEngine->drawTexture(destRect, m_fbo->texture(), m_fbo->size(), flippedSrc); } else { RefPtr<Image> image = StillImage::create(QPixmap::fromImage(toQImage())); destContext->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, blendMode, DoNotRespectImageOrientation, useLowQualityScale); } }
QImage QFramebufferPaintDevice::toImage() const { QOpenGLContext* currentContext = QOpenGLContext::currentContext(); QSurface* currentSurface = currentContext ? currentContext->surface() : 0; context()->makeCurrent(m_surface); #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) QImage image = m_framebufferObject.toImage(false); #else QImage image = m_framebufferObject.toImage(); #endif if (currentContext) currentContext->makeCurrent(currentSurface); else context()->doneCurrent(); return image; }
void RenderableWebEntityItem::render(RenderArgs* args) { QOpenGLContext * currentContext = QOpenGLContext::currentContext(); QSurface * currentSurface = currentContext->surface(); if (!_webSurface) { _webSurface = new OffscreenQmlSurface(); _webSurface->create(currentContext); _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); _webSurface->load("WebEntity.qml"); _webSurface->resume(); _webSurface->getRootItem()->setProperty("url", _sourceUrl); _connection = QObject::connect(_webSurface, &OffscreenQmlSurface::textureUpdated, [&](GLuint textureId) { _webSurface->lockTexture(textureId); assert(!glGetError()); // TODO change to atomic<GLuint>? withLock(_textureLock, [&] { std::swap(_texture, textureId); }); if (textureId) { _webSurface->releaseTexture(textureId); } if (_texture) { _webSurface->makeCurrent(); glBindTexture(GL_TEXTURE_2D, _texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); _webSurface->doneCurrent(); } }); auto forwardMouseEvent = [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId) { // Ignore mouse interaction if we're locked if (this->getLocked()) { return; } if (event->button() == Qt::MouseButton::RightButton) { if (event->type() == QEvent::MouseButtonPress) { const QMouseEvent* mouseEvent = static_cast<const QMouseEvent*>(event); _lastPress = toGlm(mouseEvent->pos()); } } if (intersection.entityID == getID()) { if (event->button() == Qt::MouseButton::RightButton) { if (event->type() == QEvent::MouseButtonRelease) { const QMouseEvent* mouseEvent = static_cast<const QMouseEvent*>(event); ivec2 dist = glm::abs(toGlm(mouseEvent->pos()) - _lastPress); if (!glm::any(glm::greaterThan(dist, ivec2(1)))) { AbstractViewStateInterface::instance()->postLambdaEvent([this] { QMetaObject::invokeMethod(_webSurface->getRootItem(), "goBack"); }); } _lastPress = ivec2(INT_MIN); } return; } // FIXME doesn't work... double click events not received if (event->type() == QEvent::MouseButtonDblClick) { AbstractViewStateInterface::instance()->postLambdaEvent([this] { _webSurface->getRootItem()->setProperty("url", _sourceUrl); }); } if (event->button() == Qt::MouseButton::MiddleButton) { if (event->type() == QEvent::MouseButtonRelease) { AbstractViewStateInterface::instance()->postLambdaEvent([this] { _webSurface->getRootItem()->setProperty("url", _sourceUrl); }); } return; } // Map the intersection point to an actual offscreen pixel glm::vec3 point = intersection.intersection; point -= getPosition(); point = glm::inverse(getRotation()) * point; point /= getDimensions(); point += 0.5f; point.y = 1.0f - point.y; point *= getDimensions() * METERS_TO_INCHES * DPI; // Forward the mouse event. QMouseEvent mappedEvent(event->type(), QPoint((int)point.x, (int)point.y), event->screenPos(), event->button(), event->buttons(), event->modifiers()); QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent); } }; EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer); QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardMouseEvent); QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardMouseEvent); QObject::connect(renderer, &EntityTreeRenderer::mouseMoveOnEntity, forwardMouseEvent); } glm::vec2 dims = glm::vec2(getDimensions()); dims *= METERS_TO_INCHES * DPI; // The offscreen surface is idempotent for resizes (bails early // if it's a no-op), so it's safe to just call resize every frame // without worrying about excessive overhead. _webSurface->resize(QSize(dims.x, dims.y)); currentContext->makeCurrent(currentSurface); PerformanceTimer perfTimer("RenderableWebEntityItem::render"); Q_ASSERT(getType() == EntityTypes::Web); static const glm::vec2 texMin(0.0f), texMax(1.0f), topLeft(-0.5f), bottomRight(0.5f); Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; batch.setModelTransform(getTransformToCenter()); bool textured = false, culled = false, emissive = false; if (_texture) { batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _texture); textured = emissive = true; } DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, textured, culled, emissive); DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f)); }
bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) { if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) { qWarning() << "Too many concurrent web views to create new view"; return false; } qDebug() << "Building web surface"; ++_currentWebCount; // Save the original GL context, because creating a QML surface will create a new context QOpenGLContext * currentContext = QOpenGLContext::currentContext(); QSurface * currentSurface = currentContext->surface(); _webSurface = new OffscreenQmlSurface(); _webSurface->create(currentContext); _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); _webSurface->load("WebEntity.qml"); _webSurface->resume(); _webSurface->getRootItem()->setProperty("url", _sourceUrl); _connection = QObject::connect(_webSurface, &OffscreenQmlSurface::textureUpdated, [&](GLuint textureId) { _texture = textureId; }); // Restore the original GL context currentContext->makeCurrent(currentSurface); auto forwardMouseEvent = [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event) { // Ignore mouse interaction if we're locked if (this->getLocked()) { return; } if (event->button() == Qt::MouseButton::RightButton) { if (event->type() == QEvent::MouseButtonPress) { const QMouseEvent* mouseEvent = static_cast<const QMouseEvent*>(event); _lastPress = toGlm(mouseEvent->pos()); } } if (intersection.entityID == getID()) { if (event->button() == Qt::MouseButton::RightButton) { if (event->type() == QEvent::MouseButtonRelease) { const QMouseEvent* mouseEvent = static_cast<const QMouseEvent*>(event); ivec2 dist = glm::abs(toGlm(mouseEvent->pos()) - _lastPress); if (!glm::any(glm::greaterThan(dist, ivec2(1)))) { AbstractViewStateInterface::instance()->postLambdaEvent([this] { QMetaObject::invokeMethod(_webSurface->getRootItem(), "goBack"); }); } _lastPress = ivec2(INT_MIN); } return; } // FIXME doesn't work... double click events not received if (event->type() == QEvent::MouseButtonDblClick) { AbstractViewStateInterface::instance()->postLambdaEvent([this] { _webSurface->getRootItem()->setProperty("url", _sourceUrl); }); } if (event->button() == Qt::MouseButton::MiddleButton) { if (event->type() == QEvent::MouseButtonRelease) { AbstractViewStateInterface::instance()->postLambdaEvent([this] { _webSurface->getRootItem()->setProperty("url", _sourceUrl); }); } return; } // Map the intersection point to an actual offscreen pixel glm::vec3 point = intersection.intersection; glm::vec3 dimensions = getDimensions(); point -= getPosition(); point = glm::inverse(getRotation()) * point; point /= dimensions; point += 0.5f; point.y = 1.0f - point.y; point *= dimensions * (METERS_TO_INCHES * DPI); if (event->button() == Qt::MouseButton::LeftButton) { if (event->type() == QEvent::MouseButtonPress) { this->_pressed = true; this->_lastMove = ivec2((int)point.x, (int)point.y); } else if (event->type() == QEvent::MouseButtonRelease) { this->_pressed = false; } } if (event->type() == QEvent::MouseMove) { this->_lastMove = ivec2((int)point.x, (int)point.y); } // Forward the mouse event. QMouseEvent mappedEvent(event->type(), QPoint((int)point.x, (int)point.y), event->screenPos(), event->button(), event->buttons(), event->modifiers()); QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent); } }; _mousePressConnection = QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardMouseEvent); _mouseReleaseConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardMouseEvent); _mouseMoveConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseMoveOnEntity, forwardMouseEvent); _hoverLeaveConnection = QObject::connect(renderer, &EntityTreeRenderer::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) { if (this->_pressed && this->getID() == entityItemID) { // If the user mouses off the entity while the button is down, simulate a mouse release QMouseEvent mappedEvent(QEvent::MouseButtonRelease, QPoint(_lastMove.x, _lastMove.y), Qt::MouseButton::LeftButton, Qt::MouseButtons(), Qt::KeyboardModifiers()); QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent); } }); return true; }
void Web3DOverlay::render(RenderArgs* args) { QOpenGLContext * currentContext = QOpenGLContext::currentContext(); QSurface * currentSurface = currentContext->surface(); if (!_webSurface) { _webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(pickURL()); // FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces // and the current rendering load) if (_currentMaxFPS != _desiredMaxFPS) { setMaxFPS(_desiredMaxFPS); } loadSourceURL(); _webSurface->resume(); _webSurface->resize(QSize(_resolution.x, _resolution.y)); _webSurface->getRootItem()->setProperty("url", _url); _webSurface->getRootItem()->setProperty("scriptURL", _scriptURL); currentContext->makeCurrent(currentSurface); auto selfOverlayID = getOverlayID(); std::weak_ptr<Web3DOverlay> weakSelf = std::dynamic_pointer_cast<Web3DOverlay>(qApp->getOverlays().getOverlay(selfOverlayID)); auto forwardPointerEvent = [=](OverlayID overlayID, const PointerEvent& event) { auto self = weakSelf.lock(); if (self && overlayID == selfOverlayID) { self->handlePointerEvent(event); } }; auto overlays = &(qApp->getOverlays()); QObject::connect(overlays, &Overlays::mousePressOnOverlay, this, forwardPointerEvent); QObject::connect(overlays, &Overlays::mouseReleaseOnOverlay, this, forwardPointerEvent); QObject::connect(overlays, &Overlays::mouseMoveOnOverlay, this, forwardPointerEvent); QObject::connect(overlays, &Overlays::hoverLeaveOverlay, this, [=](OverlayID overlayID, const PointerEvent& event) { auto self = weakSelf.lock(); if (!self) { return; } if (overlayID == selfOverlayID && (self->_pressed || (!self->_activeTouchPoints.empty() && self->_touchBeginAccepted))) { PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(), event.getButton(), event.getButtons(), event.getKeyboardModifiers()); forwardPointerEvent(overlayID, endEvent); } }); QObject::connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent); QObject::connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived); } else { if (_currentMaxFPS != _desiredMaxFPS) { setMaxFPS(_desiredMaxFPS); } } if (_mayNeedResize) { _mayNeedResize = false; _webSurface->resize(QSize(_resolution.x, _resolution.y)); } if (!_visible || !getParentVisible()) { return; } vec2 halfSize = getSize() / 2.0f; vec4 color(toGlm(getColor()), getAlpha()); Transform transform = getTransform(); // FIXME: applyTransformTo causes tablet overlay to detach from tablet entity. // Perhaps rather than deleting the following code it should be run only if isFacingAvatar() is true? /* applyTransformTo(transform, true); setTransform(transform); */ if (glm::length2(getDimensions()) != 1.0f) { transform.postScale(vec3(getDimensions(), 1.0f)); } if (!_texture) { auto webSurface = _webSurface; _texture = gpu::Texture::createExternal(OffscreenQmlSurface::getDiscardLambda()); _texture->setSource(__FUNCTION__); } OffscreenQmlSurface::TextureAndFence newTextureAndFence; bool newTextureAvailable = _webSurface->fetchTexture(newTextureAndFence); if (newTextureAvailable) { _texture->setExternalTexture(newTextureAndFence.first, newTextureAndFence.second); } Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; batch.setResourceTexture(0, _texture); batch.setModelTransform(transform); auto geometryCache = DependencyManager::get<GeometryCache>(); if (color.a < OPAQUE_ALPHA_THRESHOLD) { geometryCache->bindTransparentWebBrowserProgram(batch, _isAA); } else { geometryCache->bindOpaqueWebBrowserProgram(batch, _isAA); } geometryCache->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color, _geometryId); batch.setResourceTexture(0, nullptr); // restore default white color after me }