Added quick render to QtQuick UI

This commit is contained in:
Michaël Lemaire 2014-09-09 17:56:52 +02:00
parent d0a5f19cc5
commit 06a8227de3
13 changed files with 401 additions and 4 deletions

View file

@ -5,6 +5,11 @@
#include "OpenGLRenderer.h"
#include "AtmosphereModeler.h"
#include "WaterModeler.h"
#include "RenderPreviewProvider.h"
#include "RenderProcess.h"
#include "RenderConfig.h"
#include <QQmlEngine>
MainModelerWindow::MainModelerWindow()
{
@ -12,8 +17,13 @@ MainModelerWindow::MainModelerWindow()
scenery->autoPreset();
renderer = new OpenGLRenderer(scenery);
qmlRegisterType<OpenGLView>("Paysages", 1, 0, "OpenGLView");
render_preview_provider = new RenderPreviewProvider();
render_process = new RenderProcess(render_preview_provider);
qmlRegisterType<OpenGLView>("Paysages", 1, 0, "OpenGLView");
engine()->addImageProvider("renderpreviewprovider", render_preview_provider);
setMinimumSize(QSize(1000, 800));
setTitle(QObject::tr("Paysages 3D"));
setResizeMode(QQuickView::SizeRootObjectToView);
setSource(QUrl("qrc:///main.qml"));
@ -27,6 +37,9 @@ MainModelerWindow::~MainModelerWindow()
delete atmosphere;
delete water;
delete render_preview_provider;
delete render_process;
delete renderer;
delete scenery;
}
@ -35,3 +48,26 @@ QObject *MainModelerWindow::findQmlObject(const QString &objectName)
{
return rootObject()->findChild<QObject *>(objectName);
}
void MainModelerWindow::keyReleaseEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_F5)
{
// Start render in a thread
render_process->startRender(scenery, RenderConfig(400, 300, 1, 3));
// Resize preview
QSize preview_size = render_process->getPreviewSize();
findQmlObject("preview_image")->setProperty("width", preview_size.width());
findQmlObject("preview_image")->setProperty("height", preview_size.height());
// Show render dialog
rootObject()->setProperty("state", QString("Render Dialog"));
}
else if (event->key() == Qt::Key_Escape)
{
render_process->stopRender();
rootObject()->setProperty("state", QString("Init"));
}
}

View file

@ -20,12 +20,18 @@ public:
inline Scenery *getScenery() const {return scenery;}
inline OpenGLRenderer *getRenderer() const {return renderer;}
protected:
virtual void keyReleaseEvent(QKeyEvent *event) override;
private:
OpenGLRenderer *renderer;
Scenery *scenery;
AtmosphereModeler *atmosphere;
WaterModeler *water;
RenderPreviewProvider *render_preview_provider;
RenderProcess *render_process;
};
}

View file

@ -0,0 +1,85 @@
#include "RenderPreviewProvider.h"
#include "Canvas.h"
#include "CanvasPreview.h"
#include "Color.h"
static inline QColor colorToQColor(Color color)
{
color.normalize();
return QColor(color.r * 255.0, color.g * 255.0, color.b * 255.0, color.a * 255.0);
}
RenderPreviewProvider::RenderPreviewProvider() :
QQuickImageProvider(QQuickImageProvider::Image)
{
canvas = NULL;
pixbuf = new QImage(1, 1, QImage::Format_ARGB32);
}
RenderPreviewProvider::~RenderPreviewProvider()
{
delete pixbuf;
}
QImage RenderPreviewProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
if (canvas)
{
canvas->getPreview()->updateLive(this);
}
if (size)
{
*size = pixbuf->size();
}
return *pixbuf;
}
void RenderPreviewProvider::setCanvas(const Canvas *canvas)
{
if (not this->canvas)
{
this->canvas = canvas;
canvas->getPreview()->initLive(this);
}
}
void RenderPreviewProvider::releaseCanvas()
{
if (canvas)
{
canvas->getPreview()->updateLive(this);
canvas = NULL;
}
}
void RenderPreviewProvider::setToneMapping(const ColorProfile &profile)
{
if (canvas)
{
canvas->getPreview()->setToneMapping(profile);
canvas->getPreview()->updateLive(this);
}
}
void RenderPreviewProvider::canvasResized(int width, int height)
{
if (QSize(width, height) != pixbuf->size())
{
delete pixbuf;
pixbuf = new QImage(width, height, QImage::Format_ARGB32);
pixbuf->fill(Qt::black);
}
}
void RenderPreviewProvider::canvasCleared(const Color &col)
{
pixbuf->fill(colorToQColor(col));
}
void RenderPreviewProvider::canvasPainted(int x, int y, const Color &col)
{
pixbuf->setPixel(x, pixbuf->height() - 1 - y, colorToQColor(col).rgb());
}

