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;
|
||||
|
||||
static const char* subsystemName() { return "Canvas"; }
|
||||
protected:
|
||||
|
||||
osg::observer_ptr<osg::Camera> _gui_camera;
|
||||
|
|
|
@ -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)
|
||||
|
|
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