From ab3edf1da3d76caaa189a04afed34b9eeeeb0739 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 14 Jul 2010 21:06:27 +0200 Subject: Draw the graphicsView in a texture. --- declarativeviewtexture.cpp | 93 +++++++++++++++++++++++++++++++ declarativeviewtexture.h | 28 ++++++++++ ogrewidget.cpp | 133 ++++++++++++++++++++++++++++++++------------- ogrewidget.h | 13 +++-- qmlogre.pro | 8 ++- 5 files changed, 231 insertions(+), 44 deletions(-) create mode 100644 declarativeviewtexture.cpp create mode 100644 declarativeviewtexture.h diff --git a/declarativeviewtexture.cpp b/declarativeviewtexture.cpp new file mode 100644 index 0000000..2af4879 --- /dev/null +++ b/declarativeviewtexture.cpp @@ -0,0 +1,93 @@ +#include "declarativeviewtexture.h" + +#include +#include +#include +#include + +static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) +{ + const int width = img.width(); + const int height = img.height(); + + if (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian) + { + for (int i = 0; i < height; ++i) { + uint *p = (uint *) img.scanLine(i); + for (int x = 0; x < width; ++x) + p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); + } + } else { + for (int i = 0; i < height; ++i) { + uint *p = (uint *) img.scanLine(i); + for (int x = 0; x < width; ++x) + p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff); + } + } +} + +DeclarativeViewTexture::DeclarativeViewTexture(QWidget *parent) : + QDeclarativeView(parent), + m_bufferPainter(0) +{ + setAttribute(Qt::WA_DontShowOnScreen); + setOptimizationFlag(QGraphicsView::IndirectPainting); + + glGenTextures(1, &m_textureId); +} + +DeclarativeViewTexture::~DeclarativeViewTexture() +{ + +} + +void DeclarativeViewTexture::paintEvent(QPaintEvent *event) +{ + // Render the view in an offscreen image + if (m_bufferPainter) + delete m_bufferPainter; + m_bufferPainter = new QPainter; + + QRegion exposedRegion = event->region(); + QImage im(exposedRegion.boundingRect().size(), QImage::Format_ARGB32_Premultiplied); + im.fill(Qt::transparent); + m_bufferPainter->begin(&im); + m_bufferPainter->translate(-exposedRegion.boundingRect().topLeft()); + m_bufferPainter->setClipRegion(exposedRegion); + + QDeclarativeView::paintEvent(event); + + m_bufferPainter->end(); + + // Upload the image in graphics memory + glBindTexture(GL_TEXTURE_2D, m_textureId); + qgl_byteSwapImage(im, GL_UNSIGNED_BYTE); + foreach (const QRect &rect, exposedRegion.rects()) { + if (rect.size() == size()) { + glTexImage2D(GL_TEXTURE_2D, 0, 4, rect.width(), rect.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, im.bits()); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + break; + } else { + QRect adjustedRect = rect.translated(-exposedRegion.boundingRect().topLeft()); + QImage subIm = im.copy(adjustedRect); + glTexSubImage2D(GL_TEXTURE_2D, 0, rect.left(), rect.top(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, subIm.bits()); + } + } + glBindTexture(GL_TEXTURE_2D, 0); +} + +void DeclarativeViewTexture::drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[]) +{ + QDeclarativeView::drawItems(m_bufferPainter, numItems, items, options); +} + +void DeclarativeViewTexture::drawBackground(QPainter *painter, const QRectF &rect) +{ + QDeclarativeView::drawBackground(m_bufferPainter, rect); +} + +void DeclarativeViewTexture::drawForeground(QPainter *painter, const QRectF &rect) +{ + QDeclarativeView::drawForeground(m_bufferPainter, rect); +} diff --git a/declarativeviewtexture.h b/declarativeviewtexture.h new file mode 100644 index 0000000..edf93e3 --- /dev/null +++ b/declarativeviewtexture.h @@ -0,0 +1,28 @@ +#ifndef DECLARATIVEVIEWTEXTURE_H +#define DECLARATIVEVIEWTEXTURE_H + +#include +#include + +class DeclarativeViewTexture : public QDeclarativeView +{ + Q_OBJECT +public: + explicit DeclarativeViewTexture(QWidget *parent = 0); + ~DeclarativeViewTexture(); + + GLuint textureId() const + { return m_textureId; } + +protected: + void paintEvent(QPaintEvent *event); + void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[]); + void drawBackground(QPainter *painter, const QRectF &rect); + void drawForeground(QPainter *painter, const QRectF &rect); + +private: + QPainter *m_bufferPainter; + GLuint m_textureId; +}; + +#endif // DECLARATIVEVIEWTEXTURE_H diff --git a/ogrewidget.cpp b/ogrewidget.cpp index 7b5d0e5..991bf2a 100644 --- a/ogrewidget.cpp +++ b/ogrewidget.cpp @@ -1,5 +1,7 @@ #include "ogrewidget.h" +#include "declarativeviewtexture.h" + #include #include #include @@ -7,7 +9,7 @@ #include #include #include -#include +#include #include #if defined(Q_WS_X11) @@ -15,19 +17,19 @@ #endif OgreWidget::OgreWidget(QWidget *parent) : - QWidget(parent), + QGLWidget(parent), m_root(0), m_camera(0), m_sceneManager(0), m_renderWindow(0), - m_viewport(0) + m_viewport(0), + m_QmlUI(0) { - setAttribute(Qt::WA_PaintOnScreen); - setAttribute(Qt::WA_NoSystemBackground); + setAutoBufferSwap(false); + setFormat(QGLFormat(QGL::DoubleBuffer | QGL::SampleBuffers)); + setAttribute(Qt::WA_OpaquePaintEvent); resize(1024, 768); - initOgre(); - startTimer(16); } @@ -48,6 +50,90 @@ OgreWidget::~OgreWidget() delete m_root; } +void OgreWidget::paintGL() +{ + // Render Ogre + Ogre::WindowEventUtilities::messagePump(); + m_root->renderOneFrame(); + + // Set a clear pass to give the renderer a clear renderstate + static Ogre::Pass* clearPass = 0; + if (!clearPass) + { + Ogre::MaterialPtr clearMat = Ogre::MaterialManager::getSingleton().getByName("BaseWhite"); + clearPass = clearMat->getTechnique(0)->getPass(0); + } + m_sceneManager->_setPass(clearPass, true, false); + + // Render the QDeclarativeView texture on top + glBindTexture(GL_TEXTURE_2D, m_QmlUI->textureId()); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glEnable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + glEnable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /*float top = qMax(-1.f, qMin(1.f, (rect().center().y() - m_QmlUI->pos().y()) / float(rect().center().y()))); + float left = qMax(-1.f, qMin(1.f, (rect().center().x() - m_QmlUI->pos().x()) / float(-rect().center().x()))); + float bottom = qMax(-1.f, qMin(1.f, (rect().center().y() - m_QmlUI->pos().y() - m_QmlUI->height()) / float(rect().center().y()))); + float right = qMax(-1.f, qMin(1.f, (rect().center().x() - m_QmlUI->pos().x() - m_QmlUI->width()) / float(-rect().center().x()))); + float texTop = qMin(1.f, qMax(-m_QmlUI->pos().y() / float(m_QmlUI->height()), 0.f)); + float texLeft = qMin(1.f, qMax(-m_QmlUI->pos().x() / float(m_QmlUI->width()), 0.f)); + float texBottom = qMax(0.f, qMin(height() - m_QmlUI->pos().y() / float(m_QmlUI->height()), 1.f)); + float texRight = qMax(0.f, qMin(width() - m_QmlUI->pos().x() / float(m_QmlUI->width()), 1.f));*/ + + float top = (rect().center().y() - m_QmlUI->pos().y()) / float(rect().center().y()); + float left = (rect().center().x() - m_QmlUI->pos().x()) / float(-rect().center().x()); + float bottom = (rect().center().y() - m_QmlUI->pos().y() - m_QmlUI->height()) / float(rect().center().y()); + float right = (rect().center().x() - m_QmlUI->pos().x() - m_QmlUI->width()) / float(-rect().center().x()); + + glBegin(GL_QUADS); + /*glTexCoord2f(texLeft, texTop); glVertex3f(left, top, -1.0f); // Top Left + glTexCoord2f(texLeft, texBottom); glVertex3f(left, bottom, -1.0f); // Bottom Left + glTexCoord2f(texRight, texBottom); glVertex3f(right, bottom, -1.0f); // Bottom Right + glTexCoord2f(texRight, texTop); glVertex3f(right, top, -1.0f); // Top Right*/ + glTexCoord2f(0, 0); glVertex3f(left, top, -1.0f); // Top Left + glTexCoord2f(0, 1); glVertex3f(left, bottom, -1.0f); // Bottom Left + glTexCoord2f(1, 1); glVertex3f(right, bottom, -1.0f); // Bottom Right + glTexCoord2f(1, 0); glVertex3f(right, top, -1.0f); // Top Right + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); +} + +void OgreWidget::timerEvent(QTimerEvent *e) +{ + Q_UNUSED(e) + paintGL(); + swapBuffers(); +} + +void OgreWidget::initializeGL() +{ + initOgre(); + + m_QmlUI = new DeclarativeViewTexture(this); +} + +void OgreWidget::resizeGL(int w, int h) +{ + if (m_renderWindow) { + m_renderWindow->resize(w, h); + m_renderWindow->windowMovedOrResized(); + } + if (m_camera) { + Ogre::Real aspectRatio = Ogre::Real(w) / Ogre::Real(h); + m_camera->setAspectRatio(aspectRatio); + } +} + + void OgreWidget::initOgre() { m_root = new Ogre::Root; @@ -60,9 +146,6 @@ void OgreWidget::initOgre() Ogre::NameValuePairList params; Ogre::String externalWindowHandleParams; - //Accept input focus - //setFocusPolicy(Qt::StrongFocus); - #if defined(Q_WS_WIN) //positive integer for W32 (HWND handle) - According to Ogre Docs externalWindowHandleParams = Ogre::StringConverter::toString((unsigned int)(winId())); @@ -86,6 +169,9 @@ void OgreWidget::initOgre() params["parentWindowHandle"] = externalWindowHandleParams; #endif + params["externalGLControl"] = "true"; + params["currentGLContext"] = "true"; + //Finally create our window. m_renderWindow = m_root->createRenderWindow("OgreWindow", width(), height(), false, ¶ms); m_renderWindow->setVisible(true); @@ -119,30 +205,3 @@ void OgreWidget::initOgre() m_camera->move(Ogre::Vector3(0, 0, 300)); m_camera->lookAt(0, 0, 0); } - -void OgreWidget::render() -{ - Ogre::WindowEventUtilities::messagePump(); - m_root->renderOneFrame(); -} - -void OgreWidget::timerEvent(QTimerEvent *e) -{ - Q_UNUSED(e) - render(); -} - -void OgreWidget::resizeEvent(QResizeEvent *e) -{ - const QSize &newSize = e->size(); - if (m_renderWindow) { - m_renderWindow->resize(newSize.width(), newSize.height()); - m_renderWindow->windowMovedOrResized(); - } - if (m_camera) { - Ogre::Real aspectRatio = Ogre::Real(newSize.width()) / Ogre::Real(newSize.height()); - m_camera->setAspectRatio(aspectRatio); - } - - QWidget::resizeEvent(e); -} diff --git a/ogrewidget.h b/ogrewidget.h index 6b940a3..d1a2ec4 100644 --- a/ogrewidget.h +++ b/ogrewidget.h @@ -1,7 +1,7 @@ #ifndef OGREWIDGET_H #define OGREWIDGET_H -#include +#include #define STRINGIFY_(x) #x #define STRINGIFY(x) STRINGIFY_(x) @@ -15,8 +15,9 @@ class RenderWindow; class Viewport; class RenderTarget; } +class DeclarativeViewTexture; -class OgreWidget : public QWidget +class OgreWidget : public QGLWidget { Q_OBJECT public: @@ -36,9 +37,11 @@ public: protected: void initOgre(); - void render(); void timerEvent(QTimerEvent *); - void resizeEvent(QResizeEvent *); + + void initializeGL(); + void resizeGL(int w, int h); + void paintGL(); private: Ogre::Root *m_root; @@ -46,6 +49,8 @@ private: Ogre::SceneManager *m_sceneManager; Ogre::RenderWindow *m_renderWindow; Ogre::Viewport *m_viewport; + + DeclarativeViewTexture *m_QmlUI; }; #endif // OGREWIDGET_H diff --git a/qmlogre.pro b/qmlogre.pro index ac72c56..e0308a0 100644 --- a/qmlogre.pro +++ b/qmlogre.pro @@ -1,5 +1,5 @@ CONFIG += qt -QT += opengl +QT += opengl declarative TEMPLATE = app TARGET = qmlogre @@ -40,7 +40,9 @@ MOC_DIR = ./.moc SOURCES += main.cpp \ - ogrewidget.cpp + ogrewidget.cpp \ + declarativeviewtexture.cpp HEADERS += \ - ogrewidget.h + ogrewidget.h \ + declarativeviewtexture.h -- cgit v1.2.3