Exemplo n.º 1
0
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));
}
Exemplo n.º 2
0
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;
}