mirror of
https://github.com/thp/pyotherside.git
synced 2025-02-05 08:08:23 +08:00
PyGLArea: Pass renderer object instead of function names.
This commit is contained in:
parent
52e75e918f
commit
f08ab6be25
@ -868,9 +868,11 @@ OpenGL rendering in Python
|
||||
==========================
|
||||
|
||||
You can render directly to Qt's OpenGL context in your Python code (i.e. via
|
||||
PyOpenGL or vispy.gloo) using a ``PyGLArea`` item and supplying ``paintGL``
|
||||
and optional ``initGL`` and ``cleanupGL`` functions. The ``before`` property
|
||||
controls whether to render before or after the QML scene is rendered.
|
||||
PyOpenGL or vispy.gloo) using a ``PyGLArea`` item and supplying a ``renderer``
|
||||
which must provide a ``render()`` method and may optionally provide ``init()``
|
||||
and ``cleanup()`` methods.
|
||||
The ``before`` property controls whether to render before or after the QML
|
||||
scene is rendered.
|
||||
|
||||
**rendergl.qml**
|
||||
|
||||
@ -898,9 +900,9 @@ controls whether to render before or after the QML scene is rendered.
|
||||
Python {
|
||||
Component.onCompleted: {
|
||||
importModule('myrenderer', function () {
|
||||
glArea.initGL = 'myrenderer.initGL';
|
||||
glArea.paintGL = 'myrenderer.paintGL';
|
||||
glArea.cleanupGL = 'myrenderer.cleanupGL';
|
||||
call('myrenderer.Renderer', [], function (renderer) {
|
||||
glArea.renderer = renderer;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -909,21 +911,23 @@ controls whether to render before or after the QML scene is rendered.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def initGL():
|
||||
"""Initialize OpenGL stuff like textures, FBOs etc..."""
|
||||
class Renderer(object):
|
||||
|
||||
def paintGL(x, y, width, height):
|
||||
"""
|
||||
Render to the OpenGL context.
|
||||
def init(self):
|
||||
"""Initialize OpenGL stuff like textures, FBOs etc..."""
|
||||
|
||||
(x, y, width, height) indicates the area to render on.
|
||||
def render(self, x, y, width, height):
|
||||
"""
|
||||
Render to the OpenGL context.
|
||||
|
||||
The coordinate system's origin is at the bottom left corner of the
|
||||
window.
|
||||
"""
|
||||
(x, y, width, height) indicates the area to render on.
|
||||
|
||||
def cleanupGL():
|
||||
"""Clean up OpenGL stuff initialized in initGL()."""
|
||||
The coordinate system's origin is at the bottom left corner of the
|
||||
window.
|
||||
"""
|
||||
|
||||
def cleanup(self):
|
||||
"""Clean up OpenGL stuff initialized in initGL()."""
|
||||
|
||||
Building PyOtherSide
|
||||
====================
|
||||
|
@ -36,34 +36,21 @@ PyGLArea::PyGLArea()
|
||||
|
||||
PyGLArea::~PyGLArea()
|
||||
{
|
||||
delete m_renderer;
|
||||
if (m_renderer) {
|
||||
delete m_renderer;
|
||||
m_renderer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PyGLArea::setInitGL(QString initGL)
|
||||
void PyGLArea::setRenderer(QVariant renderer)
|
||||
{
|
||||
if (initGL == m_initGL)
|
||||
if (renderer == m_pyRenderer)
|
||||
return;
|
||||
m_initGL = initGL;
|
||||
delete m_renderer;
|
||||
m_renderer = 0;
|
||||
}
|
||||
|
||||
void PyGLArea::setPaintGL(QString paintGL)
|
||||
{
|
||||
if (paintGL == m_paintGL)
|
||||
return;
|
||||
m_paintGL = paintGL;
|
||||
delete m_renderer;
|
||||
m_renderer = 0;
|
||||
}
|
||||
|
||||
void PyGLArea::setCleanupGL(QString cleanupGL)
|
||||
{
|
||||
if (cleanupGL == m_cleanupGL)
|
||||
return;
|
||||
m_cleanupGL = cleanupGL;
|
||||
delete m_renderer;
|
||||
m_renderer = 0;
|
||||
m_pyRenderer = renderer;
|
||||
if (m_renderer) {
|
||||
delete m_renderer;
|
||||
m_renderer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PyGLArea::setBefore(bool before)
|
||||
@ -71,8 +58,10 @@ void PyGLArea::setBefore(bool before)
|
||||
if (before == m_before)
|
||||
return;
|
||||
m_before = before;
|
||||
delete m_renderer;
|
||||
m_renderer = 0;
|
||||
if (m_renderer) {
|
||||
delete m_renderer;
|
||||
m_renderer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PyGLArea::setT(qreal t)
|
||||
@ -101,21 +90,21 @@ void PyGLArea::update() {
|
||||
|
||||
void PyGLArea::sync()
|
||||
{
|
||||
if (!m_renderer) {
|
||||
disconnect(window(), SIGNAL(beforeRendering()), this, SLOT(paint()));
|
||||
disconnect(window(), SIGNAL(afterRendering()), this, SLOT(paint()));
|
||||
m_renderer = new PyGLRenderer();
|
||||
m_renderer->setInitGL(m_initGL);
|
||||
if (!m_renderer && !m_pyRenderer.isNull()) {
|
||||
disconnect(window(), SIGNAL(beforeRendering()), this, SLOT(render()));
|
||||
disconnect(window(), SIGNAL(afterRendering()), this, SLOT(render()));
|
||||
m_renderer = new PyGLRenderer(m_pyRenderer);
|
||||
/*m_renderer->setInitGL(m_initGL);
|
||||
m_renderer->setPaintGL(m_paintGL);
|
||||
m_renderer->setCleanupGL(m_cleanupGL);
|
||||
m_renderer->setCleanupGL(m_cleanupGL);*/
|
||||
if (m_before)
|
||||
connect(window(), SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection);
|
||||
connect(window(), SIGNAL(beforeRendering()), this, SLOT(render()), Qt::DirectConnection);
|
||||
else
|
||||
connect(window(), SIGNAL(afterRendering()), this, SLOT(paint()), Qt::DirectConnection);
|
||||
connect(window(), SIGNAL(afterRendering()), this, SLOT(render()), Qt::DirectConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void PyGLArea::paint()
|
||||
void PyGLArea::render()
|
||||
{
|
||||
QPointF pos = mapToScene(QPointF(.0, .0));
|
||||
m_renderer->setRect(
|
||||
@ -125,7 +114,7 @@ void PyGLArea::paint()
|
||||
)
|
||||
);
|
||||
m_renderer->init();
|
||||
m_renderer->paint();
|
||||
m_renderer->render();
|
||||
window()->resetOpenGLState();
|
||||
}
|
||||
|
||||
|
@ -22,17 +22,18 @@
|
||||
#include "Python.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QtQuick/QQuickItem>
|
||||
|
||||
#include "pyobject_ref.h"
|
||||
|
||||
#include "pyglrenderer.h"
|
||||
|
||||
|
||||
class PyGLArea : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString initGL READ initGL WRITE setInitGL)
|
||||
Q_PROPERTY(QString paintGL READ paintGL WRITE setPaintGL)
|
||||
Q_PROPERTY(QString cleanupGL READ cleanupGL WRITE setCleanupGL)
|
||||
Q_PROPERTY(QVariant renderer READ renderer WRITE setRenderer)
|
||||
Q_PROPERTY(bool before READ before WRITE setBefore)
|
||||
Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
|
||||
|
||||
@ -40,13 +41,9 @@ public:
|
||||
PyGLArea();
|
||||
~PyGLArea();
|
||||
|
||||
QString initGL() const { return m_initGL; };
|
||||
QString paintGL() const { return m_paintGL; };
|
||||
QString cleanupGL() const { return m_paintGL; };
|
||||
QVariant renderer() const { return m_pyRenderer; };
|
||||
bool before() { return m_before; };
|
||||
void setInitGL(QString initGL);
|
||||
void setPaintGL(QString paintGL);
|
||||
void setCleanupGL(QString cleanupGL);
|
||||
void setRenderer(QVariant renderer);
|
||||
void setBefore(bool before);
|
||||
qreal t() const { return m_t; }
|
||||
void setT(qreal t);
|
||||
@ -60,14 +57,12 @@ public slots:
|
||||
|
||||
private slots:
|
||||
void handleWindowChanged(QQuickWindow *win);
|
||||
void paint();
|
||||
void render();
|
||||
void cleanup();
|
||||
|
||||
private:
|
||||
qreal m_t;
|
||||
QString m_initGL;
|
||||
QString m_paintGL;
|
||||
QString m_cleanupGL;
|
||||
QVariant m_pyRenderer;
|
||||
bool m_before;
|
||||
PyGLRenderer *m_renderer;
|
||||
};
|
||||
|
@ -17,58 +17,36 @@
|
||||
**/
|
||||
|
||||
#include "qpython_priv.h"
|
||||
#include "converter.h"
|
||||
#include "pyobject_ref.h"
|
||||
#include "pyglrenderer.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMetaType>
|
||||
|
||||
|
||||
PyGLRenderer::PyGLRenderer()
|
||||
: m_paintGLCallable(0)
|
||||
PyGLRenderer::PyGLRenderer(QVariant pyRenderer)
|
||||
: m_pyRendererObject(0)
|
||||
, m_renderMethod(0)
|
||||
, m_initialized(false)
|
||||
, m_initGL("")
|
||||
, m_paintGL("")
|
||||
{
|
||||
m_pyRenderer = pyRenderer;
|
||||
}
|
||||
|
||||
PyGLRenderer::~PyGLRenderer()
|
||||
{
|
||||
if (m_paintGLCallable) {
|
||||
if (m_pyRendererObject) {
|
||||
QPythonPriv *priv = QPythonPriv::instance();
|
||||
priv->enter();
|
||||
Py_DECREF(m_paintGLCallable);
|
||||
Py_CLEAR(m_pyRendererObject);
|
||||
if (m_renderMethod)
|
||||
Py_DECREF(m_renderMethod);
|
||||
priv->leave();
|
||||
m_paintGLCallable = 0;
|
||||
m_pyRendererObject = 0;
|
||||
m_renderMethod = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PyGLRenderer::setInitGL(QString initGL)
|
||||
{
|
||||
if (initGL == m_initGL)
|
||||
return;
|
||||
m_initGL = initGL;
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
void PyGLRenderer::setPaintGL(QString paintGL)
|
||||
{
|
||||
if (paintGL == m_paintGL)
|
||||
return;
|
||||
m_paintGL = paintGL;
|
||||
if (m_paintGLCallable) {
|
||||
QPythonPriv *priv = QPythonPriv::instance();
|
||||
priv->enter();
|
||||
Py_DECREF(m_paintGLCallable);
|
||||
priv->leave();
|
||||
}
|
||||
}
|
||||
|
||||
void PyGLRenderer::setCleanupGL(QString cleanupGL)
|
||||
{
|
||||
if (cleanupGL == m_cleanupGL)
|
||||
return;
|
||||
m_cleanupGL = cleanupGL;
|
||||
}
|
||||
|
||||
void PyGLRenderer::setRect(QRect rect) {
|
||||
m_rect = rect;
|
||||
}
|
||||
@ -77,41 +55,54 @@ void PyGLRenderer::init() {
|
||||
if (m_initialized)
|
||||
return;
|
||||
|
||||
if (!m_initGL.isEmpty()) {
|
||||
QPythonPriv *priv = QPythonPriv::instance();
|
||||
priv->enter();
|
||||
PyObject *initGLCallable = priv->eval(m_initGL);
|
||||
if (!initGLCallable) {
|
||||
qWarning() << "Init callback " << m_initGL << " not defined.";
|
||||
priv->leave();
|
||||
return;
|
||||
}
|
||||
PyObject *args = PyTuple_New(0);
|
||||
PyObject *o = PyObject_Call(initGLCallable, args, NULL);
|
||||
if (o) Py_DECREF(o); else PyErr_PrintEx(0);
|
||||
Py_DECREF(args);
|
||||
Py_DECREF(initGLCallable);
|
||||
QPythonPriv *priv = QPythonPriv::instance();
|
||||
priv->enter();
|
||||
|
||||
PyObject *pyRendererObject = getPyRendererObject();
|
||||
if (!pyRendererObject || pyRendererObject == Py_None) {
|
||||
priv->leave();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PyObject_HasAttrString(m_pyRendererObject, "init")) {
|
||||
// Optional init() method not found, consider the renderer initialized.
|
||||
priv->leave();
|
||||
m_initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
PyObject *initMethod = PyObject_GetAttrString(m_pyRendererObject, "init");
|
||||
if (!initMethod) {
|
||||
qWarning() << "Failed to get init method of renderer.";
|
||||
PyErr_PrintEx(0);
|
||||
priv->leave();
|
||||
return;
|
||||
}
|
||||
|
||||
PyObject *args = PyTuple_New(0);
|
||||
PyObject *o = PyObject_Call(initMethod, args, NULL);
|
||||
if (o) Py_DECREF(o); else PyErr_PrintEx(0);
|
||||
Py_DECREF(args);
|
||||
Py_DECREF(initMethod);
|
||||
priv->leave();
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
|
||||
void PyGLRenderer::paint()
|
||||
void PyGLRenderer::render()
|
||||
{
|
||||
if (!m_initialized || m_paintGL.isEmpty())
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
QPythonPriv *priv = QPythonPriv::instance();
|
||||
priv->enter();
|
||||
|
||||
if (!m_paintGLCallable) {
|
||||
m_paintGLCallable = priv->eval(m_paintGL);
|
||||
if (!m_paintGLCallable) {
|
||||
qWarning() << "Paint callback " << m_paintGL << " not defined.";
|
||||
priv->leave();
|
||||
return;
|
||||
}
|
||||
PyObject *renderMethod = getRenderMethod();
|
||||
if (!renderMethod) {
|
||||
qWarning() << "Failed to get render method of renderer.";
|
||||
PyErr_PrintEx(0);
|
||||
priv->leave();
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the paintGL callback with arguments x, y, width, height.
|
||||
@ -125,7 +116,7 @@ void PyGLRenderer::paint()
|
||||
PyObject *width = PyLong_FromLong(m_rect.width());
|
||||
PyObject *height = PyLong_FromLong(m_rect.height());
|
||||
PyObject *args = PyTuple_Pack(4, x, y, width, height);
|
||||
PyObject *o = PyObject_Call(m_paintGLCallable, args, NULL);
|
||||
PyObject *o = PyObject_Call(renderMethod, args, NULL);
|
||||
if (o) Py_DECREF(o); else PyErr_PrintEx(0);
|
||||
Py_DECREF(x);
|
||||
Py_DECREF(y);
|
||||
@ -137,22 +128,67 @@ void PyGLRenderer::paint()
|
||||
|
||||
void PyGLRenderer::cleanup()
|
||||
{
|
||||
if (m_cleanupGL.isEmpty())
|
||||
return;
|
||||
|
||||
QPythonPriv *priv = QPythonPriv::instance();
|
||||
priv->enter();
|
||||
PyObject *cleanupGLCallable = priv->eval(m_cleanupGL);
|
||||
if (!cleanupGLCallable) {
|
||||
qWarning() << "Cleanup callback " << m_cleanupGL << " not defined.";
|
||||
|
||||
PyObject *pyRendererObject = getPyRendererObject();
|
||||
if (!pyRendererObject || pyRendererObject == Py_None ||
|
||||
!PyObject_HasAttrString(m_pyRendererObject, "cleanup")) {
|
||||
priv->leave();
|
||||
return;
|
||||
}
|
||||
|
||||
PyObject *cleanupMethod = PyObject_GetAttrString(m_pyRendererObject, "cleanup");
|
||||
if (!cleanupMethod) {
|
||||
qWarning() << "Failed to get cleanup method of renderer.";
|
||||
PyErr_PrintEx(0);
|
||||
priv->leave();
|
||||
return;
|
||||
}
|
||||
|
||||
PyObject *args = PyTuple_New(0);
|
||||
PyObject *o = PyObject_Call(cleanupGLCallable, args, NULL);
|
||||
PyObject *o = PyObject_Call(cleanupMethod, args, NULL);
|
||||
if (o) Py_DECREF(o); else PyErr_PrintEx(0);
|
||||
m_initialized = true;
|
||||
Py_DECREF(args);
|
||||
Py_DECREF(cleanupGLCallable);
|
||||
Py_DECREF(cleanupMethod);
|
||||
priv->leave();
|
||||
}
|
||||
|
||||
PyObject *PyGLRenderer::getPyRendererObject() {
|
||||
if (m_pyRendererObject) {
|
||||
return m_pyRendererObject;
|
||||
}
|
||||
if (m_pyRenderer.userType() != qMetaTypeId<PyObjectRef>()) {
|
||||
qWarning() << "Renderer must be of type PyObjectRef (got "
|
||||
<< m_pyRenderer << ").";
|
||||
return NULL;
|
||||
}
|
||||
m_pyRendererObject = m_pyRenderer.value<PyObjectRef>().newRef();
|
||||
return m_pyRendererObject;
|
||||
}
|
||||
|
||||
PyObject *PyGLRenderer::getRenderMethod() {
|
||||
if (m_renderMethod) {
|
||||
return m_renderMethod;
|
||||
}
|
||||
|
||||
PyObject *pyRendererObject = getPyRendererObject();
|
||||
if (!pyRendererObject || pyRendererObject == Py_None) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyObject_HasAttrString(m_pyRendererObject, "render")) {
|
||||
qWarning() << "Renderer has no render method.";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *m_renderMethod = PyObject_GetAttrString(m_pyRendererObject, "render");
|
||||
if (!m_renderMethod) {
|
||||
qWarning() << "Failed to get render method of renderer.";
|
||||
PyErr_PrintEx(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_renderMethod;
|
||||
}
|
||||
|
@ -21,34 +21,34 @@
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QRect>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
|
||||
class PyGLRenderer : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PyGLRenderer();
|
||||
PyGLRenderer(QVariant pyRenderer);
|
||||
~PyGLRenderer();
|
||||
|
||||
void init();
|
||||
void paint();
|
||||
void render();
|
||||
void cleanup();
|
||||
|
||||
void setInitGL(QString initGL);
|
||||
void setPaintGL(QString paintGL);
|
||||
void setCleanupGL(QString cleanupGL);
|
||||
void setRect(QRect rect);
|
||||
|
||||
private:
|
||||
QRect m_rect;
|
||||
PyObject *m_paintGLCallable;
|
||||
QVariant m_pyRenderer;
|
||||
PyObject *m_pyRendererObject;
|
||||
PyObject *m_renderMethod;
|
||||
bool m_initialized;
|
||||
QString m_initGL;
|
||||
QString m_paintGL;
|
||||
QString m_cleanupGL;
|
||||
|
||||
PyObject *getPyRendererObject();
|
||||
PyObject *getRenderMethod();
|
||||
};
|
||||
|
||||
#endif /* PYOTHERSIDE_PYGLRENDERER_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user