View file

@ -0,0 +1,53 @@
#ifndef RENDERPREVIEWPROVIDER_H
#define RENDERPREVIEWPROVIDER_H
#include "modeler_global.h"
#include <QQuickImageProvider>
#include "CanvasLiveClient.h"
namespace paysages {
namespace modeler {
/**
* Provider for a Qml Image content, filled from a canvas rendering.
*/
class RenderPreviewProvider : public QQuickImageProvider, public CanvasLiveClient
{
public:
RenderPreviewProvider();
virtual ~RenderPreviewProvider();
/**
* Set the canvas to watch and display, null to stop watching.
*
* This function must be called from the graphics thread.
*/
void setCanvas(const Canvas *canvas);
/**
* Release the bound canvas.
*/
void releaseCanvas();
/**
* Set the tone mapping to apply to pixel colors.
*/
void setToneMapping(const ColorProfile &profile);
protected:
virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
virtual void canvasResized(int width, int height) override;
virtual void canvasCleared(const Color &col) override;
virtual void canvasPainted(int x, int y, const Color &col) override;
private:
QImage* pixbuf;
const Canvas *canvas;
};
}
}
#endif // RENDERPREVIEWPROVIDER_H

View file

@ -0,0 +1,111 @@
#include "RenderProcess.h"
#include <QSize>
#include "SoftwareCanvasRenderer.h"
#include "RenderPreviewProvider.h"
#include "RenderConfig.h"
#include "Thread.h"
#include "Canvas.h"
#include "CanvasPreview.h"
class RenderThread: public Thread
{
public:
RenderThread(SoftwareCanvasRenderer *renderer): renderer(renderer)
{
}
virtual void run() override
{
renderer->render();
}
private:
SoftwareCanvasRenderer *renderer;
};
RenderProcess::RenderProcess(RenderPreviewProvider *destination):
destination(destination)
{
rendering = false;
renderer = NULL;
render_thread = NULL;
startTimer(100);
}
RenderProcess::~RenderProcess()
{
if (rendering)
{
renderer->interrupt();
}
rendering = false;
if (render_thread)
{
render_thread->join();
delete render_thread;
}
if (renderer)
{
delete renderer;
}
}
void RenderProcess::startRender(Scenery *scenery, const RenderConfig &config)
{
if (rendering)
{
return;
}
rendering = true;
if (renderer)
{
delete renderer;
}
renderer = new SoftwareCanvasRenderer();
renderer->setScenery(scenery);
renderer->setConfig(config);
destination->setCanvas(renderer->getCanvas());
render_thread = new RenderThread(renderer);
render_thread->start();
}
void RenderProcess::stopRender()
{
if (rendering)
{
renderer->interrupt();
}
}
const QSize RenderProcess::getPreviewSize()
{
if (renderer)
{
return QSize(renderer->getCanvas()->getPreview()->getWidth(), renderer->getCanvas()->getPreview()->getHeight());
}
else
{
return QSize(10, 10);
}
}
void RenderProcess::timerEvent(QTimerEvent *)
{
if (rendering and renderer->isFinished())
{
destination->releaseCanvas();
rendering = false;
render_thread->join();
delete render_thread;
render_thread = NULL;
}
}

View file

