1
0
Fork 0

Canvas proxy for QtQuick rendering

Has zero testing so far, still a work in progress.
This commit is contained in:
James Turner 2017-10-05 12:37:43 +01:00
parent 45cb6849b2
commit 2eab935dff
4 changed files with 341 additions and 1 deletions

View file

@ -42,6 +42,7 @@ class CanvasMgr:
*/
unsigned int getCanvasTexId(const simgear::canvas::CanvasPtr& canvas) const;
static const char* subsystemName() { return "Canvas"; }
protected:
osg::observer_ptr<osg::Camera> _gui_camera;

View file

@ -160,7 +160,9 @@ if (HAVE_QT)
${Qt5Quick_PRIVATE_INCLUDE_DIRS})
add_library(fgqmlui QQuickDrawable.cxx
QQuickDrawable.hxx
QQuickDrawable.hxx
QtQuickFGCanvasItem.cxx
QtQuickFGCanvasItem.hxx
)
set_property(TARGET fgqmlui PROPERTY AUTOMOC ON)

View file

@ -0,0 +1,258 @@
//
// QtQuickFGCanvasItem.cxx
//
// Copyright (C) 2017 James Turner <zakalawe@mac.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "QtQuickFGCanvasItem.hxx"
#include <QDebug>
#include <QSGSimpleTextureNode>
#include <simgear/canvas/Canvas.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
#include <simgear/debug/logstream.hxx>
#include <Main/globals.hxx>
#include <Scripting/NasalSys.hxx>
namespace sc = simgear::canvas;
namespace {
class CanvasTexture : public QSGDynamicTexture
{
public:
CanvasTexture(sc::CanvasPtr canvas)
{
_manager = globals->get_subsystem<CanvasMgr>();
setHorizontalWrapMode(QSGTexture::ClampToEdge);
setVerticalWrapMode(QSGTexture::ClampToEdge);
}
bool updateTexture() override
{
// no-op, canvas is updated by OSG before QtQuick rendering occurs
// this would change if we wanted QtQuick to drive Canvas
// updating, which we don't
// but do return true so QQ knows to repaint / re-cache
return true;
}
bool hasMipmaps() const override
{
return false;
}
bool hasAlphaChannel() const override
{
return false; // for now, can Canvas have an alpha channel?
}
void bind() override
{
glBindTexture(GL_TEXTURE_2D, _manager->getCanvasTexId(_canvas));
}
int textureId() const override
{
return _manager->getCanvasTexId(_canvas);
}
QSize textureSize() const override
{
SGPropertyNode* cprops = _canvas->getProps();
return QSize(cprops->getIntValue("value[0]"),
cprops->getIntValue("value[1]"));
}
private:
CanvasMgr* _manager;
sc::CanvasPtr _canvas;
};
} // of anonymous namespace
static int convertQtButtonToCanvas(Qt::MouseButton button)
{
switch (button) {
case Qt::LeftButton: return 0;
case Qt::MiddleButton: return 1;
case Qt::RightButton: return 2;
default:
break;
}
qWarning() << Q_FUNC_INFO << "unmapped Qt mouse button" << button;
return 0;
}
QtQuickFGCanvasItem::QtQuickFGCanvasItem(QQuickItem *parent)
{
}
QtQuickFGCanvasItem::~QtQuickFGCanvasItem()
{
if ( _canvas ) {
_canvas->destroy();
}
}
QSGNode *QtQuickFGCanvasItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
{
QSGSimpleTextureNode* texNode = static_cast<QSGSimpleTextureNode*>(oldNode);
if (!texNode) {
texNode = new QSGSimpleTextureNode;
CanvasTexture* texture = new CanvasTexture(_canvas);
texNode->setTexture(texture);
}
// or should this simply be the geometry?
texNode->setRect(QRectF(0.0, 0.0, width(), height()));
return texNode;
}
sc::MouseEventPtr QtQuickFGCanvasItem::convertMouseEvent(QMouseEvent* event)
{
sc::MouseEventPtr canvasEvent(new sc::MouseEvent);
canvasEvent->time = event->timestamp() / 1000.0;
canvasEvent->screen_pos.set(event->screenPos().x(),
event->screenPos().y());
canvasEvent->client_pos.set(event->pos().x(),
event->pos().y());
// synthesise delta values
QPointF delta = event->screenPos() - _lastMouseEventScreenPosition;
canvasEvent->delta.set(delta.x(), delta.y());
_lastMouseEventScreenPosition = event->screenPos();
return canvasEvent;
}
void QtQuickFGCanvasItem::mousePressEvent(QMouseEvent *event)
{
sc::MouseEventPtr canvasEvent = convertMouseEvent(event);
canvasEvent->button = convertQtButtonToCanvas(event->button());
canvasEvent->type = sc::Event::MOUSE_DOWN;
_canvas->handleMouseEvent(canvasEvent);
}
void QtQuickFGCanvasItem::mouseReleaseEvent(QMouseEvent *event)
{
sc::MouseEventPtr canvasEvent = convertMouseEvent(event);
canvasEvent->button = convertQtButtonToCanvas(event->button());
canvasEvent->type = sc::Event::MOUSE_UP;
_canvas->handleMouseEvent(canvasEvent);
}
void QtQuickFGCanvasItem::mouseMoveEvent(QMouseEvent *event)
{
sc::MouseEventPtr canvasEvent = convertMouseEvent(event);
if (event->buttons() == Qt::NoButton) {
canvasEvent->type = sc::Event::MOUSE_MOVE;
} else {
canvasEvent->button = convertQtButtonToCanvas(event->button());
canvasEvent->type = sc::Event::DRAG;
}
_canvas->handleMouseEvent(canvasEvent);
}
void QtQuickFGCanvasItem::mouseDoubleClickEvent(QMouseEvent *event)
{
sc::MouseEventPtr canvasEvent = convertMouseEvent(event);
canvasEvent->button = convertQtButtonToCanvas(event->button());
canvasEvent->type = sc::Event::DBL_CLICK;
_canvas->handleMouseEvent(canvasEvent);
}
void QtQuickFGCanvasItem::wheelEvent(QWheelEvent *event)
{
sc::MouseEventPtr canvasEvent(new sc::MouseEvent);
canvasEvent->time = event->timestamp() / 1000.0;
canvasEvent->type = sc::Event::WHEEL;
// TODO - check if using pixelDelta is beneficial at all.
canvasEvent->delta.set(event->angleDelta().x(),
event->angleDelta().y());
}
void QtQuickFGCanvasItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
QQuickItem::geometryChanged(newGeometry, oldGeometry);
updateCanvasGeometry();
}
void QtQuickFGCanvasItem::setCanvas(QString canvas)
{
if (_canvasName == canvas)
return;
if (_canvas) {
// release it
_canvas->destroy();
_canvas.clear();
}
_canvasName = canvas;
if (!_canvasName.isEmpty()) {
CanvasMgr* canvasManager = globals->get_subsystem<CanvasMgr>();
_canvas = canvasManager->createCanvas("");
SGPropertyNode* cprops = _canvas->getProps();
cprops->setBoolValue("render-always", true);
initCanvasNasalModules();
updateCanvasGeometry();
}
emit canvasChanged(_canvasName);
}
void QtQuickFGCanvasItem::initCanvasNasalModules()
{
#if 0
SGPropertyNode *nasal = props->getNode("nasal");
if( !nasal )
return;
FGNasalSys *nas = globals->get_subsystem<FGNasalSys>();
if( !nas )
SG_LOG( SG_GENERAL,
SG_ALERT,
"CanvasWidget: Failed to get nasal subsystem!" );
const std::string file = std::string("__canvas:")
+ cprops->getStringValue("name");
SGPropertyNode *load = nasal->getNode("load");
if( load )
{
const char *s = load->getStringValue();
nas->handleCommand(module.c_str(), file.c_str(), s, cprops);
}
#endif
}
void QtQuickFGCanvasItem::updateCanvasGeometry()
{
SGPropertyNode* cprops = _canvas->getProps();
cprops->setIntValue("size[0]", width());
cprops->setIntValue("size[1]", height());
}

