Canvas proxy for QtQuick rendering
Has zero testing so far, still a work in progress.
This commit is contained in:
parent
45cb6849b2
commit
2eab935dff
4 changed files with 341 additions and 1 deletions
|
@ -42,6 +42,7 @@ class CanvasMgr:
|
||||||
*/
|
*/
|
||||||
unsigned int getCanvasTexId(const simgear::canvas::CanvasPtr& canvas) const;
|
unsigned int getCanvasTexId(const simgear::canvas::CanvasPtr& canvas) const;
|
||||||
|
|
||||||
|
static const char* subsystemName() { return "Canvas"; }
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
osg::observer_ptr<osg::Camera> _gui_camera;
|
osg::observer_ptr<osg::Camera> _gui_camera;
|
||||||
|
|
|
@ -161,6 +161,8 @@ if (HAVE_QT)
|
||||||
|
|
||||||
add_library(fgqmlui QQuickDrawable.cxx
|
add_library(fgqmlui QQuickDrawable.cxx
|
||||||
QQuickDrawable.hxx
|
QQuickDrawable.hxx
|
||||||
|
QtQuickFGCanvasItem.cxx
|
||||||
|
QtQuickFGCanvasItem.hxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET fgqmlui PROPERTY AUTOMOC ON)
|
set_property(TARGET fgqmlui PROPERTY AUTOMOC ON)
|
||||||
|
|
258
src/GUI/QtQuickFGCanvasItem.cxx
Normal file
258
src/GUI/QtQuickFGCanvasItem.cxx
Normal 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());
|
||||||
|
}
|
79
src/GUI/QtQuickFGCanvasItem.hxx
Normal file
79
src/GUI/QtQuickFGCanvasItem.hxx
Normal 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 */
|
Loading…
Reference in a new issue