@ -0,0 +1,47 @@
#ifndef RENDERPROCESS_H
#define RENDERPROCESS_H
#include "modeler_global.h"
#include <QObject>
namespace paysages {
namespace modeler {
class RenderProcess: public QObject
{
Q_OBJECT
public:
RenderProcess(RenderPreviewProvider *destination);
virtual ~RenderProcess();
/**
* Start the rendering process in a separate thread.
*/
void startRender(Scenery *scenery, const RenderConfig &config);
/**
* Stop any currently running render.
*/
void stopRender();
/**
* Get the size of the preview image.
*/
const QSize getPreviewSize();
protected:
virtual void timerEvent(QTimerEvent *event) override;
private:
RenderPreviewProvider *destination;
bool rendering;
SoftwareCanvasRenderer *renderer;
Thread *render_thread;
};
}
}
#endif // RENDERPROCESS_H

View file

@ -12,6 +12,9 @@ namespace modeler {
class AtmosphereModeler;
class WaterModeler;
class RenderPreviewProvider;
class RenderProcess;
}
}

View file

@ -0,0 +1,27 @@
import QtQuick 2.2
Rectangle {
width: 400
height: 300
Image {
id: preview_image
objectName: "preview_image"
anchors.centerIn: parent
width: 100
height: 100
source: ""
cache: false
}
Timer {
interval: 500
running: true
repeat: true
onTriggered: {
preview_image.source = "";
preview_image.source = "image://renderpreviewprovider/live";
}
}
}

View file

@ -25,5 +25,6 @@
<file>images/icon_atmosphere_night.png</file>
<file>BaseChoice.qml</file>
<file>BaseChoiceItem.qml</file>
<file>RenderDialog.qml</file>
</qresource>
</RCC>

View file

@ -91,6 +91,12 @@ OpenGLView {
}
}
RenderDialog {
id: render_dialog
opacity: 0
anchors.fill: parent
}
PanelWaterLevel {
id: panel_water_level
tool: tool_water_level
@ -127,6 +133,19 @@ OpenGLView {
target: atmosphere_toolbar
opacity: 1
}
},
State {
name: "Render Dialog"
when: tool_display.selected
PropertyChanges {
target: primary_toolbar
opacity: 0
}
PropertyChanges {
target: render_dialog
opacity: 1
}
}
]

View file

@ -8,7 +8,9 @@ SOURCES += main.cpp \
OpenGLView.cpp \
MainModelerWindow.cpp \
WaterModeler.cpp \
AtmosphereModeler.cpp
AtmosphereModeler.cpp \
RenderPreviewProvider.cpp \
RenderProcess.cpp
RESOURCES += \
qml/app.qrc
@ -26,7 +28,9 @@ HEADERS += \
modeler_global.h \
MainModelerWindow.h \
WaterModeler.h \
AtmosphereModeler.h
AtmosphereModeler.h \
RenderPreviewProvider.h \
RenderProcess.h
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../system/release/ -lpaysages_system
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../system/debug/ -lpaysages_system
@ -69,4 +73,5 @@ OTHER_FILES += \
qml/PanelAtmosphereDaytime.qml \
qml/BaseSlider.qml \
qml/BaseChoice.qml \
qml/BaseChoiceItem.qml
qml/BaseChoiceItem.qml \
qml/RenderDialog.qml

View file

@ -17,6 +17,7 @@
SoftwareCanvasRenderer::SoftwareCanvasRenderer()
{
started = false;
finished = false;
interrupted = false;
canvas = new Canvas();
progress = 0.0;
@ -95,6 +96,7 @@ void SoftwareCanvasRenderer::render()
progress = (double)i / (double)n;
}
}
finished = true;
}
void SoftwareCanvasRenderer::interrupt()

View file

@ -24,6 +24,7 @@ public:
inline const Canvas *getCanvas() const {return canvas;}
inline double getProgress() const {return progress;}
inline bool isFinished() const {return finished;}
/**
* Set the renderer configuration.
@ -78,6 +79,7 @@ private:
int samples;
std::vector<Rasterizer*> rasterizers;
bool started;
bool finished;
bool interrupted;
ParallelWork *current_work;