View file

@ -0,0 +1,79 @@
//
// QtQuickFGCanvasItem.hxx
//
// Copyright (C) 2017 James Turner <zakalawe@mac.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef QtQuickFGCanvasItem_hpp
#define QtQuickFGCanvasItem_hpp
#include <QQuickItem>
#include <simgear/canvas/canvas_fwd.hxx>
#include <simgear/props/props.hxx>
#include <Canvas/canvas_mgr.hxx>
/**
* Custom QtQuick item for displaying a FlightGear canvas (and interacting with it)
*
* Note this unrelated to the QtQuick 'native' canvas (HTML5 canvas 2D implementation)!
*/
class QtQuickFGCanvasItem : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QString canvas READ canvas WRITE setCanvas NOTIFY canvasChanged)
public:
QtQuickFGCanvasItem(QQuickItem* parent = nullptr);
virtual ~QtQuickFGCanvasItem();
QString canvas() const
{
return _canvasName;
}
public slots:
void setCanvas(QString canvas);
signals:
void canvasChanged(QString canvas);
protected:
QSGNode* updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void mouseDoubleClickEvent(QMouseEvent* event) override;
void wheelEvent(QWheelEvent* event) override;
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
private:
void initCanvasNasalModules();
void updateCanvasGeometry();
simgear::canvas::MouseEventPtr convertMouseEvent(QMouseEvent *event);
simgear::canvas::CanvasPtr _canvas;
QString _canvasName;
QPointF _lastMouseEventScreenPosition;
};
#endif /* QtQuickFGCanvasItem_hpp */