From 43431aae87ac5c94a3ce638caa8fec99a225c229 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Thu, 5 Jun 2014 17:12:49 +0200 Subject: [PATCH 01/29] New Canvas software rendering structure (WIP) --- src/interface/desktop/WidgetCanvas.cpp | 6 ++ src/interface/desktop/WidgetCanvas.h | 29 +++++++ src/interface/desktop/WidgetPreviewCanvas.cpp | 46 +++++++++++ src/interface/desktop/WidgetPreviewCanvas.h | 39 ++++++++++ src/interface/desktop/desktop.pro | 8 +- src/interface/desktop/desktop_global.h | 3 + src/interface/desktop/dialogrender.cpp | 9 +++ src/interface/desktop/dialogrender.h | 3 + src/render/software/Canvas.cpp | 76 +++++++++++++++++++ src/render/software/Canvas.h | 46 +++++++++++ src/render/software/CanvasFragment.cpp | 5 ++ src/render/software/CanvasFragment.h | 21 +++++ src/render/software/CanvasLiveClient.cpp | 17 +++++ src/render/software/CanvasLiveClient.h | 25 ++++++ src/render/software/CanvasPixel.cpp | 5 ++ src/render/software/CanvasPixel.h | 23 ++++++ src/render/software/CanvasPortion.cpp | 12 +++ src/render/software/CanvasPortion.h | 43 +++++++++++ src/render/software/Rasterizer.cpp | 5 ++ src/render/software/Rasterizer.h | 21 +++++ src/render/software/SkyRasterizer.h | 4 +- .../software/SoftwareCanvasRenderer.cpp | 51 +++++++++++++ src/render/software/SoftwareCanvasRenderer.h | 61 +++++++++++++++ src/render/software/SoftwareRenderer.cpp | 7 ++ src/render/software/SoftwareRenderer.h | 5 ++ src/render/software/TerrainRasterizer.h | 3 +- src/render/software/WaterRasterizer.h | 4 +- src/render/software/software.pro | 18 ++++- src/render/software/software_global.h | 8 ++ src/tests/Canvas_Test.cpp | 41 ++++++++++ src/tests/tests.pro | 3 +- 31 files changed, 639 insertions(+), 8 deletions(-) create mode 100644 src/interface/desktop/WidgetCanvas.cpp create mode 100644 src/interface/desktop/WidgetCanvas.h create mode 100644 src/interface/desktop/WidgetPreviewCanvas.cpp create mode 100644 src/interface/desktop/WidgetPreviewCanvas.h create mode 100644 src/render/software/Canvas.cpp create mode 100644 src/render/software/Canvas.h create mode 100644 src/render/software/CanvasFragment.cpp create mode 100644 src/render/software/CanvasFragment.h create mode 100644 src/render/software/CanvasLiveClient.cpp create mode 100644 src/render/software/CanvasLiveClient.h create mode 100644 src/render/software/CanvasPixel.cpp create mode 100644 src/render/software/CanvasPixel.h create mode 100644 src/render/software/CanvasPortion.cpp create mode 100644 src/render/software/CanvasPortion.h create mode 100644 src/render/software/Rasterizer.cpp create mode 100644 src/render/software/Rasterizer.h create mode 100644 src/render/software/SoftwareCanvasRenderer.cpp create mode 100644 src/render/software/SoftwareCanvasRenderer.h create mode 100644 src/tests/Canvas_Test.cpp diff --git a/src/interface/desktop/WidgetCanvas.cpp b/src/interface/desktop/WidgetCanvas.cpp new file mode 100644 index 0000000..a1a84b5 --- /dev/null +++ b/src/interface/desktop/WidgetCanvas.cpp @@ -0,0 +1,6 @@ +#include "WidgetCanvas.h" + +WidgetCanvas::WidgetCanvas(QWidget *parent) : + QWidget(parent) +{ +} diff --git a/src/interface/desktop/WidgetCanvas.h b/src/interface/desktop/WidgetCanvas.h new file mode 100644 index 0000000..ad74ae3 --- /dev/null +++ b/src/interface/desktop/WidgetCanvas.h @@ -0,0 +1,29 @@ +#ifndef WIDGETCANVAS_H +#define WIDGETCANVAS_H + +#include "desktop_global.h" + +#include + +namespace paysages { +namespace desktop { + +/*! + * \brief Widget to display the full content of a Canvas. + */ +class WidgetCanvas : public QWidget +{ + Q_OBJECT +public: + explicit WidgetCanvas(QWidget *parent = 0); + +signals: + +public slots: + +}; + +} +} + +#endif // WIDGETCANVAS_H diff --git a/src/interface/desktop/WidgetPreviewCanvas.cpp b/src/interface/desktop/WidgetPreviewCanvas.cpp new file mode 100644 index 0000000..3c104e2 --- /dev/null +++ b/src/interface/desktop/WidgetPreviewCanvas.cpp @@ -0,0 +1,46 @@ +#include "WidgetPreviewCanvas.h" + +#include "Canvas.h" + +WidgetPreviewCanvas::WidgetPreviewCanvas(QWidget *parent) : + QWidget(parent), canvas(NULL) +{ + startTimer(1000); +} + +void WidgetPreviewCanvas::setCanvas(const Canvas *canvas) +{ + this->canvas = canvas; +} + +void WidgetPreviewCanvas::canvasResized(int width, int height) +{ + // TODO +} + +void WidgetPreviewCanvas::canvasCleared(const Color &col) +{ + // TODO +} + +void WidgetPreviewCanvas::canvasPainted(int x, int y, const Color &col) +{ + // TODO +} + +void WidgetPreviewCanvas::timerEvent(QTimerEvent *) +{ + // Refresh the view + if (canvas) + { + int width = canvas->getPreviewWidth(); + int height = canvas->getPreviewHeight(); + + if (QSize(width, height) != this->size()) + { + setMaximumSize(width, height); + setMinimumSize(width, height); + resize(width, height); + } + } +} diff --git a/src/interface/desktop/WidgetPreviewCanvas.h b/src/interface/desktop/WidgetPreviewCanvas.h new file mode 100644 index 0000000..6aacafe --- /dev/null +++ b/src/interface/desktop/WidgetPreviewCanvas.h @@ -0,0 +1,39 @@ +#ifndef WIDGETPREVIEWCANVAS_H +#define WIDGETPREVIEWCANVAS_H + +#include "desktop_global.h" + +#include +#include "CanvasLiveClient.h" + +namespace paysages { +namespace desktop { + +/*! + * \brief Widget to display a live-updated preview of a Canvas software rendering. + */ +class WidgetPreviewCanvas : public QWidget, public CanvasLiveClient +{ + Q_OBJECT +public: + explicit WidgetPreviewCanvas(QWidget *parent = 0); + + /*! + * \brief Set the canvas to watch and display, null to stop watching. + */ + void setCanvas(const Canvas *canvas); + +protected: + virtual void canvasResized(int width, int height); + virtual void canvasCleared(const Color &col); + virtual void canvasPainted(int x, int y, const Color &col); + virtual void timerEvent(QTimerEvent *event); + +private: + const Canvas *canvas; +}; + +} +} + +#endif // WIDGETPREVIEWCANVAS_H diff --git a/src/interface/desktop/desktop.pro b/src/interface/desktop/desktop.pro index cb703cd..e6a47d2 100644 --- a/src/interface/desktop/desktop.pro +++ b/src/interface/desktop/desktop.pro @@ -52,7 +52,9 @@ HEADERS += \ lighting/SmallPreviewHues.h \ textures/DialogTexturesLayer.h \ desktop_global.h \ - DesktopScenery.h + DesktopScenery.h \ + WidgetCanvas.h \ + WidgetPreviewCanvas.h SOURCES += \ terrain/widgetheightmap.cpp \ @@ -96,7 +98,9 @@ SOURCES += \ lighting/SmallPreviewColor.cpp \ lighting/SmallPreviewHues.cpp \ textures/DialogTexturesLayer.cpp \ - DesktopScenery.cpp + DesktopScenery.cpp \ + WidgetCanvas.cpp \ + WidgetPreviewCanvas.cpp FORMS += \ terrain/dialogterrainpainting.ui \ diff --git a/src/interface/desktop/desktop_global.h b/src/interface/desktop/desktop_global.h index da63022..79c0d46 100644 --- a/src/interface/desktop/desktop_global.h +++ b/src/interface/desktop/desktop_global.h @@ -10,6 +10,9 @@ namespace paysages { namespace desktop { class BaseInput; class BaseForm; + + class WidgetCanvas; + class WidgetPreviewCanvas; } } diff --git a/src/interface/desktop/dialogrender.cpp b/src/interface/desktop/dialogrender.cpp index 1d979f0..59b6b70 100644 --- a/src/interface/desktop/dialogrender.cpp +++ b/src/interface/desktop/dialogrender.cpp @@ -21,6 +21,8 @@ #include "SoftwareRenderer.h" #include "Scenery.h" #include "ColorProfile.h" +#include "SoftwareCanvasRenderer.h" +#include "WidgetPreviewCanvas.h" static DialogRender* _current_dialog; @@ -103,6 +105,11 @@ DialogRender::DialogRender(QWidget *parent, SoftwareRenderer* renderer): _scroll->setWidget(area); layout()->addWidget(_scroll); + canvas_renderer = new SoftwareCanvasRenderer(); + canvas_preview = new WidgetPreviewCanvas(this); + canvas_preview->setCanvas(canvas_renderer->getCanvas()); + layout()->addWidget(canvas_preview); + // Status bar _info = new QWidget(this); _info->setLayout(new QHBoxLayout()); @@ -180,6 +187,8 @@ void DialogRender::startRender(RenderArea::RenderParams params) { _started = time(NULL); + canvas_renderer->setSize(params.width, params.height, params.antialias); + applyRenderSize(params.width, params.height); _renderer->setPreviewCallbacks(_renderStart, _renderDraw, _renderUpdate); diff --git a/src/interface/desktop/dialogrender.h b/src/interface/desktop/dialogrender.h index 80dbb05..62c6aa3 100644 --- a/src/interface/desktop/dialogrender.h +++ b/src/interface/desktop/dialogrender.h @@ -45,6 +45,9 @@ signals: void renderEnded(); private: + SoftwareCanvasRenderer* canvas_renderer; + WidgetPreviewCanvas* canvas_preview; + QScrollArea* _scroll; QWidget* _info; QWidget* _actions; diff --git a/src/render/software/Canvas.cpp b/src/render/software/Canvas.cpp new file mode 100644 index 0000000..09a890e --- /dev/null +++ b/src/render/software/Canvas.cpp @@ -0,0 +1,76 @@ +#include "Canvas.h" + +#include "CanvasPortion.h" +#include + +Canvas::Canvas() +{ + horizontal_portion_count = 1; + vertical_portion_count = 1; + width = 1; + height = 1; + preview_width = 1; + preview_height = 1; + portions.push_back(new CanvasPortion()); +} + +Canvas::~Canvas() +{ + for (auto portion: portions) + { + delete portion; + } +} + +void Canvas::setSize(int width, int height) +{ + horizontal_portion_count = 1 + width / 400; + vertical_portion_count = 1 + height / 400; + + int portion_width = width / horizontal_portion_count; + int portion_height = height / vertical_portion_count; + + for (auto portion: portions) + { + delete portion; + } + portions.clear(); + + int done_width = 0; + int done_height = 0; + + for (int y = 0; y < vertical_portion_count; y++) + { + done_width = 0; + for (int x = 0; x < horizontal_portion_count; x++) + { + CanvasPortion *portion = new CanvasPortion(); + + portion->setSize((x == horizontal_portion_count - 1) ? width - done_width : portion_width, + (y == vertical_portion_count - 1) ? height - done_height : portion_height); + + done_width += portion->getWidth(); + if (x == horizontal_portion_count - 1) + { + done_height += portion->getHeight(); + } + + portions.push_back(portion); + } + assert(done_width == width); + } + assert(done_height == height); + + this->width = width; + this->height = height; + this->preview_width = width; + this->preview_height = height; +} + +CanvasPortion *Canvas::at(int x, int y) const +{ + assert(x >= 0 && x < horizontal_portion_count); + assert(y >= 0 && y < vertical_portion_count); + + return portions[y * horizontal_portion_count + x]; +} diff --git a/src/render/software/Canvas.h b/src/render/software/Canvas.h new file mode 100644 index 0000000..4934e06 --- /dev/null +++ b/src/render/software/Canvas.h @@ -0,0 +1,46 @@ +#ifndef CANVAS_H +#define CANVAS_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +/** + * @brief Graphics area to draw and do compositing. + * + * Software rendering is done in portions of Canvas (in CanvasPortion class). + * This splitting in portions allows to keep memory consumption low. + */ +class SOFTWARESHARED_EXPORT Canvas +{ +public: + Canvas(); + ~Canvas(); + + void setSize(int width, int height); + + inline int getHorizontalPortionCount() const {return horizontal_portion_count;} + inline int getVerticalPortionCount() const {return vertical_portion_count;} + + CanvasPortion *at(int x, int y) const; + + inline int getWidth() const {return width;} + inline int getHeight() const {return height;} + inline int getPreviewWidth() const {return preview_width;} + inline int getPreviewHeight() const {return preview_height;} + +private: + std::vector portions; + int horizontal_portion_count; + int vertical_portion_count; + int width; + int height; + int preview_width; + int preview_height; +}; + +} +} + +#endif // CANVAS_H diff --git a/src/render/software/CanvasFragment.cpp b/src/render/software/CanvasFragment.cpp new file mode 100644 index 0000000..2d105dd --- /dev/null +++ b/src/render/software/CanvasFragment.cpp @@ -0,0 +1,5 @@ +#include "CanvasFragment.h" + +CanvasFragment::CanvasFragment() +{ +} diff --git a/src/render/software/CanvasFragment.h b/src/render/software/CanvasFragment.h new file mode 100644 index 0000000..f1b3b5a --- /dev/null +++ b/src/render/software/CanvasFragment.h @@ -0,0 +1,21 @@ +#ifndef CANVASFRAGMENT_H +#define CANVASFRAGMENT_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +/** + * @brief Representation of world coordinates projected in a canvas pixel. + */ +class SOFTWARESHARED_EXPORT CanvasFragment +{ +public: + CanvasFragment(); +}; + +} +} + +#endif // CANVASFRAGMENT_H diff --git a/src/render/software/CanvasLiveClient.cpp b/src/render/software/CanvasLiveClient.cpp new file mode 100644 index 0000000..3586fdd --- /dev/null +++ b/src/render/software/CanvasLiveClient.cpp @@ -0,0 +1,17 @@ +#include "CanvasLiveClient.h" + +CanvasLiveClient::CanvasLiveClient() +{ +} + +void CanvasLiveClient::canvasResized(int, int) +{ +} + +void CanvasLiveClient::canvasCleared(const Color &) +{ +} + +void CanvasLiveClient::canvasPainted(int, int, const Color &) +{ +} diff --git a/src/render/software/CanvasLiveClient.h b/src/render/software/CanvasLiveClient.h new file mode 100644 index 0000000..133e7cb --- /dev/null +++ b/src/render/software/CanvasLiveClient.h @@ -0,0 +1,25 @@ +#ifndef CANVASLIVECLIENT_H +#define CANVASLIVECLIENT_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +/** + * @brief Abstract class to receive live modifications from canvas preview. + */ +class SOFTWARESHARED_EXPORT CanvasLiveClient +{ +public: + CanvasLiveClient(); + + virtual void canvasResized(int width, int height); + virtual void canvasCleared(const Color &col); + virtual void canvasPainted(int x, int y, const Color &col); +}; + +} +} + +#endif // CANVASLIVECLIENT_H diff --git a/src/render/software/CanvasPixel.cpp b/src/render/software/CanvasPixel.cpp new file mode 100644 index 0000000..c7c1b5c --- /dev/null +++ b/src/render/software/CanvasPixel.cpp @@ -0,0 +1,5 @@ +#include "CanvasPixel.h" + +CanvasPixel::CanvasPixel() +{ +} diff --git a/src/render/software/CanvasPixel.h b/src/render/software/CanvasPixel.h new file mode 100644 index 0000000..4a00c62 --- /dev/null +++ b/src/render/software/CanvasPixel.h @@ -0,0 +1,23 @@ +#ifndef CANVASPIXEL_H +#define CANVASPIXEL_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +/** + * @brief One pixel of a Canvas. + * + * A pixel stores superimposed fragments (CanvasFragment), sorted by their distance to camera. + */ +class SOFTWARESHARED_EXPORT CanvasPixel +{ +public: + CanvasPixel(); +}; + +} +} + +#endif // CANVASPIXEL_H diff --git a/src/render/software/CanvasPortion.cpp b/src/render/software/CanvasPortion.cpp new file mode 100644 index 0000000..c44e15f --- /dev/null +++ b/src/render/software/CanvasPortion.cpp @@ -0,0 +1,12 @@ +#include "CanvasPortion.h" + +CanvasPortion::CanvasPortion() +{ +} + +void CanvasPortion::setSize(int width, int height) +{ + this->width = width; + this->height = height; + // TODO Resize and clear pixels +} diff --git a/src/render/software/CanvasPortion.h b/src/render/software/CanvasPortion.h new file mode 100644 index 0000000..274d645 --- /dev/null +++ b/src/render/software/CanvasPortion.h @@ -0,0 +1,43 @@ +#ifndef CANVASPORTION_H +#define CANVASPORTION_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +typedef struct { + double red; + double green; + double blue; +} CanvasPreviewPixel; + +/** + * @brief Rectangular portion of a Canvas. + * + * Contains the pixels of a canvas region (CanvasPixel). + */ +class SOFTWARESHARED_EXPORT CanvasPortion +{ +public: + CanvasPortion(); + + inline int getWidth() const {return width;} + inline int getHeight() const {return height;} + + void setSize(int width, int height); + +private: + int width; + int height; + std::vector *pixels; + + int preview_width; + int preview_height; + std::vector *preview_pixels; +}; + +} +} + +#endif // CANVASPORTION_H diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp new file mode 100644 index 0000000..2545ba1 --- /dev/null +++ b/src/render/software/Rasterizer.cpp @@ -0,0 +1,5 @@ +#include "Rasterizer.h" + +Rasterizer::Rasterizer() +{ +} diff --git a/src/render/software/Rasterizer.h b/src/render/software/Rasterizer.h new file mode 100644 index 0000000..422a8e2 --- /dev/null +++ b/src/render/software/Rasterizer.h @@ -0,0 +1,21 @@ +#ifndef RASTERIZER_H +#define RASTERIZER_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +/** + * @brief Base abstract class for scenery pieces that can be rasterized to polygons. + */ +class SOFTWARESHARED_EXPORT Rasterizer +{ +public: + Rasterizer(); +}; + +} +} + +#endif // RASTERIZER_H diff --git a/src/render/software/SkyRasterizer.h b/src/render/software/SkyRasterizer.h index 1d03902..c6432fc 100644 --- a/src/render/software/SkyRasterizer.h +++ b/src/render/software/SkyRasterizer.h @@ -3,10 +3,12 @@ #include "software_global.h" +#include "Rasterizer.h" + namespace paysages { namespace software { -class SOFTWARESHARED_EXPORT SkyRasterizer +class SOFTWARESHARED_EXPORT SkyRasterizer: public Rasterizer { public: SkyRasterizer(SoftwareRenderer* renderer); diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp new file mode 100644 index 0000000..f8c9742 --- /dev/null +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -0,0 +1,51 @@ +#include "SoftwareCanvasRenderer.h" + +#include "Rasterizer.h" +#include "SoftwareRenderer.h" +#include "Canvas.h" + +SoftwareCanvasRenderer::SoftwareCanvasRenderer() +{ + started = false; + renderer = new SoftwareRenderer(); + canvas = new Canvas(); +} + +SoftwareCanvasRenderer::~SoftwareCanvasRenderer() +{ + delete renderer; + delete canvas; +} + +void SoftwareCanvasRenderer::setSize(int width, int height, int samples) +{ + if (not started) + { + canvas->setSize(width * samples, height * samples); + } +} + +void SoftwareCanvasRenderer::render() +{ + // TEMP + started = true; + CanvasPortion *portion = canvas->at(0, 0); + + rasterize(portion, true); + postProcess(portion, true); +} + +void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded) +{ + std::vector rasterizers; + renderer->getRasterizers(&rasterizers); + + for (auto &rasterizer:rasterizers) + { + } +} + +void SoftwareCanvasRenderer::postProcess(CanvasPortion *portion, bool threaded) +{ + // TODO +} diff --git a/src/render/software/SoftwareCanvasRenderer.h b/src/render/software/SoftwareCanvasRenderer.h new file mode 100644 index 0000000..847fbd7 --- /dev/null +++ b/src/render/software/SoftwareCanvasRenderer.h @@ -0,0 +1,61 @@ +#ifndef SOFTWARECANVASRENDERER_H +#define SOFTWARECANVASRENDERER_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +/** + * @brief Software rendering inside a Canvas surface. + * + * This class launches the rasterization process into canvas portions and + * redirects post processing to the software renderer. + * + * It tries to keep a canvas portion rasterized ahead of the post processing. + */ +class SOFTWARESHARED_EXPORT SoftwareCanvasRenderer +{ +public: + SoftwareCanvasRenderer(); + ~SoftwareCanvasRenderer(); + + inline const Canvas *getCanvas() const {return canvas;} + + /** + * @brief Set the rendering size in pixels. + * + * Set 'samples' to something bigger than 1 to allow for the multi-sampling of pixels. + */ + void setSize(int width, int height, int samples=1); + + /** + * @brief Start the two-pass render process. + */ + void render(); + +protected: + /** + * @brief Rasterize the scenery into a canvas portion. + * + * If 'threaded' is true, the rasterization will take advantage of multiple CPU cores. + */ + void rasterize(CanvasPortion* portion, bool threaded); + + /** + * @brief Apply post-processing to fragments stored in the CanvasPortion. + * + * If 'threaded' is true, the post-processing will take advantage of multiple CPU cores. + */ + void postProcess(CanvasPortion* portion, bool threaded=true); + +private: + SoftwareRenderer* renderer; + Canvas* canvas; + bool started; +}; + +} +} + +#endif // SOFTWARECANVASRENDERER_H diff --git a/src/render/software/SoftwareRenderer.cpp b/src/render/software/SoftwareRenderer.cpp index 1f88f17..12cdb64 100644 --- a/src/render/software/SoftwareRenderer.cpp +++ b/src/render/software/SoftwareRenderer.cpp @@ -108,6 +108,13 @@ void SoftwareRenderer::prepare() //fluid_medium->registerMedium(water_renderer); } +void SoftwareRenderer::getRasterizers(std::vector *array) +{ + array->push_back(TerrainRasterizer(this)); + array->push_back(WaterRasterizer(this)); + array->push_back(SkyRasterizer(this)); +} + void SoftwareRenderer::rasterize() { TerrainRasterizer terrain(this); diff --git a/src/render/software/SoftwareRenderer.h b/src/render/software/SoftwareRenderer.h index 9f269f3..08b2d76 100644 --- a/src/render/software/SoftwareRenderer.h +++ b/src/render/software/SoftwareRenderer.h @@ -59,6 +59,11 @@ public: */ virtual void prepare(); + /*! + * \brief Get the list of objects that can be rasterized to polygons on a canvas. + */ + virtual void getRasterizers(std::vector *array); + /*! * \brief Start the rasterization process. */ diff --git a/src/render/software/TerrainRasterizer.h b/src/render/software/TerrainRasterizer.h index 47b559e..83c9eaf 100644 --- a/src/render/software/TerrainRasterizer.h +++ b/src/render/software/TerrainRasterizer.h @@ -3,12 +3,13 @@ #include "software_global.h" +#include "Rasterizer.h" #include "Vector3.h" namespace paysages { namespace software { -class SOFTWARESHARED_EXPORT TerrainRasterizer +class SOFTWARESHARED_EXPORT TerrainRasterizer: public Rasterizer { public: typedef struct diff --git a/src/render/software/WaterRasterizer.h b/src/render/software/WaterRasterizer.h index 7d08798..031f937 100644 --- a/src/render/software/WaterRasterizer.h +++ b/src/render/software/WaterRasterizer.h @@ -3,10 +3,12 @@ #include "software_global.h" +#include "Rasterizer.h" + namespace paysages { namespace software { -class WaterRasterizer +class WaterRasterizer: public Rasterizer { public: WaterRasterizer(SoftwareRenderer* renderer); diff --git a/src/render/software/software.pro b/src/render/software/software.pro index ec32efa..8fbd61a 100644 --- a/src/render/software/software.pro +++ b/src/render/software/software.pro @@ -37,7 +37,14 @@ SOURCES += SoftwareRenderer.cpp \ RenderArea.cpp \ RayCastingManager.cpp \ NightSky.cpp \ - TerrainRayWalker.cpp + TerrainRayWalker.cpp \ + Canvas.cpp \ + CanvasPortion.cpp \ + CanvasPixel.cpp \ + CanvasFragment.cpp \ + SoftwareCanvasRenderer.cpp \ + Rasterizer.cpp \ + CanvasLiveClient.cpp HEADERS += SoftwareRenderer.h\ software_global.h \ @@ -64,7 +71,14 @@ HEADERS += SoftwareRenderer.h\ RenderArea.h \ RayCastingManager.h \ NightSky.h \ - TerrainRayWalker.h + TerrainRayWalker.h \ + Canvas.h \ + CanvasPortion.h \ + CanvasPixel.h \ + CanvasFragment.h \ + SoftwareCanvasRenderer.h \ + Rasterizer.h \ + CanvasLiveClient.h unix:!symbian { maemo5 { diff --git a/src/render/software/software_global.h b/src/render/software/software_global.h index 180bcca..432f108 100644 --- a/src/render/software/software_global.h +++ b/src/render/software/software_global.h @@ -14,6 +14,7 @@ namespace paysages { namespace software { class SoftwareRenderer; + class SoftwareCanvasRenderer; class RenderArea; class FluidMediumManager; @@ -33,6 +34,7 @@ namespace software { class TexturesRenderer; class WaterRenderer; + class Rasterizer; class SkyRasterizer; class TerrainRasterizer; @@ -44,6 +46,12 @@ namespace software { class NightSky; class TerrainRayWalker; + + class Canvas; + class CanvasPortion; + class CanvasPixel; + class CanvasFragment; + class CanvasLiveClient; } } diff --git a/src/tests/Canvas_Test.cpp b/src/tests/Canvas_Test.cpp new file mode 100644 index 0000000..7ae9551 --- /dev/null +++ b/src/tests/Canvas_Test.cpp @@ -0,0 +1,41 @@ +#include "BaseTestCase.h" + +#include "Canvas.h" +#include "CanvasPortion.h" + +static void checkPortion(Canvas &canvas, int x, int y, int width, int height) +{ + ASSERT_LT(x, canvas.getHorizontalPortionCount()); + ASSERT_LT(y, canvas.getVerticalPortionCount()); + + CanvasPortion* portion = canvas.at(x, y); + + EXPECT_EQ(width, portion->getWidth()); + EXPECT_EQ(height, portion->getHeight()); +} + +TEST(Canvas, SizingAndCutting) +{ + Canvas canvas; + + canvas.setSize(200, 100); + EXPECT_EQ(200, canvas.getWidth()); + EXPECT_EQ(100, canvas.getHeight()); + EXPECT_EQ(200, canvas.getPreviewWidth()); + EXPECT_EQ(100, canvas.getPreviewHeight()); + ASSERT_EQ(1, canvas.getHorizontalPortionCount()); + ASSERT_EQ(1, canvas.getVerticalPortionCount()); + checkPortion(canvas, 0, 0, 200, 100); + + canvas.setSize(600, 501); + EXPECT_EQ(600, canvas.getWidth()); + EXPECT_EQ(501, canvas.getHeight()); + EXPECT_EQ(600, canvas.getPreviewWidth()); + EXPECT_EQ(501, canvas.getPreviewHeight()); + ASSERT_EQ(2, canvas.getHorizontalPortionCount()); + ASSERT_EQ(2, canvas.getVerticalPortionCount()); + checkPortion(canvas, 0, 0, 300, 250); + checkPortion(canvas, 0, 1, 300, 251); + checkPortion(canvas, 1, 0, 300, 250); + checkPortion(canvas, 1, 1, 300, 251); +} diff --git a/src/tests/tests.pro b/src/tests/tests.pro index 378272f..3dd95e6 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -19,7 +19,8 @@ SOURCES += main.cpp \ Clouds_Test.cpp \ FluidMediumManager_Test.cpp \ VertexArray_Test.cpp \ - FractalNoise_Test.cpp + FractalNoise_Test.cpp \ + Canvas_Test.cpp HEADERS += \ BaseTestCase.h From 8099361cc918f67baa357e1b5da59a1925330005 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Tue, 10 Jun 2014 15:13:16 +0200 Subject: [PATCH 02/29] WIP on new canvas system --- src/interface/desktop/WidgetPreviewCanvas.cpp | 6 +- src/render/software/Canvas.cpp | 14 ++- src/render/software/Canvas.h | 7 +- src/render/software/CanvasFragment.cpp | 6 + src/render/software/CanvasFragment.h | 17 +++ src/render/software/CanvasPixel.cpp | 83 ++++++++++++++ src/render/software/CanvasPixel.h | 14 +++ src/render/software/CanvasPortion.cpp | 52 ++++++++- src/render/software/CanvasPortion.h | 23 ++-- src/render/software/CanvasPreview.cpp | 22 ++++ src/render/software/CanvasPreview.h | 44 ++++++++ src/render/software/software.pro | 6 +- src/render/software/software_global.h | 1 + src/tests/CanvasPortion_Test.cpp | 104 ++++++++++++++++++ src/tests/Canvas_Test.cpp | 9 +- src/tests/tests.pro | 3 +- 16 files changed, 381 insertions(+), 30 deletions(-) create mode 100644 src/render/software/CanvasPreview.cpp create mode 100644 src/render/software/CanvasPreview.h create mode 100644 src/tests/CanvasPortion_Test.cpp diff --git a/src/interface/desktop/WidgetPreviewCanvas.cpp b/src/interface/desktop/WidgetPreviewCanvas.cpp index 3c104e2..ade72a8 100644 --- a/src/interface/desktop/WidgetPreviewCanvas.cpp +++ b/src/interface/desktop/WidgetPreviewCanvas.cpp @@ -1,6 +1,7 @@ #include "WidgetPreviewCanvas.h" #include "Canvas.h" +#include "CanvasPreview.h" WidgetPreviewCanvas::WidgetPreviewCanvas(QWidget *parent) : QWidget(parent), canvas(NULL) @@ -31,10 +32,11 @@ void WidgetPreviewCanvas::canvasPainted(int x, int y, const Color &col) void WidgetPreviewCanvas::timerEvent(QTimerEvent *) { // Refresh the view + CanvasPreview *preview = canvas->getPreview(); if (canvas) { - int width = canvas->getPreviewWidth(); - int height = canvas->getPreviewHeight(); + int width = preview->getWidth(); + int height = preview->getHeight(); if (QSize(width, height) != this->size()) { diff --git a/src/render/software/Canvas.cpp b/src/render/software/Canvas.cpp index 09a890e..ee82e3f 100644 --- a/src/render/software/Canvas.cpp +++ b/src/render/software/Canvas.cpp @@ -1,17 +1,19 @@ #include "Canvas.h" -#include "CanvasPortion.h" #include +#include "CanvasPortion.h" +#include "CanvasPreview.h" + Canvas::Canvas() { horizontal_portion_count = 1; vertical_portion_count = 1; width = 1; height = 1; - preview_width = 1; - preview_height = 1; portions.push_back(new CanvasPortion()); + + preview = new CanvasPreview(); } Canvas::~Canvas() @@ -20,6 +22,7 @@ Canvas::~Canvas() { delete portion; } + delete preview; } void Canvas::setSize(int width, int height) @@ -63,8 +66,9 @@ void Canvas::setSize(int width, int height) this->width = width; this->height = height; - this->preview_width = width; - this->preview_height = height; + + // TODO Smaller preview + preview->setSize(width, height, width, height); } CanvasPortion *Canvas::at(int x, int y) const diff --git a/src/render/software/Canvas.h b/src/render/software/Canvas.h index 4934e06..edd8e80 100644 --- a/src/render/software/Canvas.h +++ b/src/render/software/Canvas.h @@ -27,8 +27,7 @@ public: inline int getWidth() const {return width;} inline int getHeight() const {return height;} - inline int getPreviewWidth() const {return preview_width;} - inline int getPreviewHeight() const {return preview_height;} + inline CanvasPreview *getPreview() const {return preview;} private: std::vector portions; @@ -36,8 +35,8 @@ private: int vertical_portion_count; int width; int height; - int preview_width; - int preview_height; + + CanvasPreview *preview; }; } diff --git a/src/render/software/CanvasFragment.cpp b/src/render/software/CanvasFragment.cpp index 2d105dd..c5a5564 100644 --- a/src/render/software/CanvasFragment.cpp +++ b/src/render/software/CanvasFragment.cpp @@ -3,3 +3,9 @@ CanvasFragment::CanvasFragment() { } + +CanvasFragment::CanvasFragment(double z, const Vector3 &location, int client, bool opaque): + z(z), location(location), client(client), opaque(opaque) +{ + color = COLOR_BLACK; +} diff --git a/src/render/software/CanvasFragment.h b/src/render/software/CanvasFragment.h index f1b3b5a..7175add 100644 --- a/src/render/software/CanvasFragment.h +++ b/src/render/software/CanvasFragment.h @@ -3,6 +3,9 @@ #include "software_global.h" +#include "Color.h" +#include "Vector3.h" + namespace paysages { namespace software { @@ -13,6 +16,20 @@ class SOFTWARESHARED_EXPORT CanvasFragment { public: CanvasFragment(); + CanvasFragment(double z, const Vector3 &location, int client=0, bool opaque=true); + + inline bool getOpaque() const {return opaque;} + inline double getZ() const {return z;} + inline const Vector3 &getLocation() const {return location;} + inline int getClient() const {return client;} + inline const Color &getColor() const {return color;} + +private: + bool opaque; + double z; + Vector3 location; + int client; + Color color; }; } diff --git a/src/render/software/CanvasPixel.cpp b/src/render/software/CanvasPixel.cpp index c7c1b5c..7cc4cf6 100644 --- a/src/render/software/CanvasPixel.cpp +++ b/src/render/software/CanvasPixel.cpp @@ -1,5 +1,88 @@ #include "CanvasPixel.h" +#include + CanvasPixel::CanvasPixel() { + count = 0; +} + +const CanvasFragment *CanvasPixel::getFrontFragment() const +{ + if (count == 0) + { + return NULL; + } + else + { + return fragments + (count - 1); + } +} + +void CanvasPixel::reset() +{ + count = 0; +} + +void CanvasPixel::pushFragment(const CanvasFragment &fragment) +{ + if (count == 0) + { + fragments[0] = fragment; + count = 1; + } + else + { + if (fragments[0].getOpaque() and fragment.getZ() > fragments[0].getZ()) + { + // behind opaque fragment, don't bother + return; + } + + // find expected position + int i = 0; + while (i < count and fragment.getZ() < fragments[i].getZ()) + { + i++; + } + + if (fragment.getOpaque()) + { + // Discard fragments masked by the incoming opaque one + if (i < count) + { + memmove(fragments + 1, fragments + i, sizeof(CanvasFragment) * (count - i)); + count -= i; + } + else + { + count = 1; + } + fragments[0] = fragment; + } + else if (i < count) + { + // Need to make room for the incoming fragment + if (count < MAX_FRAGMENT_COUNT) + { + memmove(fragments + i + 1, fragments + i, sizeof(CanvasFragment) * (count - i)); + fragments[i] = fragment; + count++; + } + } + else + { + if (count == MAX_FRAGMENT_COUNT) + { + // Replace nearest fragment + fragments[count - 1] = fragment; + } + else + { + // Append + fragments[count] = fragment; + count++; + } + } + } } diff --git a/src/render/software/CanvasPixel.h b/src/render/software/CanvasPixel.h index 4a00c62..da32e3f 100644 --- a/src/render/software/CanvasPixel.h +++ b/src/render/software/CanvasPixel.h @@ -3,6 +3,10 @@ #include "software_global.h" +#include "CanvasFragment.h" + +const int MAX_FRAGMENT_COUNT = 7; + namespace paysages { namespace software { @@ -15,6 +19,16 @@ class SOFTWARESHARED_EXPORT CanvasPixel { public: CanvasPixel(); + + inline int getFragmentCount() const {return count;} + const CanvasFragment *getFrontFragment() const; + + void reset(); + void pushFragment(const CanvasFragment &fragment); + +private: + int count; + CanvasFragment fragments[MAX_FRAGMENT_COUNT]; }; } diff --git a/src/render/software/CanvasPortion.cpp b/src/render/software/CanvasPortion.cpp index c44e15f..e017592 100644 --- a/src/render/software/CanvasPortion.cpp +++ b/src/render/software/CanvasPortion.cpp @@ -1,12 +1,62 @@ #include "CanvasPortion.h" +#include + +#include "CanvasPixel.h" + +#define CHECK_COORDINATES() assert(x >= 0); \ + assert(x < width); \ + assert(y >= 0); \ + assert(y < height) + CanvasPortion::CanvasPortion() { + width = 1; + height = 1; + pixels = new CanvasPixel[1]; +} + +CanvasPortion::~CanvasPortion() +{ + delete[] pixels; +} + +int CanvasPortion::getFragmentCount(int x, int y) const +{ + CHECK_COORDINATES(); + + return pixels[y * width + x].getFragmentCount(); +} + +const CanvasFragment *CanvasPortion::getFrontFragment(int x, int y) const +{ + CHECK_COORDINATES(); + + return pixels[y * width + x].getFrontFragment(); +} + +void CanvasPortion::clear() +{ + int n = width * height; + for (int i = 0; i < n; i++) + { + pixels[i].reset(); + } } void CanvasPortion::setSize(int width, int height) { this->width = width; this->height = height; - // TODO Resize and clear pixels + + delete[] pixels; + pixels = new CanvasPixel[width * height]; +} + +void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment) +{ + CHECK_COORDINATES(); + + CanvasPixel &pixel = pixels[y * width + x]; + pixel.pushFragment(fragment); } diff --git a/src/render/software/CanvasPortion.h b/src/render/software/CanvasPortion.h index 274d645..e735b7f 100644 --- a/src/render/software/CanvasPortion.h +++ b/src/render/software/CanvasPortion.h @@ -6,12 +6,6 @@ namespace paysages { namespace software { -typedef struct { - double red; - double green; - double blue; -} CanvasPreviewPixel; - /** * @brief Rectangular portion of a Canvas. * @@ -21,20 +15,27 @@ class SOFTWARESHARED_EXPORT CanvasPortion { public: CanvasPortion(); + ~CanvasPortion(); inline int getWidth() const {return width;} inline int getHeight() const {return height;} + int getFragmentCount(int x, int y) const; + const CanvasFragment *getFrontFragment(int x, int y) const; + void clear(); void setSize(int width, int height); + /** + * @brief Add a fragment to the pixel located at (x, y). + * + * Checking x and y coordinates to be in the canvas portion should be done before this call. + */ + void pushFragment(int x, int y, const CanvasFragment &fragment); + private: int width; int height; - std::vector *pixels; - - int preview_width; - int preview_height; - std::vector *preview_pixels; + CanvasPixel *pixels; }; } diff --git a/src/render/software/CanvasPreview.cpp b/src/render/software/CanvasPreview.cpp new file mode 100644 index 0000000..3a7a427 --- /dev/null +++ b/src/render/software/CanvasPreview.cpp @@ -0,0 +1,22 @@ +#include "CanvasPreview.h" + +CanvasPreview::CanvasPreview() +{ + width = 1; + height = 1; + pixels = new CanvasPreviewPixel[1]; +} + +CanvasPreview::~CanvasPreview() +{ + delete [] pixels; +} + +void CanvasPreview::setSize(int real_width, int real_height, int preview_width, int preview_height) +{ + delete [] pixels; + pixels = new CanvasPreviewPixel[preview_width * preview_height]; + + width = preview_width; + height = preview_height; +} diff --git a/src/render/software/CanvasPreview.h b/src/render/software/CanvasPreview.h new file mode 100644 index 0000000..f10e2dc --- /dev/null +++ b/src/render/software/CanvasPreview.h @@ -0,0 +1,44 @@ +#ifndef CANVASPREVIEW_H +#define CANVASPREVIEW_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +typedef struct { + double red; + double green; + double blue; +} CanvasPreviewPixel; + +/** + * @brief Smaller preview of a Canvas rendering, that can be watched live. + */ +class SOFTWARESHARED_EXPORT CanvasPreview +{ +public: + CanvasPreview(); + ~CanvasPreview(); + + inline int getWidth() const {return width;} + inline int getHeight() const {return height;} + + void setSize(int real_width, int real_height, int preview_width, int preview_height); + void reset(); + + void initLive(CanvasLiveClient &client); + void updateLive(CanvasLiveClient &client); + + void pushPixel(int real_x, int real_y, Color old_color, Color new_color); + +private: + CanvasPreviewPixel *pixels; + int width; + int height; +}; + +} +} + +#endif // CANVASPREVIEW_H diff --git a/src/render/software/software.pro b/src/render/software/software.pro index 8fbd61a..444a395 100644 --- a/src/render/software/software.pro +++ b/src/render/software/software.pro @@ -44,7 +44,8 @@ SOURCES += SoftwareRenderer.cpp \ CanvasFragment.cpp \ SoftwareCanvasRenderer.cpp \ Rasterizer.cpp \ - CanvasLiveClient.cpp + CanvasLiveClient.cpp \ + CanvasPreview.cpp HEADERS += SoftwareRenderer.h\ software_global.h \ @@ -78,7 +79,8 @@ HEADERS += SoftwareRenderer.h\ CanvasFragment.h \ SoftwareCanvasRenderer.h \ Rasterizer.h \ - CanvasLiveClient.h + CanvasLiveClient.h \ + CanvasPreview.h unix:!symbian { maemo5 { diff --git a/src/render/software/software_global.h b/src/render/software/software_global.h index 432f108..419a378 100644 --- a/src/render/software/software_global.h +++ b/src/render/software/software_global.h @@ -52,6 +52,7 @@ namespace software { class CanvasPixel; class CanvasFragment; class CanvasLiveClient; + class CanvasPreview; } } diff --git a/src/tests/CanvasPortion_Test.cpp b/src/tests/CanvasPortion_Test.cpp new file mode 100644 index 0000000..643d11e --- /dev/null +++ b/src/tests/CanvasPortion_Test.cpp @@ -0,0 +1,104 @@ +#include "BaseTestCase.h" + +#include "CanvasPortion.h" +#include "CanvasFragment.h" + +TEST(CanvasPortion, setSize) +{ + CanvasPortion portion; + + portion.setSize(150, 30); + + EXPECT_EQ(150, portion.getWidth()); + EXPECT_EQ(30, portion.getHeight()); +} + +TEST(CanvasPortion, pushFragment) +{ + CanvasPortion portion; + CanvasFragment pushed; + const CanvasFragment *got; + int count; + + portion.setSize(50, 50); + portion.pushFragment(10, 15, pushed); + + count = portion.getFragmentCount(10, 14); + ASSERT_EQ(0, count); + got = portion.getFrontFragment(10, 14); + ASSERT_FALSE(got); + + count = portion.getFragmentCount(10, 15); + ASSERT_EQ(1, count); + got = portion.getFrontFragment(10, 15); + ASSERT_TRUE(got); +} + +TEST(CanvasPortion, pushFragment_opaque) +{ + CanvasPortion portion; + CanvasFragment pushed; + + portion.setSize(10, 10); + + pushed = CanvasFragment(2.0, VECTOR_ZERO, 0); + portion.pushFragment(2, 2, pushed); + + ASSERT_EQ(1, portion.getFragmentCount(2, 2)); + EXPECT_DOUBLE_EQ(2.0, portion.getFrontFragment(2, 2)->getZ()); + + pushed = CanvasFragment(4.0, VECTOR_ZERO, 0); + portion.pushFragment(2, 2, pushed); + + ASSERT_EQ(1, portion.getFragmentCount(2, 2)); + EXPECT_DOUBLE_EQ(2.0, portion.getFrontFragment(2, 2)->getZ()); + + pushed = CanvasFragment(1.0, VECTOR_ZERO, 0); + portion.pushFragment(2, 2, pushed); + + ASSERT_EQ(1, portion.getFragmentCount(2, 2)); + EXPECT_DOUBLE_EQ(1.0, portion.getFrontFragment(2, 2)->getZ()); +} + +TEST(CanvasPortion, pushFragment_transparent) +{ + CanvasPortion portion; + CanvasFragment pushed; + + portion.setSize(10, 10); + + pushed = CanvasFragment(4.0, VECTOR_ZERO, 0, false); + portion.pushFragment(2, 2, pushed); + + ASSERT_EQ(1, portion.getFragmentCount(2, 2)); + EXPECT_DOUBLE_EQ(4.0, portion.getFrontFragment(2, 2)->getZ()); + + pushed = CanvasFragment(3.0, VECTOR_ZERO, 0, true); + portion.pushFragment(2, 2, pushed); + + ASSERT_EQ(1, portion.getFragmentCount(2, 2)); + EXPECT_DOUBLE_EQ(3.0, portion.getFrontFragment(2, 2)->getZ()); + + pushed = CanvasFragment(2.0, VECTOR_ZERO, 0, false); + portion.pushFragment(2, 2, pushed); + + ASSERT_EQ(2, portion.getFragmentCount(2, 2)); + EXPECT_DOUBLE_EQ(2.0, portion.getFrontFragment(2, 2)->getZ()); +} + +TEST(CanvasPortion, clear) +{ + CanvasPortion portion; + CanvasFragment fragment; + + portion.setSize(10, 10); + portion.pushFragment(5, 5, fragment); + + EXPECT_EQ(0, portion.getFragmentCount(4, 5)); + EXPECT_EQ(1, portion.getFragmentCount(5, 5)); + + portion.clear(); + + EXPECT_EQ(0, portion.getFragmentCount(4, 5)); + EXPECT_EQ(0, portion.getFragmentCount(5, 5)); +} diff --git a/src/tests/Canvas_Test.cpp b/src/tests/Canvas_Test.cpp index 7ae9551..39edf16 100644 --- a/src/tests/Canvas_Test.cpp +++ b/src/tests/Canvas_Test.cpp @@ -2,6 +2,7 @@ #include "Canvas.h" #include "CanvasPortion.h" +#include "CanvasPreview.h" static void checkPortion(Canvas &canvas, int x, int y, int width, int height) { @@ -21,8 +22,8 @@ TEST(Canvas, SizingAndCutting) canvas.setSize(200, 100); EXPECT_EQ(200, canvas.getWidth()); EXPECT_EQ(100, canvas.getHeight()); - EXPECT_EQ(200, canvas.getPreviewWidth()); - EXPECT_EQ(100, canvas.getPreviewHeight()); + EXPECT_EQ(200, canvas.getPreview()->getWidth()); + EXPECT_EQ(100, canvas.getPreview()->getHeight()); ASSERT_EQ(1, canvas.getHorizontalPortionCount()); ASSERT_EQ(1, canvas.getVerticalPortionCount()); checkPortion(canvas, 0, 0, 200, 100); @@ -30,8 +31,8 @@ TEST(Canvas, SizingAndCutting) canvas.setSize(600, 501); EXPECT_EQ(600, canvas.getWidth()); EXPECT_EQ(501, canvas.getHeight()); - EXPECT_EQ(600, canvas.getPreviewWidth()); - EXPECT_EQ(501, canvas.getPreviewHeight()); + EXPECT_EQ(600, canvas.getPreview()->getWidth()); + EXPECT_EQ(501, canvas.getPreview()->getHeight()); ASSERT_EQ(2, canvas.getHorizontalPortionCount()); ASSERT_EQ(2, canvas.getVerticalPortionCount()); checkPortion(canvas, 0, 0, 300, 250); diff --git a/src/tests/tests.pro b/src/tests/tests.pro index 3dd95e6..2efe000 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -20,7 +20,8 @@ SOURCES += main.cpp \ FluidMediumManager_Test.cpp \ VertexArray_Test.cpp \ FractalNoise_Test.cpp \ - Canvas_Test.cpp + Canvas_Test.cpp \ + CanvasPortion_Test.cpp HEADERS += \ BaseTestCase.h From cf58bea1b7e3fb93b13751f04c73c60f3a7db743 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Thu, 12 Jun 2014 17:45:59 +0200 Subject: [PATCH 03/29] WIP on new canvas system --- src/interface/desktop/WidgetPreviewCanvas.cpp | 45 ++- src/interface/desktop/WidgetPreviewCanvas.h | 5 + .../desktop/common/freeformhelper.cpp | 5 +- src/interface/desktop/dialogrender.cpp | 24 +- src/interface/desktop/dialogrender.h | 3 +- src/interface/desktop/formrender.cpp | 8 +- src/interface/desktop/formrender.h | 2 +- src/render/software/Canvas.cpp | 8 +- src/render/software/CanvasFragment.cpp | 7 +- src/render/software/CanvasFragment.h | 2 + src/render/software/CanvasPixel.cpp | 13 + src/render/software/CanvasPixel.h | 3 + src/render/software/CanvasPortion.cpp | 11 +- src/render/software/CanvasPortion.h | 3 +- src/render/software/CanvasPreview.cpp | 119 ++++++- src/render/software/CanvasPreview.h | 24 +- src/render/software/Rasterizer.cpp | 334 +++++++++++++++++- src/render/software/Rasterizer.h | 29 +- src/render/software/SkyRasterizer.cpp | 60 +++- src/render/software/SkyRasterizer.h | 7 +- .../software/SoftwareCanvasRenderer.cpp | 28 +- src/render/software/SoftwareCanvasRenderer.h | 13 +- src/render/software/SoftwareRenderer.cpp | 17 +- src/render/software/SoftwareRenderer.h | 5 - src/render/software/TerrainRasterizer.cpp | 6 +- src/render/software/TerrainRasterizer.h | 5 +- src/render/software/WaterRasterizer.cpp | 6 +- src/render/software/WaterRasterizer.h | 7 +- 28 files changed, 700 insertions(+), 99 deletions(-) diff --git a/src/interface/desktop/WidgetPreviewCanvas.cpp b/src/interface/desktop/WidgetPreviewCanvas.cpp index ade72a8..47d989a 100644 --- a/src/interface/desktop/WidgetPreviewCanvas.cpp +++ b/src/interface/desktop/WidgetPreviewCanvas.cpp @@ -1,48 +1,69 @@ #include "WidgetPreviewCanvas.h" +#include "tools.h" #include "Canvas.h" #include "CanvasPreview.h" +#include + WidgetPreviewCanvas::WidgetPreviewCanvas(QWidget *parent) : QWidget(parent), canvas(NULL) { + pixbuf = new QImage(); + inited = false; + startTimer(1000); } +WidgetPreviewCanvas::~WidgetPreviewCanvas() +{ + delete pixbuf; +} + void WidgetPreviewCanvas::setCanvas(const Canvas *canvas) { this->canvas = canvas; } +void WidgetPreviewCanvas::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + painter.drawImage(0, 0, *pixbuf); +} + void WidgetPreviewCanvas::canvasResized(int width, int height) { - // TODO + if (QSize(width, height) != this->size()) + { + setMaximumSize(width, height); + setMinimumSize(width, height); + resize(width, height); + + delete pixbuf; + pixbuf = new QImage(width, height, QImage::Format_ARGB32); + } } void WidgetPreviewCanvas::canvasCleared(const Color &col) { - // TODO + pixbuf->fill(colorToQColor(col)); } void WidgetPreviewCanvas::canvasPainted(int x, int y, const Color &col) { - // TODO + pixbuf->setPixel(x, pixbuf->height() - 1 - y, colorToQColor(col).rgb()); } void WidgetPreviewCanvas::timerEvent(QTimerEvent *) { - // Refresh the view - CanvasPreview *preview = canvas->getPreview(); if (canvas) { - int width = preview->getWidth(); - int height = preview->getHeight(); - - if (QSize(width, height) != this->size()) + if (!inited) { - setMaximumSize(width, height); - setMinimumSize(width, height); - resize(width, height); + canvas->getPreview()->initLive(this); + inited = true; } + + canvas->getPreview()->updateLive(this); } } diff --git a/src/interface/desktop/WidgetPreviewCanvas.h b/src/interface/desktop/WidgetPreviewCanvas.h index 6aacafe..a862fc9 100644 --- a/src/interface/desktop/WidgetPreviewCanvas.h +++ b/src/interface/desktop/WidgetPreviewCanvas.h @@ -17,12 +17,15 @@ class WidgetPreviewCanvas : public QWidget, public CanvasLiveClient Q_OBJECT public: explicit WidgetPreviewCanvas(QWidget *parent = 0); + virtual ~WidgetPreviewCanvas(); /*! * \brief Set the canvas to watch and display, null to stop watching. */ void setCanvas(const Canvas *canvas); + virtual void paintEvent(QPaintEvent* event); + protected: virtual void canvasResized(int width, int height); virtual void canvasCleared(const Color &col); @@ -30,7 +33,9 @@ protected: virtual void timerEvent(QTimerEvent *event); private: + QImage* pixbuf; const Canvas *canvas; + bool inited; }; } diff --git a/src/interface/desktop/common/freeformhelper.cpp b/src/interface/desktop/common/freeformhelper.cpp index 7a927f8..433867e 100644 --- a/src/interface/desktop/common/freeformhelper.cpp +++ b/src/interface/desktop/common/freeformhelper.cpp @@ -14,7 +14,7 @@ #include "dialogexplorer.h" #include "DesktopScenery.h" #include "BasePreview.h" -#include "SoftwareRenderer.h" +#include "SoftwareCanvasRenderer.h" #include "CameraDefinition.h" #include "tools.h" @@ -246,7 +246,8 @@ void FreeFormHelper::processExploreClicked() void FreeFormHelper::processRenderClicked() { - SoftwareRenderer renderer(DesktopScenery::getCurrent()); + SoftwareCanvasRenderer renderer; + renderer.setScenery(DesktopScenery::getCurrent()); emit needAlterRenderer(&renderer); diff --git a/src/interface/desktop/dialogrender.cpp b/src/interface/desktop/dialogrender.cpp index 59b6b70..ceec5b4 100644 --- a/src/interface/desktop/dialogrender.cpp +++ b/src/interface/desktop/dialogrender.cpp @@ -51,7 +51,7 @@ static void _renderUpdate(double progress) class RenderThread:public QThread { public: - RenderThread(DialogRender* dialog, SoftwareRenderer* renderer, RenderArea::RenderParams params):QThread() + RenderThread(DialogRender* dialog, SoftwareCanvasRenderer* renderer, RenderArea::RenderParams params):QThread() { _dialog = dialog; _renderer = renderer; @@ -59,12 +59,13 @@ public: } void run() { + _renderer->render(); _renderer->start(_params); _dialog->tellRenderEnded(); } private: DialogRender* _dialog; - SoftwareRenderer* _renderer; + SoftwareCanvasRenderer* _renderer; RenderArea::RenderParams _params; }; @@ -86,14 +87,14 @@ public: } }; -DialogRender::DialogRender(QWidget *parent, SoftwareRenderer* renderer): +DialogRender::DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer): QDialog(parent, Qt::WindowTitleHint | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint) { pixbuf_lock = new QMutex(); pixbuf = new QImage(1, 1, QImage::Format_ARGB32); _current_dialog = this; _render_thread = NULL; - _renderer = renderer; + canvas_renderer = renderer; setModal(true); setWindowTitle(tr("Paysages 3D - Render")); @@ -105,7 +106,6 @@ DialogRender::DialogRender(QWidget *parent, SoftwareRenderer* renderer): _scroll->setWidget(area); layout()->addWidget(_scroll); - canvas_renderer = new SoftwareCanvasRenderer(); canvas_preview = new WidgetPreviewCanvas(this); canvas_preview->setCanvas(canvas_renderer->getCanvas()); layout()->addWidget(canvas_preview); @@ -159,7 +159,7 @@ DialogRender::~DialogRender() { if (_render_thread) { - _renderer->interrupt(); + canvas_renderer->interrupt(); _render_thread->wait(); delete _render_thread; @@ -190,9 +190,9 @@ void DialogRender::startRender(RenderArea::RenderParams params) canvas_renderer->setSize(params.width, params.height, params.antialias); applyRenderSize(params.width, params.height); - _renderer->setPreviewCallbacks(_renderStart, _renderDraw, _renderUpdate); + canvas_renderer->setPreviewCallbacks(_renderStart, _renderDraw, _renderUpdate); - _render_thread = new RenderThread(this, _renderer, params); + _render_thread = new RenderThread(this, canvas_renderer, params); _render_thread->start(); exec(); @@ -218,7 +218,7 @@ void DialogRender::saveRender() filepath = filepath.append(".png"); } std::string filepathstr = filepath.toStdString(); - if (_renderer->render_area->saveToFile((char*)filepathstr.c_str())) + if (canvas_renderer->render_area->saveToFile((char*)filepathstr.c_str())) { QMessageBox::information(this, "Message", QString(tr("The picture %1 has been saved.")).arg(filepath)); } @@ -232,13 +232,13 @@ void DialogRender::saveRender() void DialogRender::toneMappingChanged() { ColorProfile profile((ColorProfile::ToneMappingOperator)_tonemapping_control->currentIndex(), ((double)_exposure_control->value()) * 0.01); - _renderer->render_area->setToneMapping(profile); + canvas_renderer->render_area->setToneMapping(profile); } void DialogRender::loadLastRender() { - applyRenderSize(_renderer->render_width, _renderer->render_height); - _renderer->setPreviewCallbacks(_renderStart, _renderDraw, _renderUpdate); + applyRenderSize(canvas_renderer->render_width, canvas_renderer->render_height); + canvas_renderer->setPreviewCallbacks(_renderStart, _renderDraw, _renderUpdate); renderEnded(); toneMappingChanged(); diff --git a/src/interface/desktop/dialogrender.h b/src/interface/desktop/dialogrender.h index 62c6aa3..3ea599a 100644 --- a/src/interface/desktop/dialogrender.h +++ b/src/interface/desktop/dialogrender.h @@ -19,7 +19,7 @@ class DialogRender : public QDialog { Q_OBJECT public: - explicit DialogRender(QWidget *parent, SoftwareRenderer* renderer); + explicit DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer); ~DialogRender(); void tellRenderSize(int width, int height); @@ -56,7 +56,6 @@ private: QPushButton* _save_button; QThread* _render_thread; QLabel* _timer; - SoftwareRenderer* _renderer; QProgressBar* _progress; time_t _started; }; diff --git a/src/interface/desktop/formrender.cpp b/src/interface/desktop/formrender.cpp index 9a24dab..26f58a0 100644 --- a/src/interface/desktop/formrender.cpp +++ b/src/interface/desktop/formrender.cpp @@ -7,7 +7,7 @@ #include "tools.h" #include "DesktopScenery.h" #include "PackStream.h" -#include "SoftwareRenderer.h" +#include "SoftwareCanvasRenderer.h" #include "BasePreview.h" #include "CloudsDefinition.h" #include "CameraDefinition.h" @@ -103,7 +103,8 @@ void FormRender::startQuickRender() { delete _renderer; } - _renderer = new SoftwareRenderer(DesktopScenery::getCurrent()); + _renderer = new SoftwareCanvasRenderer(); + _renderer->setScenery(DesktopScenery::getCurrent()); _renderer_inited = true; DialogRender* dialog = new DialogRender(this, _renderer); @@ -119,7 +120,8 @@ void FormRender::startRender() { delete _renderer; } - _renderer = new SoftwareRenderer(DesktopScenery::getCurrent()); + _renderer = new SoftwareCanvasRenderer(); + _renderer->setScenery(DesktopScenery::getCurrent()); _renderer_inited = true; DialogRender* dialog = new DialogRender(this, _renderer); diff --git a/src/interface/desktop/formrender.h b/src/interface/desktop/formrender.h index b555575..9f4afcd 100644 --- a/src/interface/desktop/formrender.h +++ b/src/interface/desktop/formrender.h @@ -31,7 +31,7 @@ protected slots: private: RenderArea::RenderParams _params; CameraDefinition* _camera; - SoftwareRenderer* _renderer; + SoftwareCanvasRenderer* _renderer; bool _renderer_inited; BasePreview* _preview_landscape; Base2dPreviewRenderer* _preview_landscape_renderer; diff --git a/src/render/software/Canvas.cpp b/src/render/software/Canvas.cpp index ee82e3f..809b170 100644 --- a/src/render/software/Canvas.cpp +++ b/src/render/software/Canvas.cpp @@ -13,7 +13,7 @@ Canvas::Canvas() height = 1; portions.push_back(new CanvasPortion()); - preview = new CanvasPreview(); + preview = new CanvasPreview; } Canvas::~Canvas() @@ -27,8 +27,8 @@ Canvas::~Canvas() void Canvas::setSize(int width, int height) { - horizontal_portion_count = 1 + width / 400; - vertical_portion_count = 1 + height / 400; + horizontal_portion_count = 1 + (width - 1) / 400; + vertical_portion_count = 1 + (height - 1) / 400; int portion_width = width / horizontal_portion_count; int portion_height = height / vertical_portion_count; @@ -47,7 +47,7 @@ void Canvas::setSize(int width, int height) done_width = 0; for (int x = 0; x < horizontal_portion_count; x++) { - CanvasPortion *portion = new CanvasPortion(); + CanvasPortion *portion = new CanvasPortion(preview); portion->setSize((x == horizontal_portion_count - 1) ? width - done_width : portion_width, (y == vertical_portion_count - 1) ? height - done_height : portion_height); diff --git a/src/render/software/CanvasFragment.cpp b/src/render/software/CanvasFragment.cpp index c5a5564..7af7b90 100644 --- a/src/render/software/CanvasFragment.cpp +++ b/src/render/software/CanvasFragment.cpp @@ -7,5 +7,10 @@ CanvasFragment::CanvasFragment() CanvasFragment::CanvasFragment(double z, const Vector3 &location, int client, bool opaque): z(z), location(location), client(client), opaque(opaque) { - color = COLOR_BLACK; + color = COLOR_WHITE; +} + +void CanvasFragment::setColor(const Color &col) +{ + color = col; } diff --git a/src/render/software/CanvasFragment.h b/src/render/software/CanvasFragment.h index 7175add..520415c 100644 --- a/src/render/software/CanvasFragment.h +++ b/src/render/software/CanvasFragment.h @@ -18,6 +18,8 @@ public: CanvasFragment(); CanvasFragment(double z, const Vector3 &location, int client=0, bool opaque=true); + void setColor(const Color &col); + inline bool getOpaque() const {return opaque;} inline double getZ() const {return z;} inline const Vector3 &getLocation() const {return location;} diff --git a/src/render/software/CanvasPixel.cpp b/src/render/software/CanvasPixel.cpp index 7cc4cf6..b4287ab 100644 --- a/src/render/software/CanvasPixel.cpp +++ b/src/render/software/CanvasPixel.cpp @@ -5,6 +5,7 @@ CanvasPixel::CanvasPixel() { count = 0; + composite = COLOR_BLACK; } const CanvasFragment *CanvasPixel::getFrontFragment() const @@ -85,4 +86,16 @@ void CanvasPixel::pushFragment(const CanvasFragment &fragment) } } } + + updateComposite(); +} + +void CanvasPixel::updateComposite() +{ + Color result(0.0, 0.0, 0.0, 1.0); + for (int i = 0; i < count; i++) + { + result.mask(fragments[i].getColor()); + } + composite = result; } diff --git a/src/render/software/CanvasPixel.h b/src/render/software/CanvasPixel.h index da32e3f..bcbab0a 100644 --- a/src/render/software/CanvasPixel.h +++ b/src/render/software/CanvasPixel.h @@ -21,14 +21,17 @@ public: CanvasPixel(); inline int getFragmentCount() const {return count;} + inline const Color &getComposite() const {return composite;} const CanvasFragment *getFrontFragment() const; void reset(); void pushFragment(const CanvasFragment &fragment); + void updateComposite(); private: int count; CanvasFragment fragments[MAX_FRAGMENT_COUNT]; + Color composite; }; } diff --git a/src/render/software/CanvasPortion.cpp b/src/render/software/CanvasPortion.cpp index e017592..7b1438f 100644 --- a/src/render/software/CanvasPortion.cpp +++ b/src/render/software/CanvasPortion.cpp @@ -3,13 +3,15 @@ #include #include "CanvasPixel.h" +#include "CanvasPreview.h" #define CHECK_COORDINATES() assert(x >= 0); \ assert(x < width); \ assert(y >= 0); \ assert(y < height) -CanvasPortion::CanvasPortion() +CanvasPortion::CanvasPortion(CanvasPreview* preview): + preview(preview) { width = 1; height = 1; @@ -58,5 +60,12 @@ void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment) CHECK_COORDINATES(); CanvasPixel &pixel = pixels[y * width + x]; + Color old_color = pixel.getComposite(); + pixel.pushFragment(fragment); + + if (preview) + { + preview->pushPixel(x, y, old_color, pixel.getComposite()); + } } diff --git a/src/render/software/CanvasPortion.h b/src/render/software/CanvasPortion.h index e735b7f..85be35e 100644 --- a/src/render/software/CanvasPortion.h +++ b/src/render/software/CanvasPortion.h @@ -14,7 +14,7 @@ namespace software { class SOFTWARESHARED_EXPORT CanvasPortion { public: - CanvasPortion(); + CanvasPortion(CanvasPreview* preview=NULL); ~CanvasPortion(); inline int getWidth() const {return width;} @@ -36,6 +36,7 @@ private: int width; int height; CanvasPixel *pixels; + CanvasPreview* preview; }; } diff --git a/src/render/software/CanvasPreview.cpp b/src/render/software/CanvasPreview.cpp index 3a7a427..61b63ef 100644 --- a/src/render/software/CanvasPreview.cpp +++ b/src/render/software/CanvasPreview.cpp @@ -1,22 +1,137 @@ #include "CanvasPreview.h" +#include "Color.h" +#include "CanvasLiveClient.h" +#include "Mutex.h" + +#include + CanvasPreview::CanvasPreview() { width = 1; height = 1; - pixels = new CanvasPreviewPixel[1]; + pixels = new Color[1]; + + dirty_left = 1; + dirty_right = -1; + dirty_down = 1; + dirty_up = -1; + + lock = new Mutex(); } CanvasPreview::~CanvasPreview() { delete [] pixels; + delete lock; } void CanvasPreview::setSize(int real_width, int real_height, int preview_width, int preview_height) { + lock->acquire(); + delete [] pixels; - pixels = new CanvasPreviewPixel[preview_width * preview_height]; + pixels = new Color[preview_width * preview_height]; width = preview_width; height = preview_height; + + dirty_left = width; + dirty_right = -1; + dirty_down = height; + dirty_up = -1; + + lock->release(); + + reset(); +} + +void CanvasPreview::reset() +{ + lock->acquire(); + + int n = width * height; + for (int i = 0; i < n; i++) + { + pixels[i] = COLOR_BLACK; + } + + lock->release(); +} + +void CanvasPreview::initLive(CanvasLiveClient *client) +{ + client->canvasResized(width, height); + client->canvasCleared(COLOR_BLACK); + + setAllDirty(); +} + +void CanvasPreview::updateLive(CanvasLiveClient *client) +{ + int x, y; + + lock->acquire(); + + for (y = dirty_down; y <= dirty_up; y++) + { + for (x = dirty_left; x <= dirty_right; x++) + { + client->canvasPainted(x, y, pixels[y * width + x]); + } + } + + dirty_left = width; + dirty_right = -1; + dirty_down = height; + dirty_up = -1; + + lock->release(); +} + +void CanvasPreview::pushPixel(int real_x, int real_y, const Color &old_color, const Color &new_color) +{ + lock->acquire(); + + // TODO Assert-check and transform coordinates + int x = real_x; + int y = real_y; + double fact = 1.0; + + Color* pixel = pixels + (real_y * width + real_x); + pixel->r = pixel->r - old_color.r * fact + new_color.r * fact; + pixel->g = pixel->g - old_color.g * fact + new_color.g * fact; + pixel->b = pixel->b - old_color.b * fact + new_color.b * fact; + + // Set pixel dirty + if (x < dirty_left) + { + dirty_left = x; + } + if (x > dirty_right) + { + dirty_right = x; + } + if (y < dirty_down) + { + dirty_down = y; + } + if (y > dirty_up) + { + dirty_up = y; + } + + lock->release(); +} + +void CanvasPreview::setAllDirty() +{ + lock->acquire(); + + dirty_left = 0; + dirty_right = width - 1; + dirty_down = 0; + dirty_up = height - 1; + + lock->release(); } diff --git a/src/render/software/CanvasPreview.h b/src/render/software/CanvasPreview.h index f10e2dc..e6607d3 100644 --- a/src/render/software/CanvasPreview.h +++ b/src/render/software/CanvasPreview.h @@ -6,12 +6,6 @@ namespace paysages { namespace software { -typedef struct { - double red; - double green; - double blue; -} CanvasPreviewPixel; - /** * @brief Smaller preview of a Canvas rendering, that can be watched live. */ @@ -27,15 +21,25 @@ public: void setSize(int real_width, int real_height, int preview_width, int preview_height); void reset(); - void initLive(CanvasLiveClient &client); - void updateLive(CanvasLiveClient &client); + void initLive(CanvasLiveClient *client); + void updateLive(CanvasLiveClient *client); - void pushPixel(int real_x, int real_y, Color old_color, Color new_color); + void pushPixel(int real_x, int real_y, const Color &old_color, const Color &new_color); + +protected: + void setAllDirty(); private: - CanvasPreviewPixel *pixels; + Mutex *lock; + + Color *pixels; int width; int height; + + int dirty_left; + int dirty_right; + int dirty_down; + int dirty_up; }; } diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index 2545ba1..f54a8c6 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -1,5 +1,337 @@ #include "Rasterizer.h" -Rasterizer::Rasterizer() +#include "SoftwareRenderer.h" +#include "CameraDefinition.h" +#include "CanvasPortion.h" +#include "CanvasFragment.h" +#include "Vector3.h" + +struct paysages::software::ScanPoint +{ + int x; + int y; + struct { + double x; + double y; + double z; + } pixel; + struct { + double x; + double y; + double z; + } location; + int client; +}; + +struct paysages::software::RenderScanlines +{ + ScanPoint* up; + ScanPoint* down; + int left; + int right; +}; + +Rasterizer::Rasterizer(SoftwareRenderer* renderer, int client_id): + renderer(renderer), client_id(client_id) { } + +Rasterizer::~Rasterizer() +{ +} + +void Rasterizer::pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3) +{ + ScanPoint point1, point2, point3; + double limit_width = (double)(canvas->getWidth() - 1); + double limit_height = (double)(canvas->getHeight() - 1); + + /* Filter if outside screen */ + if (pixel1.z < 1.0 || pixel2.z < 1.0 || pixel3.z < 1.0 || (pixel1.x < 0.0 && pixel2.x < 0.0 && pixel3.x < 0.0) || (pixel1.y < 0.0 && pixel2.y < 0.0 && pixel3.y < 0.0) || (pixel1.x > limit_width && pixel2.x > limit_width && pixel3.x > limit_width) || (pixel1.y > limit_height && pixel2.y > limit_height && pixel3.y > limit_height)) + { + return; + } + + /* Prepare vertices */ + // FIXME Apply canvas portion offset + point1.pixel.x = pixel1.x; + point1.pixel.y = pixel1.y; + point1.pixel.z = pixel1.z; + point1.location.x = location1.x; + point1.location.y = location1.y; + point1.location.z = location1.z; + point1.client = client_id; + + point2.pixel.x = pixel2.x; + point2.pixel.y = pixel2.y; + point2.pixel.z = pixel2.z; + point2.location.x = location2.x; + point2.location.y = location2.y; + point2.location.z = location2.z; + point2.client = client_id; + + point3.pixel.x = pixel3.x; + point3.pixel.y = pixel3.y; + point3.pixel.z = pixel3.z; + point3.location.x = location3.x; + point3.location.y = location3.y; + point3.location.z = location3.z; + point3.client = client_id; + + /* Prepare scanlines */ + // TODO Don't create scanlines for each triangles (one by thread is more appropriate) + RenderScanlines scanlines; + int width = canvas->getWidth(); + scanlines.left = width; + scanlines.right = -1; + scanlines.up = new ScanPoint[width]; + scanlines.down = new ScanPoint[width]; + + /* Render edges in scanlines */ + pushScanLineEdge(canvas, &scanlines, &point1, &point2); + pushScanLineEdge(canvas, &scanlines, &point2, &point3); + pushScanLineEdge(canvas, &scanlines, &point3, &point1); + + /* Commit scanlines to area */ + renderScanLines(canvas, &scanlines); + + /* Free scalines */ + delete[] scanlines.up; + delete[] scanlines.down; +} + +void Rasterizer::pushTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3) +{ + Vector3 p1, p2, p3; + + p1 = getRenderer()->projectPoint(v1); + p2 = getRenderer()->projectPoint(v2); + p3 = getRenderer()->projectPoint(v3); + + pushProjectedTriangle(canvas, p1, p2, p3, v1, v2, v3); +} + +void Rasterizer::pushQuad(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4) +{ + pushTriangle(canvas, v2, v3, v1); + pushTriangle(canvas, v4, v1, v3); +} + +void Rasterizer::pushDisplacedTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3) +{ + Vector3 p1, p2, p3; + + p1 = getRenderer()->projectPoint(v1); + p2 = getRenderer()->projectPoint(v2); + p3 = getRenderer()->projectPoint(v3); + + pushProjectedTriangle(canvas, p1, p2, p3, ov1, ov2, ov3); +} + +void Rasterizer::pushDisplacedQuad(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3, const Vector3 &ov4) +{ + pushDisplacedTriangle(canvas, v2, v3, v1, ov2, ov3, ov1); + pushDisplacedTriangle(canvas, v4, v1, v3, ov4, ov1, ov3); +} + +void Rasterizer::rasterizeToCanvas(CanvasPortion *) +{ +} + +void Rasterizer::scanGetDiff(ScanPoint* v1, ScanPoint* v2, ScanPoint* result) +{ + result->pixel.x = v2->pixel.x - v1->pixel.x; + result->pixel.y = v2->pixel.y - v1->pixel.y; + result->pixel.z = v2->pixel.z - v1->pixel.z; + result->location.x = v2->location.x - v1->location.x; + result->location.y = v2->location.y - v1->location.y; + result->location.z = v2->location.z - v1->location.z; + result->client = v1->client; +} + +void Rasterizer::scanInterpolate(CameraDefinition* camera, ScanPoint* v1, ScanPoint* diff, double value, ScanPoint* result) +{ + Vector3 vec1(v1->pixel.x, v1->pixel.y, v1->pixel.z); + Vector3 vecdiff(diff->pixel.x, diff->pixel.y, diff->pixel.z); + double v1depth = camera->getRealDepth(vec1); + double v2depth = camera->getRealDepth(vec1.add(vecdiff)); + double factor = ((1.0 - value) / v1depth + value / v2depth); + + result->pixel.x = v1->pixel.x + diff->pixel.x * value; + result->pixel.y = v1->pixel.y + diff->pixel.y * value; + result->pixel.z = v1->pixel.z + diff->pixel.z * value; + result->location.x = ((1.0 - value) * (v1->location.x / v1depth) + value * (v1->location.x + diff->location.x) / v2depth) / factor; + result->location.y = ((1.0 - value) * (v1->location.y / v1depth) + value * (v1->location.y + diff->location.y) / v2depth) / factor; + result->location.z = ((1.0 - value) * (v1->location.z / v1depth) + value * (v1->location.z + diff->location.z) / v2depth) / factor; + result->client = v1->client; +} + +void Rasterizer::pushScanPoint(CanvasPortion* canvas, RenderScanlines* scanlines, ScanPoint* point) +{ + point->x = (int)floor(point->pixel.x); + point->y = (int)floor(point->pixel.y); + + if (point->x < 0 || point->x >= canvas->getWidth()) + { + // Point outside scanline range + return; + } + else if (scanlines->right < 0) + { + // First point pushed + scanlines->left = point->x; + scanlines->right = point->x; + scanlines->up[point->x] = *point; + scanlines->down[point->x] = *point; + } + else if (point->x > scanlines->right) + { + // Grow scanlines to right + for (int x = scanlines->right + 1; x < point->x; x++) + { + scanlines->up[x].y = -1; + scanlines->down[x].y = canvas->getHeight(); + } + scanlines->right = point->x; + scanlines->up[point->x] = *point; + scanlines->down[point->x] = *point; + } + else if (point->x < scanlines->left) + { + // Grow scanlines to left + for (int x = point->x + 1; x < scanlines->left; x++) + { + scanlines->up[x].y = -1; + scanlines->down[x].y = canvas->getHeight(); + } + scanlines->left = point->x; + scanlines->up[point->x] = *point; + scanlines->down[point->x] = *point; + } + else + { + // Expand existing scanline + if (point->y > scanlines->up[point->x].y) + { + scanlines->up[point->x] = *point; + } + if (point->y < scanlines->down[point->x].y) + { + scanlines->down[point->x] = *point; + } + } +} + +void Rasterizer::pushScanLineEdge(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point1, ScanPoint *point2) +{ + double dx, fx; + ScanPoint diff, point; + int startx = lround(point1->pixel.x); + int endx = lround(point2->pixel.x); + int curx; + + if (endx < startx) + { + pushScanLineEdge(canvas, scanlines, point2, point1); + } + else if (endx < 0 || startx >= canvas->getWidth()) + { + return; + } + else if (startx == endx) + { + pushScanPoint(canvas, scanlines, point1); + pushScanPoint(canvas, scanlines, point2); + } + else + { + if (startx < 0) + { + startx = 0; + } + if (endx >= canvas->getWidth()) + { + endx = canvas->getWidth() - 1; + } + + dx = point2->pixel.x - point1->pixel.x; + scanGetDiff(point1, point2, &diff); + for (curx = startx; curx <= endx; curx++) + { + fx = (double)curx + 0.5; + if (fx < point1->pixel.x) + { + fx = point1->pixel.x; + } + else if (fx > point2->pixel.x) + { + fx = point2->pixel.x; + } + fx = fx - point1->pixel.x; + scanInterpolate(renderer->render_camera, point1, &diff, fx / dx, &point); + + /*point.pixel.x = (double)curx;*/ + + pushScanPoint(canvas, scanlines, &point); + } + } +} + +void Rasterizer::renderScanLines(CanvasPortion *canvas, RenderScanlines* scanlines) +{ + int x, starty, endy, cury; + ScanPoint diff; + double dy, fy; + ScanPoint up, down, current; + + if (scanlines->right > 0) + { + for (x = scanlines->left; x <= scanlines->right; x++) + { + up = scanlines->up[x]; + down = scanlines->down[x]; + + starty = down.y; + endy = up.y; + + if (endy < 0 || starty >= canvas->getHeight()) + { + continue; + } + + if (starty < 0) + { + starty = 0; + } + if (endy >= canvas->getHeight()) + { + endy = canvas->getHeight() - 1; + } + + dy = up.pixel.y - down.pixel.y; + scanGetDiff(&down, &up, &diff); + + current.x = x; + for (cury = starty; cury <= endy; cury++) + { + fy = (double)cury + 0.5; + if (fy < down.pixel.y) + { + fy = down.pixel.y; + } + else if (fy > up.pixel.y) + { + fy = up.pixel.y; + } + fy = fy - down.pixel.y; + + current.y = cury; + scanInterpolate(renderer->render_camera, &down, &diff, fy / dy, ¤t); + + CanvasFragment fragment(current.pixel.z, Vector3(current.location.x, current.location.y, current.location.z), current.client); + fragment.setColor((cury == starty || cury == endy) ? COLOR_GREY : COLOR_WHITE); + canvas->pushFragment(current.x, current.y, fragment); + } + } + } +} diff --git a/src/render/software/Rasterizer.h b/src/render/software/Rasterizer.h index 422a8e2..ec75297 100644 --- a/src/render/software/Rasterizer.h +++ b/src/render/software/Rasterizer.h @@ -6,13 +6,40 @@ namespace paysages { namespace software { +typedef struct ScanPoint ScanPoint; +typedef struct RenderScanlines RenderScanlines; + /** * @brief Base abstract class for scenery pieces that can be rasterized to polygons. */ class SOFTWARESHARED_EXPORT Rasterizer { public: - Rasterizer(); + Rasterizer(SoftwareRenderer *renderer, int client_id); + virtual ~Rasterizer(); + + inline SoftwareRenderer *getRenderer() const {return renderer;} + + virtual void rasterize() = 0; + virtual void rasterizeToCanvas(CanvasPortion* canvas); + +protected: + void pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3); + + void pushTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3); + void pushQuad(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4); + void pushDisplacedTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3); + void pushDisplacedQuad(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3, const Vector3 &ov4); + + SoftwareRenderer *renderer; + int client_id; + +private: + void scanGetDiff(ScanPoint *v1, ScanPoint *v2, ScanPoint *result); + void scanInterpolate(CameraDefinition *camera, ScanPoint *v1, ScanPoint *diff, double value, ScanPoint *result); + void pushScanPoint(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point); + void pushScanLineEdge(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point1, ScanPoint *point2); + void renderScanLines(CanvasPortion *canvas, RenderScanlines *scanlines); }; } diff --git a/src/render/software/SkyRasterizer.cpp b/src/render/software/SkyRasterizer.cpp index 226e070..b0016a3 100644 --- a/src/render/software/SkyRasterizer.cpp +++ b/src/render/software/SkyRasterizer.cpp @@ -6,11 +6,12 @@ #include "AtmosphereRenderer.h" #include "AtmosphereResult.h" #include "CloudsRenderer.h" +#include "Rasterizer.h" #define SPHERE_SIZE 20000.0 -SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer): - renderer(renderer) +SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, int client_id): + Rasterizer(renderer, client_id) { } @@ -83,3 +84,58 @@ void SkyRasterizer::rasterize() } } } + +void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas) +{ + int res_i, res_j; + int i, j; + double step_i, step_j; + double current_i, current_j; + Vector3 vertex1, vertex2, vertex3, vertex4; + Vector3 camera_location, direction; + + res_i = renderer->render_quality * 40; + res_j = renderer->render_quality * 20; + step_i = M_PI * 2.0 / (double)res_i; + step_j = M_PI / (double)res_j; + + camera_location = renderer->getCameraLocation(VECTOR_ZERO); + + for (j = 0; j < res_j; j++) + { + if (!renderer->addRenderProgress(0.0)) + { + return; + } + + current_j = (double)(j - res_j / 2) * step_j; + + for (i = 0; i < res_i; i++) + { + current_i = (double)i * step_i; + + direction.x = SPHERE_SIZE * cos(current_i) * cos(current_j); + direction.y = SPHERE_SIZE * sin(current_j); + direction.z = SPHERE_SIZE * sin(current_i) * cos(current_j); + vertex1 = camera_location.add(direction); + + direction.x = SPHERE_SIZE * cos(current_i + step_i) * cos(current_j); + direction.y = SPHERE_SIZE * sin(current_j); + direction.z = SPHERE_SIZE * sin(current_i + step_i) * cos(current_j); + vertex2 = camera_location.add(direction); + + direction.x = SPHERE_SIZE * cos(current_i + step_i) * cos(current_j + step_j); + direction.y = SPHERE_SIZE * sin(current_j + step_j); + direction.z = SPHERE_SIZE * sin(current_i + step_i) * cos(current_j + step_j); + vertex3 = camera_location.add(direction); + + direction.x = SPHERE_SIZE * cos(current_i) * cos(current_j + step_j); + direction.y = SPHERE_SIZE * sin(current_j + step_j); + direction.z = SPHERE_SIZE * sin(current_i) * cos(current_j + step_j); + vertex4 = camera_location.add(direction); + + /* TODO Triangles at poles */ + pushQuad(canvas, vertex1, vertex4, vertex3, vertex2); + } + } +} diff --git a/src/render/software/SkyRasterizer.h b/src/render/software/SkyRasterizer.h index c6432fc..3184df3 100644 --- a/src/render/software/SkyRasterizer.h +++ b/src/render/software/SkyRasterizer.h @@ -11,11 +11,10 @@ namespace software { class SOFTWARESHARED_EXPORT SkyRasterizer: public Rasterizer { public: - SkyRasterizer(SoftwareRenderer* renderer); - void rasterize(); + SkyRasterizer(SoftwareRenderer* renderer, int client_id); -private: - SoftwareRenderer* renderer; + virtual void rasterize(); + virtual void rasterizeToCanvas(CanvasPortion* canvas); }; } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index f8c9742..684f573 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -3,18 +3,29 @@ #include "Rasterizer.h" #include "SoftwareRenderer.h" #include "Canvas.h" +#include "TerrainRasterizer.h" +#include "WaterRasterizer.h" +#include "SkyRasterizer.h" +#include "CameraDefinition.h" SoftwareCanvasRenderer::SoftwareCanvasRenderer() { started = false; - renderer = new SoftwareRenderer(); canvas = new Canvas(); + + rasterizers.push_back(new TerrainRasterizer(this, 0)); + rasterizers.push_back(new WaterRasterizer(this, 1)); + rasterizers.push_back(new SkyRasterizer(this, 2)); } SoftwareCanvasRenderer::~SoftwareCanvasRenderer() { - delete renderer; delete canvas; + + for (auto &rasterizer: rasterizers) + { + delete rasterizer; + } } void SoftwareCanvasRenderer::setSize(int width, int height, int samples) @@ -31,17 +42,22 @@ void SoftwareCanvasRenderer::render() started = true; CanvasPortion *portion = canvas->at(0, 0); + render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight()); + rasterize(portion, true); postProcess(portion, true); } +const std::vector &SoftwareCanvasRenderer::getRasterizers() const +{ + return rasterizers; +} + void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded) { - std::vector rasterizers; - renderer->getRasterizers(&rasterizers); - - for (auto &rasterizer:rasterizers) + for (auto &rasterizer:getRasterizers()) { + rasterizer->rasterizeToCanvas(portion); } } diff --git a/src/render/software/SoftwareCanvasRenderer.h b/src/render/software/SoftwareCanvasRenderer.h index 847fbd7..3f51569 100644 --- a/src/render/software/SoftwareCanvasRenderer.h +++ b/src/render/software/SoftwareCanvasRenderer.h @@ -3,6 +3,8 @@ #include "software_global.h" +#include "SoftwareRenderer.h" + namespace paysages { namespace software { @@ -14,11 +16,11 @@ namespace software { * * It tries to keep a canvas portion rasterized ahead of the post processing. */ -class SOFTWARESHARED_EXPORT SoftwareCanvasRenderer +class SOFTWARESHARED_EXPORT SoftwareCanvasRenderer: public SoftwareRenderer { public: SoftwareCanvasRenderer(); - ~SoftwareCanvasRenderer(); + virtual ~SoftwareCanvasRenderer(); inline const Canvas *getCanvas() const {return canvas;} @@ -34,6 +36,11 @@ public: */ void render(); + /*! + * \brief Get the list of objects that can be rasterized to polygons on a canvas. + */ + virtual const std::vector &getRasterizers() const; + protected: /** * @brief Rasterize the scenery into a canvas portion. @@ -50,8 +57,8 @@ protected: void postProcess(CanvasPortion* portion, bool threaded=true); private: - SoftwareRenderer* renderer; Canvas* canvas; + std::vector rasterizers; bool started; }; diff --git a/src/render/software/SoftwareRenderer.cpp b/src/render/software/SoftwareRenderer.cpp index 12cdb64..2af4f4a 100644 --- a/src/render/software/SoftwareRenderer.cpp +++ b/src/render/software/SoftwareRenderer.cpp @@ -108,22 +108,15 @@ void SoftwareRenderer::prepare() //fluid_medium->registerMedium(water_renderer); } -void SoftwareRenderer::getRasterizers(std::vector *array) -{ - array->push_back(TerrainRasterizer(this)); - array->push_back(WaterRasterizer(this)); - array->push_back(SkyRasterizer(this)); -} - void SoftwareRenderer::rasterize() { - TerrainRasterizer terrain(this); - terrain.renderSurface(); + TerrainRasterizer terrain(this, 0); + terrain.rasterize(); - WaterRasterizer water(this); - water.renderSurface(); + WaterRasterizer water(this, 1); + water.rasterize(); - SkyRasterizer sky(this); + SkyRasterizer sky(this, 2); sky.rasterize(); } diff --git a/src/render/software/SoftwareRenderer.h b/src/render/software/SoftwareRenderer.h index 08b2d76..9f269f3 100644 --- a/src/render/software/SoftwareRenderer.h +++ b/src/render/software/SoftwareRenderer.h @@ -59,11 +59,6 @@ public: */ virtual void prepare(); - /*! - * \brief Get the list of objects that can be rasterized to polygons on a canvas. - */ - virtual void getRasterizers(std::vector *array); - /*! * \brief Start the rasterization process. */ diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index cf53310..36f1d17 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -9,8 +9,8 @@ #include "Scenery.h" #include "ParallelQueue.h" -TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer): - renderer(renderer) +TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id): + Rasterizer(renderer, client_id) { } @@ -228,7 +228,7 @@ int TerrainRasterizer::processChunk(TerrainChunkInfo* chunk, double progress) return !renderer->render_interrupt; } -void TerrainRasterizer::renderSurface() +void TerrainRasterizer::rasterize() { queue = new ParallelQueue(); diff --git a/src/render/software/TerrainRasterizer.h b/src/render/software/TerrainRasterizer.h index 83c9eaf..7426b5f 100644 --- a/src/render/software/TerrainRasterizer.h +++ b/src/render/software/TerrainRasterizer.h @@ -22,7 +22,7 @@ public: } TerrainChunkInfo; public: - TerrainRasterizer(SoftwareRenderer* renderer); + TerrainRasterizer(SoftwareRenderer* renderer, int client_id); /** * Method called for each chunk tessellated by getTessellationInfo. @@ -46,10 +46,9 @@ public: * * This will push the rasterized quads in the render area, waiting for post process. */ - void renderSurface(); + virtual void rasterize(); private: - SoftwareRenderer* renderer; ParallelQueue* queue; }; diff --git a/src/render/software/WaterRasterizer.cpp b/src/render/software/WaterRasterizer.cpp index 2ec32d1..40350b2 100644 --- a/src/render/software/WaterRasterizer.cpp +++ b/src/render/software/WaterRasterizer.cpp @@ -4,8 +4,8 @@ #include "WaterRenderer.h" #include "ParallelQueue.h" -WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer): - renderer(renderer) +WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, int client_id): + Rasterizer(renderer, client_id) { } @@ -64,7 +64,7 @@ static int _parallelJobCallback(ParallelQueue*, int, void* data, int stopping) return 0; } -void WaterRasterizer::renderSurface() +void WaterRasterizer::rasterize() { ParallelRasterInfo* info; ParallelQueue* queue; diff --git a/src/render/software/WaterRasterizer.h b/src/render/software/WaterRasterizer.h index 031f937..62062be 100644 --- a/src/render/software/WaterRasterizer.h +++ b/src/render/software/WaterRasterizer.h @@ -11,12 +11,9 @@ namespace software { class WaterRasterizer: public Rasterizer { public: - WaterRasterizer(SoftwareRenderer* renderer); + WaterRasterizer(SoftwareRenderer* renderer, int client_id); - void renderSurface(); - -private: - SoftwareRenderer* renderer; + virtual void rasterize(); }; } From f94d93ae60549709a28901c4274251ff03b4a1e4 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Wed, 18 Jun 2014 20:10:05 +0200 Subject: [PATCH 04/29] Fixed canvas Z-index --- src/render/software/CanvasPixel.cpp | 4 +- .../software/SoftwareCanvasRenderer.cpp | 2 + src/render/software/TerrainRasterizer.cpp | 5 ++ src/render/software/TerrainRasterizer.h | 2 + src/render/software/WaterRasterizer.cpp | 62 ++++++++++++++++++- src/render/software/WaterRasterizer.h | 4 ++ src/tests/CanvasPortion_Test.cpp | 14 ++--- 7 files changed, 83 insertions(+), 10 deletions(-) diff --git a/src/render/software/CanvasPixel.cpp b/src/render/software/CanvasPixel.cpp index b4287ab..1b09863 100644 --- a/src/render/software/CanvasPixel.cpp +++ b/src/render/software/CanvasPixel.cpp @@ -34,7 +34,7 @@ void CanvasPixel::pushFragment(const CanvasFragment &fragment) } else { - if (fragments[0].getOpaque() and fragment.getZ() > fragments[0].getZ()) + if (fragments[0].getOpaque() and fragment.getZ() < fragments[0].getZ()) { // behind opaque fragment, don't bother return; @@ -42,7 +42,7 @@ void CanvasPixel::pushFragment(const CanvasFragment &fragment) // find expected position int i = 0; - while (i < count and fragment.getZ() < fragments[i].getZ()) + while (i < count and fragment.getZ() > fragments[i].getZ()) { i++; } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 684f573..3a626d4 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -44,6 +44,8 @@ void SoftwareCanvasRenderer::render() render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight()); + prepare(); + rasterize(portion, true); postProcess(portion, true); } diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index 36f1d17..143b208 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -238,3 +238,8 @@ void TerrainRasterizer::rasterize() queue->wait(); } + +void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas) +{ + +} diff --git a/src/render/software/TerrainRasterizer.h b/src/render/software/TerrainRasterizer.h index 7426b5f..9528958 100644 --- a/src/render/software/TerrainRasterizer.h +++ b/src/render/software/TerrainRasterizer.h @@ -48,6 +48,8 @@ public: */ virtual void rasterize(); + virtual void rasterizeToCanvas(CanvasPortion* canvas); + private: ParallelQueue* queue; }; diff --git a/src/render/software/WaterRasterizer.cpp b/src/render/software/WaterRasterizer.cpp index 40350b2..0df1c9f 100644 --- a/src/render/software/WaterRasterizer.cpp +++ b/src/render/software/WaterRasterizer.cpp @@ -14,7 +14,7 @@ static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &loc return renderer->getWaterRenderer()->getResult(location.x, location.z).final; } -static Vector3 _getFirstPassVertex(SoftwareRenderer* renderer, double x, double z) +static inline Vector3 _getFirstPassVertex(SoftwareRenderer* renderer, double x, double z) { Vector3 result; @@ -128,3 +128,63 @@ void WaterRasterizer::rasterize() queue->wait(); delete queue; } + +void WaterRasterizer::rasterizeQuad(CanvasPortion* canvas, double x, double z, double size) +{ + Vector3 v1, v2, v3, v4; + + v1 = _getFirstPassVertex(renderer, x, z); + v2 = _getFirstPassVertex(renderer, x, z + size); + v3 = _getFirstPassVertex(renderer, x + size, z + size); + v4 = _getFirstPassVertex(renderer, x + size, z); + + pushQuad(canvas, v1, v2, v3, v4); +} + +void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas) +{ + int chunk_factor, chunk_count, i; + Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO); + double radius_int, radius_ext, base_chunk_size, chunk_size; + + base_chunk_size = 2.0 / (double)renderer->render_quality; + if (renderer->render_quality > 7) + { + base_chunk_size *= 0.5; + } + + chunk_factor = 1; + chunk_count = 2; + radius_int = 0.0; + radius_ext = base_chunk_size; + chunk_size = base_chunk_size; + + double cx = cam.x - fmod(cam.x, base_chunk_size); + double cz = cam.z - fmod(cam.x, base_chunk_size); + + while (radius_int < 20000.0) + { + if (!renderer->addRenderProgress(0.0)) + { + return; + } + + for (i = 0; i < chunk_count - 1; i++) + { + rasterizeQuad(canvas, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size); + rasterizeQuad(canvas, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size); + rasterizeQuad(canvas, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size); + rasterizeQuad(canvas, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size); + } + + if (radius_int > 20.0 && chunk_count % 64 == 0 && (double)chunk_factor < radius_int / 20.0) + { + chunk_count /= 2; + chunk_factor *= 2; + } + chunk_count += 2; + chunk_size = base_chunk_size * chunk_factor; + radius_int = radius_ext; + radius_ext += chunk_size; + } +} diff --git a/src/render/software/WaterRasterizer.h b/src/render/software/WaterRasterizer.h index 62062be..98e4450 100644 --- a/src/render/software/WaterRasterizer.h +++ b/src/render/software/WaterRasterizer.h @@ -13,7 +13,11 @@ class WaterRasterizer: public Rasterizer public: WaterRasterizer(SoftwareRenderer* renderer, int client_id); + void rasterizeQuad(CanvasPortion* canvas, double x, double z, double size); + virtual void rasterize(); + + virtual void rasterizeToCanvas(CanvasPortion* canvas); }; } diff --git a/src/tests/CanvasPortion_Test.cpp b/src/tests/CanvasPortion_Test.cpp index 643d11e..b88137c 100644 --- a/src/tests/CanvasPortion_Test.cpp +++ b/src/tests/CanvasPortion_Test.cpp @@ -47,17 +47,17 @@ TEST(CanvasPortion, pushFragment_opaque) ASSERT_EQ(1, portion.getFragmentCount(2, 2)); EXPECT_DOUBLE_EQ(2.0, portion.getFrontFragment(2, 2)->getZ()); - pushed = CanvasFragment(4.0, VECTOR_ZERO, 0); + pushed = CanvasFragment(1.0, VECTOR_ZERO, 0); portion.pushFragment(2, 2, pushed); ASSERT_EQ(1, portion.getFragmentCount(2, 2)); EXPECT_DOUBLE_EQ(2.0, portion.getFrontFragment(2, 2)->getZ()); - pushed = CanvasFragment(1.0, VECTOR_ZERO, 0); + pushed = CanvasFragment(4.0, VECTOR_ZERO, 0); portion.pushFragment(2, 2, pushed); ASSERT_EQ(1, portion.getFragmentCount(2, 2)); - EXPECT_DOUBLE_EQ(1.0, portion.getFrontFragment(2, 2)->getZ()); + EXPECT_DOUBLE_EQ(4.0, portion.getFrontFragment(2, 2)->getZ()); } TEST(CanvasPortion, pushFragment_transparent) @@ -67,11 +67,11 @@ TEST(CanvasPortion, pushFragment_transparent) portion.setSize(10, 10); - pushed = CanvasFragment(4.0, VECTOR_ZERO, 0, false); + pushed = CanvasFragment(2.0, VECTOR_ZERO, 0, false); portion.pushFragment(2, 2, pushed); ASSERT_EQ(1, portion.getFragmentCount(2, 2)); - EXPECT_DOUBLE_EQ(4.0, portion.getFrontFragment(2, 2)->getZ()); + EXPECT_DOUBLE_EQ(2.0, portion.getFrontFragment(2, 2)->getZ()); pushed = CanvasFragment(3.0, VECTOR_ZERO, 0, true); portion.pushFragment(2, 2, pushed); @@ -79,11 +79,11 @@ TEST(CanvasPortion, pushFragment_transparent) ASSERT_EQ(1, portion.getFragmentCount(2, 2)); EXPECT_DOUBLE_EQ(3.0, portion.getFrontFragment(2, 2)->getZ()); - pushed = CanvasFragment(2.0, VECTOR_ZERO, 0, false); + pushed = CanvasFragment(4.0, VECTOR_ZERO, 0, false); portion.pushFragment(2, 2, pushed); ASSERT_EQ(2, portion.getFragmentCount(2, 2)); - EXPECT_DOUBLE_EQ(2.0, portion.getFrontFragment(2, 2)->getZ()); + EXPECT_DOUBLE_EQ(4.0, portion.getFrontFragment(2, 2)->getZ()); } TEST(CanvasPortion, clear) From bc34a2b823b01e0ab760d95bc9b055aea42a9958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Wed, 18 Jun 2014 22:10:46 +0200 Subject: [PATCH 05/29] Removed RenderArea and added terrain rasterization to canvas --- src/interface/commandline/main.cpp | 17 +- .../desktop/common/freeformhelper.cpp | 3 +- src/interface/desktop/dialogrender.cpp | 18 +- src/interface/desktop/dialogrender.h | 3 +- src/interface/desktop/formrender.cpp | 2 +- src/interface/desktop/formrender.h | 4 +- src/render/software/Rasterizer.h | 1 - src/render/software/RenderArea.cpp | 792 ------------------ src/render/software/RenderArea.h | 76 -- src/render/software/RenderConfig.cpp | 30 + src/render/software/RenderConfig.h | 23 + src/render/software/SkyRasterizer.cpp | 55 -- src/render/software/SkyRasterizer.h | 1 - .../software/SoftwareCanvasRenderer.cpp | 7 +- src/render/software/SoftwareRenderer.cpp | 108 --- src/render/software/SoftwareRenderer.h | 13 - src/render/software/TerrainRasterizer.cpp | 80 +- src/render/software/TerrainRasterizer.h | 8 +- src/render/software/WaterRasterizer.cpp | 104 --- src/render/software/WaterRasterizer.h | 2 - src/render/software/software.pro | 8 +- src/render/software/software_global.h | 2 +- src/tests/Bruneton_Test.cpp | 8 +- src/tests/Render_Test.cpp | 12 +- 24 files changed, 142 insertions(+), 1235 deletions(-) delete mode 100644 src/render/software/RenderArea.cpp delete mode 100644 src/render/software/RenderArea.h create mode 100644 src/render/software/RenderConfig.cpp create mode 100644 src/render/software/RenderConfig.h diff --git a/src/interface/commandline/main.cpp b/src/interface/commandline/main.cpp index dcd2571..447ce61 100644 --- a/src/interface/commandline/main.cpp +++ b/src/interface/commandline/main.cpp @@ -5,16 +5,17 @@ #include "CameraDefinition.h" #include "AtmosphereDefinition.h" -#include "SoftwareRenderer.h" +#include "SoftwareCanvasRenderer.h" #include "Scenery.h" +#include "RenderConfig.h" -void startRender(SoftwareRenderer* renderer, char* outputpath, RenderArea::RenderParams params) +void startRender(SoftwareRenderer *renderer, char *outputpath, const RenderConfig ¶ms) { - printf("\rRendering %s ... \n", outputpath); + /*printf("\rRendering %s ... \n", outputpath); renderer->start(params); printf("\rSaving %s ... \n", outputpath); remove(outputpath); - renderer->render_area->saveToFile(outputpath); + renderer->render_area->saveToFile(outputpath);*/ } void displayHelp() @@ -43,9 +44,9 @@ void _previewUpdate(double progress) int main(int argc, char** argv) { - SoftwareRenderer* renderer; + SoftwareCanvasRenderer* renderer; char* conf_file_path = NULL; - RenderArea::RenderParams conf_render_params = {800, 600, 1, 5}; + RenderConfig conf_render_params(800, 600, 1, 5); int conf_first_picture = 0; int conf_nb_pictures = 1; double conf_daytime_start = 0.4; @@ -177,8 +178,8 @@ int main(int argc, char** argv) Vector3 step = {conf_camera_step_x, conf_camera_step_y, conf_camera_step_z}; camera->setLocation(camera->getLocation().add(step)); - renderer = new SoftwareRenderer(scenery); - renderer->setPreviewCallbacks(NULL, NULL, _previewUpdate); + renderer = new SoftwareCanvasRenderer(); + renderer->setScenery(scenery); if (outputcount >= conf_first_picture) { diff --git a/src/interface/desktop/common/freeformhelper.cpp b/src/interface/desktop/common/freeformhelper.cpp index 433867e..ad0bcae 100644 --- a/src/interface/desktop/common/freeformhelper.cpp +++ b/src/interface/desktop/common/freeformhelper.cpp @@ -12,6 +12,7 @@ #include "mainwindow.h" #include "dialogrender.h" #include "dialogexplorer.h" +#include "RenderConfig.h" #include "DesktopScenery.h" #include "BasePreview.h" #include "SoftwareCanvasRenderer.h" @@ -252,7 +253,7 @@ void FreeFormHelper::processRenderClicked() emit needAlterRenderer(&renderer); DialogRender* dialog = new DialogRender(_form_widget, &renderer); - RenderArea::RenderParams params = {400, 300, 1, 3}; + RenderConfig params(400, 300, 1, 3); dialog->startRender(params); delete dialog; diff --git a/src/interface/desktop/dialogrender.cpp b/src/interface/desktop/dialogrender.cpp index ceec5b4..1d51787 100644 --- a/src/interface/desktop/dialogrender.cpp +++ b/src/interface/desktop/dialogrender.cpp @@ -18,7 +18,7 @@ #include #include "tools.h" -#include "SoftwareRenderer.h" +#include "RenderConfig.h" #include "Scenery.h" #include "ColorProfile.h" #include "SoftwareCanvasRenderer.h" @@ -51,7 +51,7 @@ static void _renderUpdate(double progress) class RenderThread:public QThread { public: - RenderThread(DialogRender* dialog, SoftwareCanvasRenderer* renderer, RenderArea::RenderParams params):QThread() + RenderThread(DialogRender* dialog, SoftwareCanvasRenderer* renderer, const RenderConfig ¶ms):QThread() { _dialog = dialog; _renderer = renderer; @@ -59,14 +59,14 @@ public: } void run() { + // FIXME Pass config to render _renderer->render(); - _renderer->start(_params); _dialog->tellRenderEnded(); } private: DialogRender* _dialog; SoftwareCanvasRenderer* _renderer; - RenderArea::RenderParams _params; + RenderConfig _params; }; class _RenderArea:public QWidget @@ -183,14 +183,13 @@ void DialogRender::tellRenderEnded() emit renderEnded(); } -void DialogRender::startRender(RenderArea::RenderParams params) +void DialogRender::startRender(const RenderConfig ¶ms) { _started = time(NULL); canvas_renderer->setSize(params.width, params.height, params.antialias); applyRenderSize(params.width, params.height); - canvas_renderer->setPreviewCallbacks(_renderStart, _renderDraw, _renderUpdate); _render_thread = new RenderThread(this, canvas_renderer, params); _render_thread->start(); @@ -218,11 +217,11 @@ void DialogRender::saveRender() filepath = filepath.append(".png"); } std::string filepathstr = filepath.toStdString(); - if (canvas_renderer->render_area->saveToFile((char*)filepathstr.c_str())) + /*if (canvas_renderer->render_area->saveToFile((char*)filepathstr.c_str())) { QMessageBox::information(this, "Message", QString(tr("The picture %1 has been saved.")).arg(filepath)); } - else + else*/ { QMessageBox::critical(this, "Message", QString(tr("Can't write to file : %1")).arg(filepath)); } @@ -232,13 +231,12 @@ void DialogRender::saveRender() void DialogRender::toneMappingChanged() { ColorProfile profile((ColorProfile::ToneMappingOperator)_tonemapping_control->currentIndex(), ((double)_exposure_control->value()) * 0.01); - canvas_renderer->render_area->setToneMapping(profile); + //canvas_renderer->render_area->setToneMapping(profile); } void DialogRender::loadLastRender() { applyRenderSize(canvas_renderer->render_width, canvas_renderer->render_height); - canvas_renderer->setPreviewCallbacks(_renderStart, _renderDraw, _renderUpdate); renderEnded(); toneMappingChanged(); diff --git a/src/interface/desktop/dialogrender.h b/src/interface/desktop/dialogrender.h index 3ea599a..b35fea1 100644 --- a/src/interface/desktop/dialogrender.h +++ b/src/interface/desktop/dialogrender.h @@ -5,7 +5,6 @@ #include #include -#include "RenderArea.h" class QThread; class QProgressBar; @@ -25,7 +24,7 @@ public: void tellRenderSize(int width, int height); void tellProgressChange(double value); void tellRenderEnded(); - void startRender(RenderArea::RenderParams params); + void startRender(const RenderConfig ¶ms); void loadLastRender(); QImage* pixbuf; diff --git a/src/interface/desktop/formrender.cpp b/src/interface/desktop/formrender.cpp index 26f58a0..cbc6157 100644 --- a/src/interface/desktop/formrender.cpp +++ b/src/interface/desktop/formrender.cpp @@ -108,7 +108,7 @@ void FormRender::startQuickRender() _renderer_inited = true; DialogRender* dialog = new DialogRender(this, _renderer); - RenderArea::RenderParams params = {400, 300, 1, 3}; + RenderConfig params(400, 300, 1, 3); dialog->startRender(params); delete dialog; diff --git a/src/interface/desktop/formrender.h b/src/interface/desktop/formrender.h index 9f4afcd..8404f62 100644 --- a/src/interface/desktop/formrender.h +++ b/src/interface/desktop/formrender.h @@ -5,7 +5,7 @@ #include "baseform.h" -#include "RenderArea.h" +#include "RenderConfig.h" class FormRender : public BaseForm { @@ -29,7 +29,7 @@ protected slots: virtual void configChangeEvent(); private: - RenderArea::RenderParams _params; + RenderConfig _params; CameraDefinition* _camera; SoftwareCanvasRenderer* _renderer; bool _renderer_inited; diff --git a/src/render/software/Rasterizer.h b/src/render/software/Rasterizer.h index ec75297..1bb410c 100644 --- a/src/render/software/Rasterizer.h +++ b/src/render/software/Rasterizer.h @@ -20,7 +20,6 @@ public: inline SoftwareRenderer *getRenderer() const {return renderer;} - virtual void rasterize() = 0; virtual void rasterizeToCanvas(CanvasPortion* canvas); protected: diff --git a/src/render/software/RenderArea.cpp b/src/render/software/RenderArea.cpp deleted file mode 100644 index 26064ed..0000000 --- a/src/render/software/RenderArea.cpp +++ /dev/null @@ -1,792 +0,0 @@ -#include "RenderArea.h" - -#include "Vector3.h" -#include "ColorProfile.h" -#include "Mutex.h" -#include "CameraDefinition.h" -#include "SoftwareRenderer.h" -#include "Thread.h" -#include "PictureWriter.h" - -struct RenderFragment -{ - struct - { - unsigned char dirty : 1; - unsigned char edge : 1; - unsigned char callback : 6; - } flags; - union - { - struct { - double x; - double y; - double z; - } location; - struct { - double r; - double g; - double b; - } color; - } data; - double z; -}; - -typedef struct -{ - int x; - int y; - struct { - double x; - double y; - double z; - } pixel; - struct { - double x; - double y; - double z; - } location; - int callback; -} ScanPoint; - -struct FragmentCallback -{ - RenderArea::f_RenderFragmentCallback function; - void* data; -}; - -typedef struct -{ - ScanPoint* up; - ScanPoint* down; - int left; - int right; -} RenderScanlines; - -typedef struct -{ - int startx; - int endx; - int starty; - int endy; - int finished; - int interrupt; - int pixel_done; - Thread* thread; - RenderArea* area; -} RenderChunk; - -static void _callbackStart(int, int, const Color&) {} -static void _callbackDraw(int, int, const Color&) {} -static void _callbackUpdate(double) {} - -RenderArea::RenderArea(SoftwareRenderer* renderer) -{ - this->renderer = renderer; - this->hdr_mapping = new ColorProfile; - this->params.width = 1; - this->params.height = 1; - this->params.antialias = 1; - this->params.quality = 5; - this->pixel_count = 1; - this->pixels = new RenderFragment[1]; - this->fragment_callbacks_count = 0; - this->fragment_callbacks = new FragmentCallback[64]; - this->background_color = COLOR_TRANSPARENT; - this->dirty_left = 1; - this->dirty_right = -1; - this->dirty_down = 1; - this->dirty_up = -1; - this->dirty_count = 0; - this->lock = new Mutex(); - this->callback_start = _callbackStart; - this->callback_draw = _callbackDraw; - this->callback_update = _callbackUpdate; -} - -RenderArea::~RenderArea() -{ - delete hdr_mapping; - delete lock; - delete[] fragment_callbacks; - delete[] pixels; -} - -void RenderArea::setAllDirty() -{ - dirty_left = 0; - dirty_right = params.width * params.antialias - 1; - dirty_down = 0; - dirty_up = params.height * params.antialias - 1; -} - -void RenderArea::setParams(RenderParams params) -{ - int width, height; - - width = params.width * params.antialias; - height = params.height * params.antialias; - - this->params = params; - delete[] pixels; - pixels = new RenderFragment[width * height]; - pixel_count = width * height; - - dirty_left = width; - dirty_right = -1; - dirty_down = height; - dirty_up = -1; - dirty_count = 0; - - clear(); -} - -void RenderArea::setToneMapping(const ColorProfile &profile) -{ - profile.copy(hdr_mapping); - setAllDirty(); - update(); -} - -void RenderArea::setBackgroundColor(const Color &col) -{ - background_color = col; -} - -void RenderArea::clear() -{ - RenderFragment* pixel; - int x; - int y; - - fragment_callbacks_count = 1; - fragment_callbacks[0].function = NULL; - fragment_callbacks[0].data = NULL; - - for (x = 0; x < params.width * params.antialias; x++) - { - for (y = 0; y < params.height * params.antialias; y++) - { - pixel = pixels + (y * params.width * params.antialias + x); - pixel->z = -100000000.0; - pixel->flags.dirty = 0; - pixel->flags.callback = 0; - pixel->data.color.r = background_color.r; - pixel->data.color.g = background_color.g; - pixel->data.color.b = background_color.b; - } - } - - callback_start(params.width, params.height, background_color); - - dirty_left = params.width * params.antialias; - dirty_right = -1; - dirty_down = params.height * params.antialias; - dirty_up = -1; - dirty_count = 0; -} - -static inline void _setDirtyPixel(RenderArea* area, int x, int y) -{ - if (x < area->dirty_left) - { - area->dirty_left = x; - } - if (x > area->dirty_right) - { - area->dirty_right = x; - } - if (y < area->dirty_down) - { - area->dirty_down = y; - } - if (y > area->dirty_up) - { - area->dirty_up = y; - } - - area->dirty_count++; -} - -static inline Color _getFinalPixel(RenderArea* area, int x, int y) -{ - Color result, col; - int sx, sy; - double factor = 1.0 / (double)(area->params.antialias * area->params.antialias); - RenderFragment* pixel_data; - - result.r = result.g = result.b = 0.0; - result.a = 1.0; - for (sx = 0; sx < area->params.antialias; sx++) - { - for (sy = 0; sy < area->params.antialias; sy++) - { - pixel_data = area->pixels + (y * area->params.antialias + sy) * area->params.width * area->params.antialias + (x * area->params.antialias + sx); - if (pixel_data->flags.dirty) - { - if (pixel_data->flags.edge) - { - col = COLOR_GREY; - } - else - { - col = COLOR_WHITE; - } - } - else - { - col.r = pixel_data->data.color.r; - col.g = pixel_data->data.color.g; - col.b = pixel_data->data.color.b; - } - result.r += col.r * factor; - result.g += col.g * factor; - result.b += col.b * factor; - - } - } - - return area->hdr_mapping->apply(result); -} - -void RenderArea::processDirtyPixels() -{ - int x, y; - int down, up, left, right; - - down = dirty_down / params.antialias; - up = dirty_up / params.antialias; - left = dirty_left / params.antialias; - right = dirty_right / params.antialias; - - for (y = down; y <= up; y++) - { - for (x = left; x <= right; x++) - { - callback_draw(x, y, _getFinalPixel(this, x, y)); - } - } - - callback_update(renderer->render_progress); - - dirty_left = params.width * params.antialias; - dirty_right = -1; - dirty_down = params.height * params.antialias; - dirty_up = -1; - dirty_count = 0; -} - -void RenderArea::update() -{ - lock->acquire(); - processDirtyPixels(); - lock->release(); -} - -static inline unsigned int _pushCallback(RenderArea* area, FragmentCallback callback) -{ - int i; - for (i = 0; i < area->fragment_callbacks_count; i++) - { - if (area->fragment_callbacks[i].function == callback.function && area->fragment_callbacks[i].data == callback.data) - { - return i; - } - } - - if (area->fragment_callbacks_count >= 64) - { - return 0; - } - else - { - area->fragment_callbacks[area->fragment_callbacks_count].function = callback.function; - area->fragment_callbacks[area->fragment_callbacks_count].data = callback.data; - return area->fragment_callbacks_count++; - } -} - -void RenderArea::pushFragment(int x, int y, double z, int edge, const Vector3 &location, int callback) -{ - RenderFragment* pixel_data; - - if (x >= 0 && x < params.width * params.antialias && y >= 0 && y < params.height * params.antialias && z > 1.0) - { - pixel_data = pixels + (y * params.width * params.antialias + x); - - if (z > pixel_data->z) - { - pixel_data->flags.dirty = (unsigned char)1; - pixel_data->flags.edge = (unsigned char)edge; - pixel_data->flags.callback = (unsigned char)callback; - pixel_data->data.location.x = location.x; - pixel_data->data.location.y = location.y; - pixel_data->data.location.z = location.z; - pixel_data->z = z; - _setDirtyPixel(this, x, y); - } - } -} - -static void _scanGetDiff(ScanPoint* v1, ScanPoint* v2, ScanPoint* result) -{ - result->pixel.x = v2->pixel.x - v1->pixel.x; - result->pixel.y = v2->pixel.y - v1->pixel.y; - result->pixel.z = v2->pixel.z - v1->pixel.z; - result->location.x = v2->location.x - v1->location.x; - result->location.y = v2->location.y - v1->location.y; - result->location.z = v2->location.z - v1->location.z; - result->callback = v1->callback; -} - -static void _scanInterpolate(CameraDefinition* camera, ScanPoint* v1, ScanPoint* diff, double value, ScanPoint* result) -{ - Vector3 vec1(v1->pixel.x, v1->pixel.y, v1->pixel.z); - Vector3 vecdiff(diff->pixel.x, diff->pixel.y, diff->pixel.z); - double v1depth = camera->getRealDepth(vec1); - double v2depth = camera->getRealDepth(vec1.add(vecdiff)); - double factor = ((1.0 - value) / v1depth + value / v2depth); - - result->pixel.x = v1->pixel.x + diff->pixel.x * value; - result->pixel.y = v1->pixel.y + diff->pixel.y * value; - result->pixel.z = v1->pixel.z + diff->pixel.z * value; - result->location.x = ((1.0 - value) * (v1->location.x / v1depth) + value * (v1->location.x + diff->location.x) / v2depth) / factor; - result->location.y = ((1.0 - value) * (v1->location.y / v1depth) + value * (v1->location.y + diff->location.y) / v2depth) / factor; - result->location.z = ((1.0 - value) * (v1->location.z / v1depth) + value * (v1->location.z + diff->location.z) / v2depth) / factor; - result->callback = v1->callback; -} - -static void _pushScanPoint(RenderArea* area, RenderScanlines* scanlines, ScanPoint* point) -{ - point->x = (int)floor(point->pixel.x); - point->y = (int)floor(point->pixel.y); - - if (point->x < 0 || point->x >= area->params.width * area->params.antialias) - { - // Point outside scanline range - return; - } - else if (scanlines->right < 0) - { - // First point pushed - scanlines->left = point->x; - scanlines->right = point->x; - scanlines->up[point->x] = *point; - scanlines->down[point->x] = *point; - } - else if (point->x > scanlines->right) - { - // Grow scanlines to right - for (int x = scanlines->right + 1; x < point->x; x++) - { - scanlines->up[x].y = -1; - scanlines->down[x].y = area->params.height * area->params.antialias; - } - scanlines->right = point->x; - scanlines->up[point->x] = *point; - scanlines->down[point->x] = *point; - } - else if (point->x < scanlines->left) - { - // Grow scanlines to left - for (int x = point->x + 1; x < scanlines->left; x++) - { - scanlines->up[x].y = -1; - scanlines->down[x].y = area->params.height * area->params.antialias; - } - scanlines->left = point->x; - scanlines->up[point->x] = *point; - scanlines->down[point->x] = *point; - } - else - { - // Expand existing scanline - if (point->y > scanlines->up[point->x].y) - { - scanlines->up[point->x] = *point; - } - if (point->y < scanlines->down[point->x].y) - { - scanlines->down[point->x] = *point; - } - } -} - -static void _pushScanLineEdge(RenderArea* area, RenderScanlines* scanlines, ScanPoint* point1, ScanPoint* point2) -{ - double dx, fx; - ScanPoint diff, point; - int startx = lround(point1->pixel.x); - int endx = lround(point2->pixel.x); - int curx; - - if (endx < startx) - { - _pushScanLineEdge(area, scanlines, point2, point1); - } - else if (endx < 0 || startx >= area->params.width * area->params.antialias) - { - return; - } - else if (startx == endx) - { - _pushScanPoint(area, scanlines, point1); - _pushScanPoint(area, scanlines, point2); - } - else - { - if (startx < 0) - { - startx = 0; - } - if (endx >= area->params.width * area->params.antialias) - { - endx = area->params.width * area->params.antialias - 1; - } - - dx = point2->pixel.x - point1->pixel.x; - _scanGetDiff(point1, point2, &diff); - for (curx = startx; curx <= endx; curx++) - { - fx = (double)curx + 0.5; - if (fx < point1->pixel.x) - { - fx = point1->pixel.x; - } - else if (fx > point2->pixel.x) - { - fx = point2->pixel.x; - } - fx = fx - point1->pixel.x; - _scanInterpolate(area->renderer->render_camera, point1, &diff, fx / dx, &point); - - /*point.pixel.x = (double)curx;*/ - - _pushScanPoint(area, scanlines, &point); - } - } -} - -static void _renderScanLines(RenderArea* area, RenderScanlines* scanlines) -{ - int x, starty, endy, cury; - ScanPoint diff; - double dy, fy; - ScanPoint up, down, current; - - if (scanlines->right > 0) - { - for (x = scanlines->left; x <= scanlines->right; x++) - { - up = scanlines->up[x]; - down = scanlines->down[x]; - - starty = down.y; - endy = up.y; - - if (endy < 0 || starty >= area->params.height * area->params.antialias) - { - continue; - } - - if (starty < 0) - { - starty = 0; - } - if (endy >= area->params.height * area->params.antialias) - { - endy = area->params.height * area->params.antialias - 1; - } - - dy = up.pixel.y - down.pixel.y; - _scanGetDiff(&down, &up, &diff); - - current.x = x; - for (cury = starty; cury <= endy; cury++) - { - fy = (double)cury + 0.5; - if (fy < down.pixel.y) - { - fy = down.pixel.y; - } - else if (fy > up.pixel.y) - { - fy = up.pixel.y; - } - fy = fy - down.pixel.y; - - current.y = cury; - _scanInterpolate(area->renderer->render_camera, &down, &diff, fy / dy, ¤t); - - Vector3 veclocation = Vector3(current.location.x, current.location.y, current.location.z); - area->pushFragment(current.x, current.y, current.pixel.z, (cury == starty || cury == endy), veclocation, current.callback); - } - } - } -} - -void RenderArea::pushTriangle(const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3, f_RenderFragmentCallback callback, void* callback_data) -{ - FragmentCallback fragment_callback = {callback, callback_data}; - ScanPoint point1, point2, point3; - double limit_width = (double)(params.width * params.antialias - 1); - double limit_height = (double)(params.height * params.antialias - 1); - - /* Filter if outside screen */ - if (pixel1.z < 1.0 || pixel2.z < 1.0 || pixel3.z < 1.0 || (pixel1.x < 0.0 && pixel2.x < 0.0 && pixel3.x < 0.0) || (pixel1.y < 0.0 && pixel2.y < 0.0 && pixel3.y < 0.0) || (pixel1.x > limit_width && pixel2.x > limit_width && pixel3.x > limit_width) || (pixel1.y > limit_height && pixel2.y > limit_height && pixel3.y > limit_height)) - { - return; - } - - /* Prepare fragment callback */ - lock->acquire(); - point1.callback = _pushCallback(this, fragment_callback); - lock->release(); - - /* Prepare vertices */ - point1.pixel.x = pixel1.x; - point1.pixel.y = pixel1.y; - point1.pixel.z = pixel1.z; - point1.location.x = location1.x; - point1.location.y = location1.y; - point1.location.z = location1.z; - - point2.pixel.x = pixel2.x; - point2.pixel.y = pixel2.y; - point2.pixel.z = pixel2.z; - point2.location.x = location2.x; - point2.location.y = location2.y; - point2.location.z = location2.z; - point2.callback = point1.callback; - - point3.pixel.x = pixel3.x; - point3.pixel.y = pixel3.y; - point3.pixel.z = pixel3.z; - point3.location.x = location3.x; - point3.location.y = location3.y; - point3.location.z = location3.z; - point3.callback = point1.callback; - - /* Prepare scanlines */ - // TODO Don't create scanlines for each triangles (one by thread is more appropriate) - RenderScanlines scanlines; - int width = params.width * params.antialias; - scanlines.left = width; - scanlines.right = -1; - scanlines.up = new ScanPoint[width]; - scanlines.down = new ScanPoint[width]; - - /* Render edges in scanlines */ - _pushScanLineEdge(this, &scanlines, &point1, &point2); - _pushScanLineEdge(this, &scanlines, &point2, &point3); - _pushScanLineEdge(this, &scanlines, &point3, &point1); - - /* Commit scanlines to area */ - lock->acquire(); - _renderScanLines(this, &scanlines); - lock->release(); - - /* Free scalines */ - delete[] scanlines.up; - delete[] scanlines.down; -} - -Color RenderArea::getPixel(int x, int y) -{ - Color result; - - lock->acquire(); - result = _getFinalPixel(this, x, y); - lock->release(); - - return result; -} - -void* _renderPostProcessChunk(void* data) -{ - int x, y; - RenderFragment* fragment; - RenderChunk* chunk = (RenderChunk*)data; - - for (x = chunk->startx; x <= chunk->endx; x++) -{ - for (y = chunk->starty; y <= chunk->endy; y++) - { - fragment = chunk->area->pixels + (y * chunk->area->params.width * chunk->area->params.antialias + x); - if (fragment->flags.dirty) - { - FragmentCallback callback; - Color col; - - callback = chunk->area->fragment_callbacks[fragment->flags.callback]; - if (callback.function) - { - Vector3 location(fragment->data.location.x, fragment->data.location.y, fragment->data.location.z); - col = callback.function(chunk->area->renderer, location, callback.data); - /*colorNormalize(&col);*/ - } - else - { - col = COLOR_BLACK; - } - - fragment->data.color.r = col.r; - fragment->data.color.g = col.g; - fragment->data.color.b = col.b; - - chunk->area->lock->acquire(); - fragment->flags.dirty = 0; - _setDirtyPixel(chunk->area, x, y); - chunk->area->lock->release(); - } - chunk->area->pixel_done++; - } - if (chunk->interrupt) - { - break; - } - } - - chunk->finished = 1; - return NULL; -} - -#define MAX_CHUNKS 8 -void RenderArea::postProcess(int nbchunks) -{ - volatile RenderChunk chunks[MAX_CHUNKS]; - int i; - int x, y, dx, dy, nx, ny; - int loops, running; - - if (nbchunks > MAX_CHUNKS) - { - nbchunks = MAX_CHUNKS; - } - if (nbchunks < 1) - { - nbchunks = 1; - } - - nx = 10; - ny = 10; - dx = params.width * params.antialias / nx; - dy = params.height * params.antialias / ny; - x = 0; - y = 0; - pixel_done = 0; - - for (i = 0; i < nbchunks; i++) - { - chunks[i].thread = NULL; - chunks[i].area = this; - } - - running = 0; - loops = 0; - while ((x < nx && !renderer->render_interrupt) || running > 0) - { - Thread::timeSleepMs(50); - - for (i = 0; i < nbchunks; i++) - { - if (chunks[i].thread) - { - if (chunks[i].finished) - { - chunks[i].thread->join(); - delete chunks[i].thread; - chunks[i].thread = NULL; - running--; - } - else if (renderer->render_interrupt) - { - chunks[i].interrupt = 1; - } - } - - renderer->render_progress = 0.1 + ((double)pixel_done / (double)pixel_count) * 0.9; - - if (x < nx && !chunks[i].thread && !renderer->render_interrupt) - { - chunks[i].finished = 0; - chunks[i].interrupt = 0; - chunks[i].startx = x * dx; - if (x == nx - 1) - { - chunks[i].endx = params.width * params.antialias - 1; - } - else - { - chunks[i].endx = (x + 1) * dx - 1; - } - chunks[i].starty = y * dy; - if (y == ny - 1) - { - chunks[i].endy = params.height * params.antialias - 1; - } - else - { - chunks[i].endy = (y + 1) * dy - 1; - } - - chunks[i].thread = new Thread(_renderPostProcessChunk); - chunks[i].thread->start((void*)(chunks + i)); - running++; - - if (++y >= ny) - { - x++; - y = 0; - } - } - } - - if (++loops >= 10) - { - lock->acquire(); - processDirtyPixels(); - lock->release(); - - loops = 0; - } - } - - processDirtyPixels(); - callback_update(1.0); -} - -class RenderWriter:public PictureWriter -{ -public: - RenderWriter(RenderArea *area): area(area) {} - - virtual unsigned int getPixel(int x, int y) override - { - Color result = _getFinalPixel(area, x, y); - result.normalize(); - return result.to32BitBGRA(); - } -private: - RenderArea *area; -}; - -int RenderArea::saveToFile(const std::string &path) -{ - RenderWriter writer(this); - return writer.save(path, params.width, params.height); -} - -void RenderArea::setPreviewCallbacks(RenderCallbackStart start, RenderCallbackDraw draw, RenderCallbackUpdate update) -{ - callback_start = start ? start : _callbackStart; - callback_draw = draw ? draw : _callbackDraw; - callback_update = update ? update : _callbackUpdate; - - callback_start(params.width, params.height, background_color); - - setAllDirty(); - processDirtyPixels(); - - callback_update(0.0); -} diff --git a/src/render/software/RenderArea.h b/src/render/software/RenderArea.h deleted file mode 100644 index 8bcb826..0000000 --- a/src/render/software/RenderArea.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef RENDERAREA_H -#define RENDERAREA_H - -#include "software_global.h" - -#include "Color.h" - -typedef struct RenderFragment RenderFragment; -typedef struct FragmentCallback FragmentCallback; - -namespace paysages { -namespace software { - -class SOFTWARESHARED_EXPORT RenderArea -{ -public: - typedef struct - { - int width; - int height; - int antialias; - int quality; - } RenderParams; - - typedef Color (*f_RenderFragmentCallback)(SoftwareRenderer* renderer, const Vector3 &location, void* data); - typedef void (*RenderCallbackStart)(int width, int height, const Color &background); - typedef void (*RenderCallbackDraw)(int x, int y, const Color &col); - typedef void (*RenderCallbackUpdate)(double progress); - -public: - RenderArea(SoftwareRenderer* parent); - ~RenderArea(); - - void setParams(RenderParams params); - void setToneMapping(const ColorProfile &profile); - void setBackgroundColor(const Color& col); - void clear(); - void update(); - - void pushTriangle(const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3, f_RenderFragmentCallback callback, void* callback_data); - - Color getPixel(int x, int y); - - void postProcess(int nbchunks); - int saveToFile(const std::string &path); - void setPreviewCallbacks(RenderCallbackStart start, RenderCallbackDraw draw, RenderCallbackUpdate update); - - void setAllDirty(); - void processDirtyPixels(); - void pushFragment(int x, int y, double z, int edge, const Vector3 &location, int callback); - -public: - ColorProfile* hdr_mapping; - SoftwareRenderer* renderer; - RenderParams params; - int pixel_count; - int pixel_done; - RenderFragment* pixels; - int fragment_callbacks_count; - FragmentCallback* fragment_callbacks; - Color background_color; - volatile int dirty_left; - volatile int dirty_right; - volatile int dirty_up; - volatile int dirty_down; - volatile int dirty_count; - Mutex* lock; - RenderCallbackStart callback_start; - RenderCallbackDraw callback_draw; - RenderCallbackUpdate callback_update; -}; - -} -} - -#endif // RENDERAREA_H diff --git a/src/render/software/RenderConfig.cpp b/src/render/software/RenderConfig.cpp new file mode 100644 index 0000000..c4f67ca --- /dev/null +++ b/src/render/software/RenderConfig.cpp @@ -0,0 +1,30 @@ +#include "RenderConfig.h" + +RenderConfig::RenderConfig(int width, int height, int antialias, int quality): + width(width), height(height), antialias(antialias), quality(quality) +{ + if (this->width <= 0) + { + this->width = 400; + } + if (this->height <= 0) + { + this->height = this->width * 4 / 3; + } + if (this->antialias < 1) + { + this->antialias = 1; + } + if (this->antialias > 4) + { + this->antialias = 4; + } + if (this->quality < 1) + { + this->quality = 1; + } + if (this->quality > 10) + { + this->quality = 10; + } +} diff --git a/src/render/software/RenderConfig.h b/src/render/software/RenderConfig.h new file mode 100644 index 0000000..558b5b3 --- /dev/null +++ b/src/render/software/RenderConfig.h @@ -0,0 +1,23 @@ +#ifndef RENDERCONFIG_H +#define RENDERCONFIG_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +class SOFTWARESHARED_EXPORT RenderConfig +{ +public: + RenderConfig(int width=0, int height=0, int antialias=1, int quality=5); + + int width; + int height; + int antialias; + int quality; +}; + +} +} + +#endif // RENDERCONFIG_H diff --git a/src/render/software/SkyRasterizer.cpp b/src/render/software/SkyRasterizer.cpp index b0016a3..4bb6719 100644 --- a/src/render/software/SkyRasterizer.cpp +++ b/src/render/software/SkyRasterizer.cpp @@ -30,61 +30,6 @@ static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &loc return result; } -void SkyRasterizer::rasterize() -{ - int res_i, res_j; - int i, j; - double step_i, step_j; - double current_i, current_j; - Vector3 vertex1, vertex2, vertex3, vertex4; - Vector3 camera_location, direction; - - res_i = renderer->render_quality * 40; - res_j = renderer->render_quality * 20; - step_i = M_PI * 2.0 / (double)res_i; - step_j = M_PI / (double)res_j; - - camera_location = renderer->getCameraLocation(VECTOR_ZERO); - - for (j = 0; j < res_j; j++) - { - if (!renderer->addRenderProgress(0.0)) - { - return; - } - - current_j = (double)(j - res_j / 2) * step_j; - - for (i = 0; i < res_i; i++) - { - current_i = (double)i * step_i; - - direction.x = SPHERE_SIZE * cos(current_i) * cos(current_j); - direction.y = SPHERE_SIZE * sin(current_j); - direction.z = SPHERE_SIZE * sin(current_i) * cos(current_j); - vertex1 = camera_location.add(direction); - - direction.x = SPHERE_SIZE * cos(current_i + step_i) * cos(current_j); - direction.y = SPHERE_SIZE * sin(current_j); - direction.z = SPHERE_SIZE * sin(current_i + step_i) * cos(current_j); - vertex2 = camera_location.add(direction); - - direction.x = SPHERE_SIZE * cos(current_i + step_i) * cos(current_j + step_j); - direction.y = SPHERE_SIZE * sin(current_j + step_j); - direction.z = SPHERE_SIZE * sin(current_i + step_i) * cos(current_j + step_j); - vertex3 = camera_location.add(direction); - - direction.x = SPHERE_SIZE * cos(current_i) * cos(current_j + step_j); - direction.y = SPHERE_SIZE * sin(current_j + step_j); - direction.z = SPHERE_SIZE * sin(current_i) * cos(current_j + step_j); - vertex4 = camera_location.add(direction); - - /* TODO Triangles at poles */ - renderer->pushQuad(vertex1, vertex4, vertex3, vertex2, _postProcessFragment, NULL); - } - } -} - void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas) { int res_i, res_j; diff --git a/src/render/software/SkyRasterizer.h b/src/render/software/SkyRasterizer.h index 3184df3..0e44b76 100644 --- a/src/render/software/SkyRasterizer.h +++ b/src/render/software/SkyRasterizer.h @@ -13,7 +13,6 @@ class SOFTWARESHARED_EXPORT SkyRasterizer: public Rasterizer public: SkyRasterizer(SoftwareRenderer* renderer, int client_id); - virtual void rasterize(); virtual void rasterizeToCanvas(CanvasPortion* canvas); }; diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 3a626d4..0252be6 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -13,9 +13,9 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer() started = false; canvas = new Canvas(); - rasterizers.push_back(new TerrainRasterizer(this, 0)); + rasterizers.push_back(new SkyRasterizer(this, 0)); rasterizers.push_back(new WaterRasterizer(this, 1)); - rasterizers.push_back(new SkyRasterizer(this, 2)); + rasterizers.push_back(new TerrainRasterizer(this, 2)); } SoftwareCanvasRenderer::~SoftwareCanvasRenderer() @@ -41,6 +41,9 @@ void SoftwareCanvasRenderer::render() // TEMP started = true; CanvasPortion *portion = canvas->at(0, 0); + render_width = canvas->getWidth(); + render_height = canvas->getHeight(); + render_quality = 3; render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight()); diff --git a/src/render/software/SoftwareRenderer.cpp b/src/render/software/SoftwareRenderer.cpp index 2af4f4a..3ab791b 100644 --- a/src/render/software/SoftwareRenderer.cpp +++ b/src/render/software/SoftwareRenderer.cpp @@ -22,8 +22,6 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery) { - RenderArea::RenderParams params = {1, 1, 1, 5}; - render_quality = 5; render_width = 1; render_height = 1; @@ -31,8 +29,6 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery) render_progress = 0.0; is_rendering = 0; render_camera = new CameraDefinition; - render_area = new RenderArea(this); - render_area->setParams(params); atmosphere_renderer = new BaseAtmosphereRenderer(this); clouds_renderer = new CloudsRenderer(this); @@ -59,7 +55,6 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery) SoftwareRenderer::~SoftwareRenderer() { delete render_camera; - delete render_area; delete fluid_medium; delete lighting; @@ -108,18 +103,6 @@ void SoftwareRenderer::prepare() //fluid_medium->registerMedium(water_renderer); } -void SoftwareRenderer::rasterize() -{ - TerrainRasterizer terrain(this, 0); - terrain.rasterize(); - - WaterRasterizer water(this, 1); - water.rasterize(); - - SkyRasterizer sky(this, 2); - sky.rasterize(); -} - void SoftwareRenderer::disableClouds() { scenery->getClouds()->clear(); @@ -164,63 +147,6 @@ void SoftwareRenderer::disableAtmosphere(const std::vector &ligh atmosphere_renderer->setStaticLights(lights); } -void SoftwareRenderer::setPreviewCallbacks(RenderArea::RenderCallbackStart start, RenderArea::RenderCallbackDraw draw, RenderArea::RenderCallbackUpdate update) -{ - render_area->setPreviewCallbacks(start, draw, update); -} - -static void* _renderFirstPass(void* data) -{ - SoftwareRenderer* renderer = (SoftwareRenderer*)data; - renderer->rasterize(); - renderer->is_rendering = 0; - return NULL; -} - -void SoftwareRenderer::start(RenderArea::RenderParams params) -{ - Thread thread(_renderFirstPass); - int loops; - int core_count = System::getCoreCount(); - - params.antialias = (params.antialias < 1) ? 1 : params.antialias; - params.antialias = (params.antialias > 4) ? 4 : params.antialias; - - render_quality = params.quality; - render_width = params.width * params.antialias; - render_height = params.height * params.antialias; - render_interrupt = 0; - render_progress = 0.0; - - prepare(); - - render_camera->setRenderSize(render_width, render_height); - - render_area->setBackgroundColor(COLOR_BLACK); - render_area->setParams(params); - render_area->clear(); - - is_rendering = 1; - thread.start(this); - loops = 0; - - while (is_rendering) - { - Thread::timeSleepMs(100); - - if (++loops >= 10) - { - render_area->update(); - loops = 0; - } - } - thread.join(); - - is_rendering = 1; - render_area->postProcess(core_count); - is_rendering = 0; -} - void SoftwareRenderer::interrupt() { render_interrupt = 1; @@ -296,37 +222,3 @@ Vector3 SoftwareRenderer::unprojectPoint(const Vector3 &point) { return render_camera->unproject(point); } - -void SoftwareRenderer::pushTriangle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, RenderArea::f_RenderFragmentCallback callback, void* callback_data) -{ - Vector3 p1, p2, p3; - - p1 = projectPoint(v1); - p2 = projectPoint(v2); - p3 = projectPoint(v3); - - render_area->pushTriangle(p1, p2, p3, v1, v2, v3, callback, callback_data); -} - -void SoftwareRenderer::pushQuad(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4, RenderArea::f_RenderFragmentCallback callback, void* callback_data) -{ - pushTriangle(v2, v3, v1, callback, callback_data); - pushTriangle(v4, v1, v3, callback, callback_data); -} - -void SoftwareRenderer::pushDisplacedTriangle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3, RenderArea::f_RenderFragmentCallback callback, void* callback_data) -{ - Vector3 p1, p2, p3; - - p1 = projectPoint(v1); - p2 = projectPoint(v2); - p3 = projectPoint(v3); - - render_area->pushTriangle(p1, p2, p3, ov1, ov2, ov3, callback, callback_data); -} - -void SoftwareRenderer::pushDisplacedQuad(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3, const Vector3 &ov4, RenderArea::f_RenderFragmentCallback callback, void* callback_data) -{ - pushDisplacedTriangle(v2, v3, v1, ov2, ov3, ov1, callback, callback_data); - pushDisplacedTriangle(v4, v1, v3, ov4, ov1, ov3, callback, callback_data); -} diff --git a/src/render/software/SoftwareRenderer.h b/src/render/software/SoftwareRenderer.h index 9f269f3..04f8ded 100644 --- a/src/render/software/SoftwareRenderer.h +++ b/src/render/software/SoftwareRenderer.h @@ -3,7 +3,6 @@ #include "software_global.h" -#include "RenderArea.h" #include "RayCastingManager.h" namespace paysages { @@ -26,7 +25,6 @@ public: CameraDefinition* render_camera; /* Render related */ - RenderArea* render_area; double render_progress; int render_interrupt; int is_rendering; @@ -39,10 +37,6 @@ public: virtual Vector3 projectPoint(const Vector3 &point); virtual Vector3 unprojectPoint(const Vector3 &point); virtual int addRenderProgress(double progress); - virtual void pushTriangle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, RenderArea::f_RenderFragmentCallback callback, void* callback_data); - virtual void pushQuad(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4, RenderArea::f_RenderFragmentCallback callback, void* callback_data); - virtual void pushDisplacedTriangle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3, RenderArea::f_RenderFragmentCallback callback, void* callback_data); - virtual void pushDisplacedQuad(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3, const Vector3 &ov4, RenderArea::f_RenderFragmentCallback callback, void* callback_data); /*! * \brief Set the scenery to render. @@ -59,11 +53,6 @@ public: */ virtual void prepare(); - /*! - * \brief Start the rasterization process. - */ - virtual void rasterize(); - /*! * \brief Disable the clouds feature. * @@ -78,8 +67,6 @@ public: void disableAtmosphere(); void disableAtmosphere(const std::vector &lights); - void setPreviewCallbacks(RenderArea::RenderCallbackStart start, RenderArea::RenderCallbackDraw draw, RenderArea::RenderCallbackUpdate update); - void start(RenderArea::RenderParams params); void interrupt(); inline Scenery* getScenery() const {return scenery;} diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index 143b208..0aa386c 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -8,6 +8,7 @@ #include "TexturesRenderer.h" #include "Scenery.h" #include "ParallelQueue.h" +#include "CanvasPortion.h" TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id): Rasterizer(renderer, client_id) @@ -25,7 +26,30 @@ static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &poi return renderer->getTerrainRenderer()->getFinalColor(point, precision); } -static void _renderQuad(SoftwareRenderer* renderer, double x, double z, double size, double water_height) +void TerrainRasterizer::tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail) +{ + if (detail < 1) + { + return; + } + + double water_height = renderer->getWaterRenderer()->getHeightInfo().min_height; + + double startx = chunk->point_nw.x; + double startz = chunk->point_nw.z; + double size = (chunk->point_ne.x - chunk->point_nw.x) / (double)detail; + int i, j; + + for (i = 0; i < detail; i++) + { + for (j = 0; j < detail; j++) + { + renderQuad(canvas, startx + (double)i * size, startz + (double)j * size, size, water_height); + } + } +} + +void TerrainRasterizer::renderQuad(CanvasPortion *canvas, double x, double z, double size, double water_height) { Vector3 ov1, ov2, ov3, ov4; Vector3 dv1, dv2, dv3, dv4; @@ -50,30 +74,7 @@ static void _renderQuad(SoftwareRenderer* renderer, double x, double z, double s if (dv1.y > water_height || dv2.y > water_height || dv3.y > water_height || dv4.y > water_height) { - renderer->pushDisplacedQuad(dv1, dv2, dv3, dv4, ov1, ov2, ov3, ov4, _postProcessFragment, NULL); - } -} - -void TerrainRasterizer::tessellateChunk(TerrainChunkInfo* chunk, int detail) -{ - if (detail < 1) - { - return; - } - - double water_height = renderer->getWaterRenderer()->getHeightInfo().min_height; - - double startx = chunk->point_nw.x; - double startz = chunk->point_nw.z; - double size = (chunk->point_ne.x - chunk->point_nw.x) / (double)detail; - int i, j; - - for (i = 0; i < detail; i++) - { - for (j = 0; j < detail; j++) - { - _renderQuad(renderer, startx + (double)i * size, startz + (double)j * size, size, water_height); - } + pushDisplacedQuad(canvas, dv1, dv2, dv3, dv4, ov1, ov2, ov3, ov4); } } @@ -130,7 +131,7 @@ static void _getChunk(SoftwareRenderer* renderer, TerrainRasterizer::TerrainChun } } -void TerrainRasterizer::getTessellationInfo(int displaced) +void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, int displaced) { TerrainChunkInfo chunk; int chunk_factor, chunk_count, i; @@ -157,25 +158,25 @@ void TerrainRasterizer::getTessellationInfo(int displaced) for (i = 0; i < chunk_count - 1; i++) { _getChunk(renderer, &chunk, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size, displaced); - if (!processChunk(&chunk, progress)) + if (!processChunk(canvas, &chunk, progress)) { return; } _getChunk(renderer, &chunk, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size, displaced); - if (!processChunk(&chunk, progress)) + if (!processChunk(canvas, &chunk, progress)) { return; } _getChunk(renderer, &chunk, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size, displaced); - if (!processChunk(&chunk, progress)) + if (!processChunk(canvas, &chunk, progress)) { return; } _getChunk(renderer, &chunk, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size, displaced); - if (!processChunk(&chunk, progress)) + if (!processChunk(canvas, &chunk, progress)) { return; } @@ -196,6 +197,7 @@ void TerrainRasterizer::getTessellationInfo(int displaced) typedef struct { TerrainRasterizer* rasterizer; + CanvasPortion *canvas; TerrainRasterizer::TerrainChunkInfo chunk; } ParallelRasterInfo; @@ -205,18 +207,19 @@ static int _parallelJobCallback(ParallelQueue*, int, void* data, int stopping) if (!stopping) { - info->rasterizer->tessellateChunk(&info->chunk, info->chunk.detail_hint); + info->rasterizer->tessellateChunk(info->canvas, &info->chunk, info->chunk.detail_hint); } delete info; return 0; } -int TerrainRasterizer::processChunk(TerrainChunkInfo* chunk, double progress) +int TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double progress) { ParallelRasterInfo* info = new ParallelRasterInfo; info->rasterizer = this; + info->canvas = canvas; info->chunk = *chunk; if (!queue->addJob(_parallelJobCallback, info)) @@ -230,16 +233,15 @@ int TerrainRasterizer::processChunk(TerrainChunkInfo* chunk, double progress) void TerrainRasterizer::rasterize() { - queue = new ParallelQueue(); - - renderer->render_progress = 0.0; - getTessellationInfo(0); - renderer->render_progress = 0.05; - - queue->wait(); } void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas) { + queue = new ParallelQueue(); + renderer->render_progress = 0.0; + getTessellationInfo(canvas, 0); + renderer->render_progress = 0.05; + + queue->wait(); } diff --git a/src/render/software/TerrainRasterizer.h b/src/render/software/TerrainRasterizer.h index 9528958..af8b020 100644 --- a/src/render/software/TerrainRasterizer.h +++ b/src/render/software/TerrainRasterizer.h @@ -27,19 +27,21 @@ public: /** * Method called for each chunk tessellated by getTessellationInfo. */ - int processChunk(TerrainChunkInfo* chunk, double progress); + int processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double progress); /** * Tessellate the terrain, calling processChunk for each chunk. * * The terrain will be broken in chunks, most detailed near the camera. */ - void getTessellationInfo(int displaced); + void getTessellationInfo(CanvasPortion* canvas, int displaced); /** * Tessellate a terrain chunk, pushing the quads in the render area. */ - void tessellateChunk(TerrainChunkInfo* chunk, int detail); + void tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail); + + void renderQuad(CanvasPortion* canvas, double x, double z, double size, double water_height); /** * Start the final rasterization of terrain. diff --git a/src/render/software/WaterRasterizer.cpp b/src/render/software/WaterRasterizer.cpp index 0df1c9f..9af4ef4 100644 --- a/src/render/software/WaterRasterizer.cpp +++ b/src/render/software/WaterRasterizer.cpp @@ -25,110 +25,6 @@ static inline Vector3 _getFirstPassVertex(SoftwareRenderer* renderer, double x, return result; } -static void _renderQuad(SoftwareRenderer* renderer, double x, double z, double size) -{ - Vector3 v1, v2, v3, v4; - - v1 = _getFirstPassVertex(renderer, x, z); - v2 = _getFirstPassVertex(renderer, x, z + size); - v3 = _getFirstPassVertex(renderer, x + size, z + size); - v4 = _getFirstPassVertex(renderer, x + size, z); - - renderer->pushQuad(v1, v2, v3, v4, _postProcessFragment, NULL); -} - -typedef struct -{ - SoftwareRenderer* renderer; - int i; - double cx; - double cz; - double radius_int; - double chunk_size; - double radius_ext; -} ParallelRasterInfo; - -static int _parallelJobCallback(ParallelQueue*, int, void* data, int stopping) -{ - ParallelRasterInfo* info = (ParallelRasterInfo*)data; - - if (!stopping) - { - _renderQuad(info->renderer, info->cx - info->radius_ext + info->chunk_size * info->i, info->cz - info->radius_ext, info->chunk_size); - _renderQuad(info->renderer, info->cx + info->radius_int, info->cz - info->radius_ext + info->chunk_size * info->i, info->chunk_size); - _renderQuad(info->renderer, info->cx + info->radius_int - info->chunk_size * info->i, info->cz + info->radius_int, info->chunk_size); - _renderQuad(info->renderer, info->cx - info->radius_ext, info->cz + info->radius_int - info->chunk_size * info->i, info->chunk_size); - } - - delete info; - return 0; -} - -void WaterRasterizer::rasterize() -{ - ParallelRasterInfo* info; - ParallelQueue* queue; - queue = new ParallelQueue(); - - int chunk_factor, chunk_count, i; - Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO); - double radius_int, radius_ext, base_chunk_size, chunk_size; - - base_chunk_size = 2.0 / (double)renderer->render_quality; - if (renderer->render_quality > 7) - { - base_chunk_size *= 0.5; - } - - chunk_factor = 1; - chunk_count = 2; - radius_int = 0.0; - radius_ext = base_chunk_size; - chunk_size = base_chunk_size; - - double cx = cam.x - fmod(cam.x, base_chunk_size); - double cz = cam.z - fmod(cam.x, base_chunk_size); - - while (radius_int < 20000.0) - { - if (!renderer->addRenderProgress(0.0)) - { - return; - } - - for (i = 0; i < chunk_count - 1; i++) - { - info = new ParallelRasterInfo; - - info->renderer = renderer; - info->cx = cx; - info->cz = cz; - info->i = i; - info->radius_int = radius_int; - info->radius_ext = radius_ext; - info->chunk_size = chunk_size; - - if (!queue->addJob(_parallelJobCallback, info)) - { - delete info; - } - } - - if (radius_int > 20.0 && chunk_count % 64 == 0 && (double)chunk_factor < radius_int / 20.0) - { - chunk_count /= 2; - chunk_factor *= 2; - } - chunk_count += 2; - chunk_size = base_chunk_size * chunk_factor; - radius_int = radius_ext; - radius_ext += chunk_size; - } - - queue->wait(); - delete queue; -} - void WaterRasterizer::rasterizeQuad(CanvasPortion* canvas, double x, double z, double size) { Vector3 v1, v2, v3, v4; diff --git a/src/render/software/WaterRasterizer.h b/src/render/software/WaterRasterizer.h index 98e4450..e8cda24 100644 --- a/src/render/software/WaterRasterizer.h +++ b/src/render/software/WaterRasterizer.h @@ -15,8 +15,6 @@ public: void rasterizeQuad(CanvasPortion* canvas, double x, double z, double size); - virtual void rasterize(); - virtual void rasterizeToCanvas(CanvasPortion* canvas); }; diff --git a/src/render/software/software.pro b/src/render/software/software.pro index 444a395..8f6ba50 100644 --- a/src/render/software/software.pro +++ b/src/render/software/software.pro @@ -34,7 +34,6 @@ SOURCES += SoftwareRenderer.cpp \ TerrainRenderer.cpp \ TexturesRenderer.cpp \ WaterRenderer.cpp \ - RenderArea.cpp \ RayCastingManager.cpp \ NightSky.cpp \ TerrainRayWalker.cpp \ @@ -45,7 +44,8 @@ SOURCES += SoftwareRenderer.cpp \ SoftwareCanvasRenderer.cpp \ Rasterizer.cpp \ CanvasLiveClient.cpp \ - CanvasPreview.cpp + CanvasPreview.cpp \ + RenderConfig.cpp HEADERS += SoftwareRenderer.h\ software_global.h \ @@ -69,7 +69,6 @@ HEADERS += SoftwareRenderer.h\ TerrainRenderer.h \ TexturesRenderer.h \ WaterRenderer.h \ - RenderArea.h \ RayCastingManager.h \ NightSky.h \ TerrainRayWalker.h \ @@ -80,7 +79,8 @@ HEADERS += SoftwareRenderer.h\ SoftwareCanvasRenderer.h \ Rasterizer.h \ CanvasLiveClient.h \ - CanvasPreview.h + CanvasPreview.h \ + RenderConfig.h unix:!symbian { maemo5 { diff --git a/src/render/software/software_global.h b/src/render/software/software_global.h index 419a378..fc6a3fd 100644 --- a/src/render/software/software_global.h +++ b/src/render/software/software_global.h @@ -15,7 +15,7 @@ namespace paysages { namespace software { class SoftwareRenderer; class SoftwareCanvasRenderer; - class RenderArea; + class RenderConfig; class FluidMediumManager; class FluidMediumInterface; diff --git a/src/tests/Bruneton_Test.cpp b/src/tests/Bruneton_Test.cpp index 70d49d9..dcce68a 100644 --- a/src/tests/Bruneton_Test.cpp +++ b/src/tests/Bruneton_Test.cpp @@ -31,7 +31,7 @@ TEST(Bruneton, AerialPerspective1) renderer.render_camera->setTarget(VECTOR_EAST); renderer.render_camera->setRenderSize(renderer.render_width, renderer.render_height); - RenderArea::RenderParams params = {renderer.render_width, renderer.render_height, 1, 1}; + /*RenderArea::RenderParams params = {renderer.render_width, renderer.render_height, 1, 1}; renderer.render_area->setParams(params); renderer.render_area->setBackgroundColor(COLOR_BLACK); renderer.render_area->clear(); @@ -43,7 +43,7 @@ TEST(Bruneton, AerialPerspective1) renderer.pushQuad(Vector3(30.0, -10.0, 25.0), Vector3(30.0, -10.0, 30.0), Vector3(30.0, 50.0, 30.0), Vector3(30.0, 50.0, 25.0), _postProcessFragment, NULL); renderer.render_area->postProcess(System::getCoreCount()); - renderer.render_area->saveToFile("./output/test_bruneton_perspective.png"); + renderer.render_area->saveToFile("./output/test_bruneton_perspective.png");*/ } TEST(Bruneton, AerialPerspective2) @@ -67,7 +67,7 @@ TEST(Bruneton, AerialPerspective2) renderer.render_camera->setTarget(VECTOR_EAST); renderer.render_camera->setRenderSize(renderer.render_width, renderer.render_height); - RenderArea::RenderParams params = {renderer.render_width, renderer.render_height, 1, 1}; + /*RenderArea::RenderParams params = {renderer.render_width, renderer.render_height, 1, 1}; renderer.render_area->setParams(params); renderer.render_area->setBackgroundColor(COLOR_BLACK); renderer.render_area->clear(); @@ -79,5 +79,5 @@ TEST(Bruneton, AerialPerspective2) renderer.pushQuad(Vector3(30.0, -10.0, 25.0), Vector3(30.0, -10.0, 30.0), Vector3(30.0, 50.0, 30.0), Vector3(30.0, 50.0, 25.0), _postProcessFragment, NULL); renderer.render_area->postProcess(System::getCoreCount()); - renderer.render_area->saveToFile("./output/test_bruneton_perspective1.png"); + renderer.render_area->saveToFile("./output/test_bruneton_perspective1.png");*/ } diff --git a/src/tests/Render_Test.cpp b/src/tests/Render_Test.cpp index e1914fb..a98803d 100644 --- a/src/tests/Render_Test.cpp +++ b/src/tests/Render_Test.cpp @@ -34,19 +34,19 @@ static void _render_quad_checker(SoftwareRenderer &renderer) renderer.render_width = 800; renderer.render_height = 600; renderer.render_quality = 1; - renderer.render_area->setToneMapping(ColorProfile(ColorProfile::TONE_MAPPING_CLAMP, 0.0)); + //renderer.render_area->setToneMapping(ColorProfile(ColorProfile::TONE_MAPPING_CLAMP, 0.0)); renderer.render_camera->setRenderSize(renderer.render_width, renderer.render_height); renderer.render_camera->setFov(1.57); - RenderArea::RenderParams params = {renderer.render_width, renderer.render_height, 1, 1}; + /*RenderConfig params(renderer.render_width, renderer.render_height, 1, 1); renderer.render_area->setParams(params); renderer.render_area->setBackgroundColor(COLOR_BLUE); renderer.render_area->clear(); renderer.pushQuad(Vector3(-1.0, 0.0, 1.0), Vector3(-1.0, 0.0, -1.0), Vector3(1.0, 0.0, -1.0), Vector3(1.0, 0.0, 1.0), _postProcessFragment, NULL); - renderer.render_area->postProcess(System::getCoreCount()); + renderer.render_area->postProcess(System::getCoreCount());*/ } TEST(Render, quad) @@ -61,7 +61,7 @@ TEST(Render, quad) _render_quad_checker(renderer); - Color col; + /*Color col; col = renderer.render_area->getPixel(399, 599 - 435); ASSERT_COLOR_RGBA(col, 1.0, 1.0, 1.0, 1.0); col = renderer.render_area->getPixel(399, 599 - 436); @@ -71,7 +71,7 @@ TEST(Render, quad) col = renderer.render_area->getPixel(400, 599 - 436); ASSERT_COLOR_RGBA(col, 1.0, 1.0, 1.0, 1.0); - renderer.render_area->saveToFile("./output/test_render_quad.png"); + renderer.render_area->saveToFile("./output/test_render_quad.png");*/ } TEST(Render, quad_cut) @@ -86,5 +86,5 @@ TEST(Render, quad_cut) _render_quad_checker(renderer); - renderer.render_area->saveToFile("./output/test_render_quad_cut.png"); + //renderer.render_area->saveToFile("./output/test_render_quad_cut.png"); } From b86669c5a0f0234f234c71166e4aed5a28f25428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sat, 16 Aug 2014 13:34:55 +0200 Subject: [PATCH 06/29] Added color to rasterized polygons --- src/render/software/Rasterizer.cpp | 11 +++++++++-- src/render/software/Rasterizer.h | 3 ++- src/render/software/SkyRasterizer.cpp | 2 +- src/render/software/TerrainRasterizer.cpp | 2 +- src/render/software/WaterRasterizer.cpp | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index f54a8c6..e2b48b4 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -31,13 +31,15 @@ struct paysages::software::RenderScanlines int right; }; -Rasterizer::Rasterizer(SoftwareRenderer* renderer, int client_id): +Rasterizer::Rasterizer(SoftwareRenderer* renderer, int client_id, const Color &color): renderer(renderer), client_id(client_id) { + this->color = new Color(color); } Rasterizer::~Rasterizer() { + delete color; } void Rasterizer::pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3) @@ -329,7 +331,12 @@ void Rasterizer::renderScanLines(CanvasPortion *canvas, RenderScanlines* scanlin scanInterpolate(renderer->render_camera, &down, &diff, fy / dy, ¤t); CanvasFragment fragment(current.pixel.z, Vector3(current.location.x, current.location.y, current.location.z), current.client); - fragment.setColor((cury == starty || cury == endy) ? COLOR_GREY : COLOR_WHITE); + + Color frag_color = *color; + if (cury == starty || cury == endy) + frag_color.mask(Color(0.0, 0.0, 0.0, 0.3)); + fragment.setColor(frag_color); + canvas->pushFragment(current.x, current.y, fragment); } } diff --git a/src/render/software/Rasterizer.h b/src/render/software/Rasterizer.h index 1bb410c..4e237f1 100644 --- a/src/render/software/Rasterizer.h +++ b/src/render/software/Rasterizer.h @@ -15,7 +15,7 @@ typedef struct RenderScanlines RenderScanlines; class SOFTWARESHARED_EXPORT Rasterizer { public: - Rasterizer(SoftwareRenderer *renderer, int client_id); + Rasterizer(SoftwareRenderer *renderer, int client_id, const Color &color); virtual ~Rasterizer(); inline SoftwareRenderer *getRenderer() const {return renderer;} @@ -30,6 +30,7 @@ protected: void pushDisplacedTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3); void pushDisplacedQuad(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3, const Vector3 &ov4); + Color* color; SoftwareRenderer *renderer; int client_id; diff --git a/src/render/software/SkyRasterizer.cpp b/src/render/software/SkyRasterizer.cpp index 4bb6719..5bb9ff0 100644 --- a/src/render/software/SkyRasterizer.cpp +++ b/src/render/software/SkyRasterizer.cpp @@ -11,7 +11,7 @@ #define SPHERE_SIZE 20000.0 SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, int client_id): - Rasterizer(renderer, client_id) + Rasterizer(renderer, client_id, Color(0.3, 0.7, 1.0)) { } diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index 0aa386c..a723137 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -11,7 +11,7 @@ #include "CanvasPortion.h" TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id): - Rasterizer(renderer, client_id) + Rasterizer(renderer, client_id, Color(0.5, 0.3, 0.3)) { } diff --git a/src/render/software/WaterRasterizer.cpp b/src/render/software/WaterRasterizer.cpp index 9af4ef4..6f99ac4 100644 --- a/src/render/software/WaterRasterizer.cpp +++ b/src/render/software/WaterRasterizer.cpp @@ -5,7 +5,7 @@ #include "ParallelQueue.h" WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, int client_id): - Rasterizer(renderer, client_id) + Rasterizer(renderer, client_id, Color(0.1, 0.3, 0.6)) { } From fb3d32baf49db808314d88530b1768231d169126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sat, 16 Aug 2014 13:41:02 +0200 Subject: [PATCH 07/29] Removed old render area code in dialogrender --- src/interface/desktop/dialogrender.cpp | 62 -------------------------- src/interface/desktop/dialogrender.h | 3 -- 2 files changed, 65 deletions(-) diff --git a/src/interface/desktop/dialogrender.cpp b/src/interface/desktop/dialogrender.cpp index 1d51787..0cdcdf2 100644 --- a/src/interface/desktop/dialogrender.cpp +++ b/src/interface/desktop/dialogrender.cpp @@ -24,30 +24,6 @@ #include "SoftwareCanvasRenderer.h" #include "WidgetPreviewCanvas.h" -static DialogRender* _current_dialog; - -static void _renderStart(int width, int height, const Color &background) -{ - _current_dialog->pixbuf_lock->lock(); - delete _current_dialog->pixbuf; - _current_dialog->pixbuf = new QImage(width, height, QImage::Format_ARGB32); - _current_dialog->pixbuf->fill(colorToQColor(background).rgb()); - _current_dialog->pixbuf_lock->unlock(); - - _current_dialog->tellRenderSize(width, height); -} - -static void _renderDraw(int x, int y, const Color &col) -{ - _current_dialog->pixbuf->setPixel(x, _current_dialog->pixbuf->height() - 1 - y, colorToQColor(col).rgb()); -} - -static void _renderUpdate(double progress) -{ - _current_dialog->area->update(); - _current_dialog->tellProgressChange(progress); -} - class RenderThread:public QThread { public: @@ -69,30 +45,11 @@ private: RenderConfig _params; }; -class _RenderArea:public QWidget -{ -public: - _RenderArea(QWidget* parent): - QWidget(parent) - { - setMinimumSize(800, 600); - } - - void paintEvent(QPaintEvent*) - { - QPainter painter(this); - _current_dialog->pixbuf_lock->lock(); - painter.drawImage(0, 0, *_current_dialog->pixbuf); - _current_dialog->pixbuf_lock->unlock(); - } -}; - DialogRender::DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer): QDialog(parent, Qt::WindowTitleHint | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint) { pixbuf_lock = new QMutex(); pixbuf = new QImage(1, 1, QImage::Format_ARGB32); - _current_dialog = this; _render_thread = NULL; canvas_renderer = renderer; @@ -100,12 +57,6 @@ DialogRender::DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer): setWindowTitle(tr("Paysages 3D - Render")); setLayout(new QVBoxLayout()); - _scroll = new QScrollArea(this); - _scroll->setAlignment(Qt::AlignCenter); - area = new _RenderArea(_scroll); - _scroll->setWidget(area); - layout()->addWidget(_scroll); - canvas_preview = new WidgetPreviewCanvas(this); canvas_preview->setCanvas(canvas_renderer->getCanvas()); layout()->addWidget(canvas_preview); @@ -189,8 +140,6 @@ void DialogRender::startRender(const RenderConfig ¶ms) canvas_renderer->setSize(params.width, params.height, params.antialias); - applyRenderSize(params.width, params.height); - _render_thread = new RenderThread(this, canvas_renderer, params); _render_thread->start(); @@ -201,8 +150,6 @@ void DialogRender::applyRenderEnded() { _info->hide(); _actions->show(); - - area->update(); } void DialogRender::saveRender() @@ -236,21 +183,12 @@ void DialogRender::toneMappingChanged() void DialogRender::loadLastRender() { - applyRenderSize(canvas_renderer->render_width, canvas_renderer->render_height); renderEnded(); toneMappingChanged(); exec(); } -void DialogRender::applyRenderSize(int width, int height) -{ - area->setMinimumSize(width, height); - area->setMaximumSize(width, height); - area->resize(width, height); - _scroll->setMinimumSize(width > 800 ? 820 : width + 20, height > 600 ? 620 : height + 20); -} - void DialogRender::applyProgress(double value) { double diff = difftime(time(NULL), _started); diff --git a/src/interface/desktop/dialogrender.h b/src/interface/desktop/dialogrender.h index b35fea1..5091fa5 100644 --- a/src/interface/desktop/dialogrender.h +++ b/src/interface/desktop/dialogrender.h @@ -29,10 +29,8 @@ public: QImage* pixbuf; QMutex* pixbuf_lock; - QWidget* area; private slots: - void applyRenderSize(int width, int height); void applyProgress(double value); void saveRender(); void applyRenderEnded(); @@ -47,7 +45,6 @@ private: SoftwareCanvasRenderer* canvas_renderer; WidgetPreviewCanvas* canvas_preview; - QScrollArea* _scroll; QWidget* _info; QWidget* _actions; QComboBox* _tonemapping_control; From 2aeecdec62dc00ca43daffe663f3ab190f008115 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Mon, 18 Aug 2014 12:17:16 +0200 Subject: [PATCH 08/29] WIP on canvas pixel shading --- src/render/software/CanvasPixel.cpp | 5 ++ src/render/software/CanvasPixel.h | 2 + src/render/software/CanvasPixelShader.cpp | 36 +++++++++ src/render/software/CanvasPixelShader.h | 36 +++++++++ src/render/software/CanvasPortion.cpp | 22 ++++++ src/render/software/CanvasPortion.h | 18 ++++- src/render/software/Rasterizer.cpp | 32 +++++--- src/render/software/Rasterizer.h | 3 +- src/render/software/SkyRasterizer.cpp | 32 ++++---- src/render/software/SkyRasterizer.h | 1 + .../software/SoftwareCanvasRenderer.cpp | 19 ++++- src/render/software/SoftwareCanvasRenderer.h | 9 ++- src/render/software/TerrainRasterizer.cpp | 14 ++-- src/render/software/TerrainRasterizer.h | 1 + src/render/software/WaterRasterizer.cpp | 12 +-- src/render/software/WaterRasterizer.h | 1 + src/render/software/software.pro | 6 +- src/render/software/software_global.h | 1 + src/system/ParallelWork.cpp | 79 +++++++++++++------ src/system/ParallelWork.h | 26 +++--- src/system/ParallelWorker.cpp | 9 +++ src/system/ParallelWorker.h | 29 +++++++ src/system/system.pro | 6 +- src/system/system_global.h | 1 + 24 files changed, 317 insertions(+), 83 deletions(-) create mode 100644 src/render/software/CanvasPixelShader.cpp create mode 100644 src/render/software/CanvasPixelShader.h create mode 100644 src/system/ParallelWorker.cpp create mode 100644 src/system/ParallelWorker.h diff --git a/src/render/software/CanvasPixel.cpp b/src/render/software/CanvasPixel.cpp index 1b09863..aa11a38 100644 --- a/src/render/software/CanvasPixel.cpp +++ b/src/render/software/CanvasPixel.cpp @@ -99,3 +99,8 @@ void CanvasPixel::updateComposite() } composite = result; } + +void CanvasPixel::setComposite(const Color &color) +{ + composite = color; +} diff --git a/src/render/software/CanvasPixel.h b/src/render/software/CanvasPixel.h index bcbab0a..314e5b0 100644 --- a/src/render/software/CanvasPixel.h +++ b/src/render/software/CanvasPixel.h @@ -22,11 +22,13 @@ public: inline int getFragmentCount() const {return count;} inline const Color &getComposite() const {return composite;} + inline const CanvasFragment &getFragment(int position) const {return fragments[position];} const CanvasFragment *getFrontFragment() const; void reset(); void pushFragment(const CanvasFragment &fragment); void updateComposite(); + void setComposite(const Color &color); private: int count; diff --git a/src/render/software/CanvasPixelShader.cpp b/src/render/software/CanvasPixelShader.cpp new file mode 100644 index 0000000..6af6479 --- /dev/null +++ b/src/render/software/CanvasPixelShader.cpp @@ -0,0 +1,36 @@ +#include "CanvasPixelShader.h" + +#include "Color.h" +#include "SoftwareCanvasRenderer.h" +#include "CanvasPortion.h" +#include "CanvasPixel.h" +#include "CanvasFragment.h" +#include "Rasterizer.h" + +CanvasPixelShader::CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int chunks_x, int chunks_y): + renderer(renderer), portion(portion), chunk_size(chunk_size), chunks_x(chunks_x), chunks_y(chunks_y) +{ +} + +int CanvasPixelShader::processParallelUnit(int unit) +{ + // Locate the chunk we work on + int chunk_x = unit % chunks_x; + int chunk_y = unit / chunks_x; + + // Resolve the pixel color + int x = chunk_x * chunk_size; + int y = chunk_y * chunk_size; + const CanvasPixel &pixel = portion->at(x, y); + int n = pixel.getFragmentCount(); + Color composite = COLOR_BLACK; + for (int i = 0; i < n; i++) + { + const CanvasFragment &fragment = pixel.getFragment(i); + const Rasterizer &rasterizer = renderer.getRasterizer(fragment.getClient()); + composite.mask(rasterizer.shadeFragment(fragment)); + } + portion->setColor(x, y, composite); + + return 0; +} diff --git a/src/render/software/CanvasPixelShader.h b/src/render/software/CanvasPixelShader.h new file mode 100644 index 0000000..700bdd9 --- /dev/null +++ b/src/render/software/CanvasPixelShader.h @@ -0,0 +1,36 @@ +#ifndef CANVASPIXELSHADER_H +#define CANVASPIXELSHADER_H + +#include "software_global.h" + +#include "ParallelWorker.h" + +namespace paysages { +namespace software { + +/** + * @brief Parallel worker that can work on canvas portion to resolve pixel colors. + * + * This is used after the rasterization phase to compute pixel colors from the fragments stored in them. + * + * This worker will be set to work on a given chunk of a canvas portion. + */ +class CanvasPixelShader: public ParallelWorker +{ +public: + CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int chunks_x, int chunks_y); + + virtual int processParallelUnit(int unit); + +private: + const SoftwareCanvasRenderer &renderer; + CanvasPortion *portion; + int chunk_size; + int chunks_x; + int chunks_y; +}; + +} +} + +#endif // CANVASPIXELSHADER_H diff --git a/src/render/software/CanvasPortion.cpp b/src/render/software/CanvasPortion.cpp index 7b1438f..93acae0 100644 --- a/src/render/software/CanvasPortion.cpp +++ b/src/render/software/CanvasPortion.cpp @@ -69,3 +69,25 @@ void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment) preview->pushPixel(x, y, old_color, pixel.getComposite()); } } + +const CanvasPixel &CanvasPortion::at(int x, int y) +{ + CHECK_COORDINATES(); + + return pixels[y * width + x]; +} + +void CanvasPortion::setColor(int x, int y, const Color &color) +{ + CHECK_COORDINATES(); + + CanvasPixel &pixel = pixels[y * width + x]; + Color old_color = pixel.getComposite(); + + pixel.setComposite(color); + + if (preview) + { + preview->pushPixel(x, y, old_color, pixel.getComposite()); + } +} diff --git a/src/render/software/CanvasPortion.h b/src/render/software/CanvasPortion.h index 85be35e..49d88d4 100644 --- a/src/render/software/CanvasPortion.h +++ b/src/render/software/CanvasPortion.h @@ -7,7 +7,7 @@ namespace paysages { namespace software { /** - * @brief Rectangular portion of a Canvas. + * Rectangular portion of a Canvas. * * Contains the pixels of a canvas region (CanvasPixel). */ @@ -26,12 +26,26 @@ public: void setSize(int width, int height); /** - * @brief Add a fragment to the pixel located at (x, y). + * Add a fragment to the pixel located at (x, y). * * Checking x and y coordinates to be in the canvas portion should be done before this call. */ void pushFragment(int x, int y, const CanvasFragment &fragment); + /** + * Get the CanvasPixel at a given coordinates. + * + * Checking x and y coordinates to be in the canvas portion should be done before this call. + */ + const CanvasPixel &at(int x, int y); + + /** + * Change the final color of the pixel. + * + * Checking x and y coordinates to be in the canvas portion should be done before this call. + */ + void setColor(int x, int y, const Color &color); + private: int width; int height; diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index e2b48b4..009d984 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -136,10 +136,6 @@ void Rasterizer::pushDisplacedQuad(CanvasPortion *canvas, const Vector3 &v1, con pushDisplacedTriangle(canvas, v4, v1, v3, ov4, ov1, ov3); } -void Rasterizer::rasterizeToCanvas(CanvasPortion *) -{ -} - void Rasterizer::scanGetDiff(ScanPoint* v1, ScanPoint* v2, ScanPoint* result) { result->pixel.x = v2->pixel.x - v1->pixel.x; @@ -316,25 +312,35 @@ void Rasterizer::renderScanLines(CanvasPortion *canvas, RenderScanlines* scanlin current.x = x; for (cury = starty; cury <= endy; cury++) { - fy = (double)cury + 0.5; - if (fy < down.pixel.y) + if (dy == 0) { - fy = down.pixel.y; + // Down and up are the same + current = down; } - else if (fy > up.pixel.y) + else { - fy = up.pixel.y; - } - fy = fy - down.pixel.y; + fy = (double)cury + 0.5; + if (fy < down.pixel.y) + { + fy = down.pixel.y; + } + else if (fy > up.pixel.y) + { + fy = up.pixel.y; + } + fy = fy - down.pixel.y; - current.y = cury; - scanInterpolate(renderer->render_camera, &down, &diff, fy / dy, ¤t); + current.y = cury; + scanInterpolate(renderer->render_camera, &down, &diff, fy / dy, ¤t); + } CanvasFragment fragment(current.pixel.z, Vector3(current.location.x, current.location.y, current.location.z), current.client); Color frag_color = *color; if (cury == starty || cury == endy) + { frag_color.mask(Color(0.0, 0.0, 0.0, 0.3)); + } fragment.setColor(frag_color); canvas->pushFragment(current.x, current.y, fragment); diff --git a/src/render/software/Rasterizer.h b/src/render/software/Rasterizer.h index 4e237f1..e364df6 100644 --- a/src/render/software/Rasterizer.h +++ b/src/render/software/Rasterizer.h @@ -20,7 +20,8 @@ public: inline SoftwareRenderer *getRenderer() const {return renderer;} - virtual void rasterizeToCanvas(CanvasPortion* canvas); + virtual void rasterizeToCanvas(CanvasPortion* canvas) = 0; + virtual Color shadeFragment(const CanvasFragment &fragment) const = 0; protected: void pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3); diff --git a/src/render/software/SkyRasterizer.cpp b/src/render/software/SkyRasterizer.cpp index 5bb9ff0..dedff67 100644 --- a/src/render/software/SkyRasterizer.cpp +++ b/src/render/software/SkyRasterizer.cpp @@ -7,6 +7,7 @@ #include "AtmosphereResult.h" #include "CloudsRenderer.h" #include "Rasterizer.h" +#include "CanvasFragment.h" #define SPHERE_SIZE 20000.0 @@ -15,21 +16,6 @@ SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, int client_id): { } -static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &location, void*) -{ - Vector3 camera_location, direction; - Color result; - - camera_location = renderer->getCameraLocation(location); - direction = location.sub(camera_location); - - /* TODO Don't compute result->color if it's fully covered by clouds */ - result = renderer->getAtmosphereRenderer()->getSkyColor(direction.normalize()).final; - result = renderer->getCloudsRenderer()->getColor(camera_location, camera_location.add(direction.scale(10.0)), result); - - return result; -} - void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas) { int res_i, res_j; @@ -84,3 +70,19 @@ void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas) } } } + +Color SkyRasterizer::shadeFragment(const CanvasFragment &fragment) const +{ + Vector3 location = fragment.getLocation(); + Vector3 camera_location, direction; + Color result; + + camera_location = renderer->getCameraLocation(location); + direction = location.sub(camera_location); + + /* TODO Don't compute result->color if it's fully covered by clouds */ + result = renderer->getAtmosphereRenderer()->getSkyColor(direction.normalize()).final; + result = renderer->getCloudsRenderer()->getColor(camera_location, camera_location.add(direction.scale(10.0)), result); + + return result; +} diff --git a/src/render/software/SkyRasterizer.h b/src/render/software/SkyRasterizer.h index 0e44b76..89436b9 100644 --- a/src/render/software/SkyRasterizer.h +++ b/src/render/software/SkyRasterizer.h @@ -14,6 +14,7 @@ public: SkyRasterizer(SoftwareRenderer* renderer, int client_id); virtual void rasterizeToCanvas(CanvasPortion* canvas); + virtual Color shadeFragment(const CanvasFragment &fragment) const; }; } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 0252be6..4007e32 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -7,6 +7,9 @@ #include "WaterRasterizer.h" #include "SkyRasterizer.h" #include "CameraDefinition.h" +#include "ParallelWork.h" +#include "CanvasPortion.h" +#include "CanvasPixelShader.h" SoftwareCanvasRenderer::SoftwareCanvasRenderer() { @@ -58,6 +61,11 @@ const std::vector &SoftwareCanvasRenderer::getRasterizers() const return rasterizers; } +const Rasterizer &SoftwareCanvasRenderer::getRasterizer(int client_id) const +{ + return *(getRasterizers()[client_id]); +} + void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded) { for (auto &rasterizer:getRasterizers()) @@ -68,5 +76,14 @@ void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded) void SoftwareCanvasRenderer::postProcess(CanvasPortion *portion, bool threaded) { - // TODO + // Subdivide in chunks + int chunk_size = 32; + int chunks_x = portion->getWidth() / chunk_size + 1; + int chunks_y = portion->getHeight() / chunk_size + 1; + int units = chunks_x * chunks_y; + + // Render chunks in parallel + CanvasPixelShader shader(*this, portion, chunk_size, chunks_x, chunks_y); + ParallelWork work(&shader, units); + work.perform(); } diff --git a/src/render/software/SoftwareCanvasRenderer.h b/src/render/software/SoftwareCanvasRenderer.h index 3f51569..e18f150 100644 --- a/src/render/software/SoftwareCanvasRenderer.h +++ b/src/render/software/SoftwareCanvasRenderer.h @@ -36,11 +36,16 @@ public: */ void render(); - /*! - * \brief Get the list of objects that can be rasterized to polygons on a canvas. + /** + * @brief Get the list of objects that can be rasterized to polygons on a canvas. */ virtual const std::vector &getRasterizers() const; + /** + * Get a rasterizer by its client id. + */ + const Rasterizer &getRasterizer(int client_id) const; + protected: /** * @brief Rasterize the scenery into a canvas portion. diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index a723137..b677b81 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -9,6 +9,7 @@ #include "Scenery.h" #include "ParallelQueue.h" #include "CanvasPortion.h" +#include "CanvasFragment.h" TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id): Rasterizer(renderer, client_id, Color(0.5, 0.3, 0.3)) @@ -20,12 +21,6 @@ static inline Vector3 _getPoint(SoftwareRenderer* renderer, double x, double z) return Vector3(x, renderer->getTerrainRenderer()->getHeight(x, z, 1), z); } -static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &point, void*) -{ - double precision = renderer->getPrecision(_getPoint(renderer, point.x, point.z)); - return renderer->getTerrainRenderer()->getFinalColor(point, precision); -} - void TerrainRasterizer::tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail) { if (detail < 1) @@ -245,3 +240,10 @@ void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas) queue->wait(); } + +Color TerrainRasterizer::shadeFragment(const CanvasFragment &fragment) const +{ + Vector3 point = fragment.getLocation(); + double precision = renderer->getPrecision(_getPoint(renderer, point.x, point.z)); + return renderer->getTerrainRenderer()->getFinalColor(point, precision); +} diff --git a/src/render/software/TerrainRasterizer.h b/src/render/software/TerrainRasterizer.h index af8b020..0e6537f 100644 --- a/src/render/software/TerrainRasterizer.h +++ b/src/render/software/TerrainRasterizer.h @@ -51,6 +51,7 @@ public: virtual void rasterize(); virtual void rasterizeToCanvas(CanvasPortion* canvas); + virtual Color shadeFragment(const CanvasFragment &fragment) const; private: ParallelQueue* queue; diff --git a/src/render/software/WaterRasterizer.cpp b/src/render/software/WaterRasterizer.cpp index 6f99ac4..92face3 100644 --- a/src/render/software/WaterRasterizer.cpp +++ b/src/render/software/WaterRasterizer.cpp @@ -3,17 +3,13 @@ #include "SoftwareRenderer.h" #include "WaterRenderer.h" #include "ParallelQueue.h" +#include "CanvasFragment.h" WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, int client_id): Rasterizer(renderer, client_id, Color(0.1, 0.3, 0.6)) { } -static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &location, void*) -{ - return renderer->getWaterRenderer()->getResult(location.x, location.z).final; -} - static inline Vector3 _getFirstPassVertex(SoftwareRenderer* renderer, double x, double z) { Vector3 result; @@ -84,3 +80,9 @@ void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas) radius_ext += chunk_size; } } + +Color WaterRasterizer::shadeFragment(const CanvasFragment &fragment) const +{ + Vector3 location = fragment.getLocation(); + return renderer->getWaterRenderer()->getResult(location.x, location.z).final; +} diff --git a/src/render/software/WaterRasterizer.h b/src/render/software/WaterRasterizer.h index e8cda24..902d179 100644 --- a/src/render/software/WaterRasterizer.h +++ b/src/render/software/WaterRasterizer.h @@ -16,6 +16,7 @@ public: void rasterizeQuad(CanvasPortion* canvas, double x, double z, double size); virtual void rasterizeToCanvas(CanvasPortion* canvas); + virtual Color shadeFragment(const CanvasFragment &fragment) const; }; } diff --git a/src/render/software/software.pro b/src/render/software/software.pro index 8f6ba50..4543bf3 100644 --- a/src/render/software/software.pro +++ b/src/render/software/software.pro @@ -45,7 +45,8 @@ SOURCES += SoftwareRenderer.cpp \ Rasterizer.cpp \ CanvasLiveClient.cpp \ CanvasPreview.cpp \ - RenderConfig.cpp + RenderConfig.cpp \ + CanvasPixelShader.cpp HEADERS += SoftwareRenderer.h\ software_global.h \ @@ -80,7 +81,8 @@ HEADERS += SoftwareRenderer.h\ Rasterizer.h \ CanvasLiveClient.h \ CanvasPreview.h \ - RenderConfig.h + RenderConfig.h \ + CanvasPixelShader.h unix:!symbian { maemo5 { diff --git a/src/render/software/software_global.h b/src/render/software/software_global.h index fc6a3fd..0aa9636 100644 --- a/src/render/software/software_global.h +++ b/src/render/software/software_global.h @@ -53,6 +53,7 @@ namespace software { class CanvasFragment; class CanvasLiveClient; class CanvasPreview; + class CanvasPixelShader; } } diff --git a/src/system/ParallelWork.cpp b/src/system/ParallelWork.cpp index acd94f7..9fb57ef 100644 --- a/src/system/ParallelWork.cpp +++ b/src/system/ParallelWork.cpp @@ -2,37 +2,72 @@ #include "Thread.h" #include "System.h" +#include "ParallelWorker.h" #include +/** + * Compatibility class for code that uses ParallelUnitFunction. + */ +class ParallelWorkerCompat:public ParallelWorker +{ +public: + ParallelWorkerCompat(ParallelWork *work, ParallelWork::ParallelUnitFunction func, void* data): + ParallelWorker(), work(work), func(func), data(data) + { + } + + virtual int processParallelUnit(int unit) + { + return func(work, unit, data); + } + +private: + ParallelWork* work; + ParallelWork::ParallelUnitFunction func; + void* data; +}; + +ParallelWork::ParallelWork(ParallelWorker *worker, int units) +{ + this->units = units; + this->running = 0; + this->worker = worker; + this->worker_compat = false; +} + ParallelWork::ParallelWork(ParallelUnitFunction func, int units, void* data) { this->units = units; this->running = 0; - this->unit_function = func; - this->data = data; + this->worker = new ParallelWorkerCompat(this, func, data); + this->worker_compat = true; } ParallelWork::~ParallelWork() { assert(not running); + if (worker_compat) + { + delete worker; + } } -static void* _workerThreadCallback(ParallelWork::ParallelWorker* worker) +static void* _workerThreadCallback(ParallelWork::ParallelWorkerThread* thread) { - worker->result = worker->work->unit_function(worker->work, worker->unit, worker->work->data); - worker->status = ParallelWork::PARALLEL_WORKER_STATUS_DONE; + thread->result = thread->worker->processParallelUnit(thread->unit); + thread->status = ParallelWork::PARALLEL_WORKER_STATUS_DONE; return NULL; } -static int _runNextWorker(ParallelWork::ParallelWorker workers[], int worker_count, int unit) +static int _runNextWorker(ParallelWork::ParallelWorkerThread threads[], int thread_count, int unit) { int i; while (1) { - for (i = 0; i < worker_count; i++) + for (i = 0; i < thread_count; i++) { - ParallelWork::ParallelWorker* worker = workers + i; + ParallelWork::ParallelWorkerThread* worker = threads + i; if (worker->status == ParallelWork::PARALLEL_WORKER_STATUS_VOID) { worker->status = ParallelWork::PARALLEL_WORKER_STATUS_RUNNING; @@ -62,47 +97,47 @@ static int _runNextWorker(ParallelWork::ParallelWorker workers[], int worker_cou } } -int ParallelWork::perform(int nbworkers) +int ParallelWork::perform(int thread_count) { int i, done, result; assert(not running); result = 0; - if (nbworkers <= 0) + if (thread_count <= 0) { - nbworkers = System::getCoreCount(); + thread_count = System::getCoreCount(); } - if (nbworkers > PARALLEL_MAX_THREADS) + if (thread_count > PARALLEL_MAX_THREADS) { - nbworkers = PARALLEL_MAX_THREADS; + thread_count = PARALLEL_MAX_THREADS; } running = 1; /* Init workers */ - for (i = 0; i < nbworkers; i++) + for (i = 0; i < thread_count; i++) { - workers[i].status = PARALLEL_WORKER_STATUS_VOID; - workers[i].work = this; + threads[i].status = PARALLEL_WORKER_STATUS_VOID; + threads[i].worker = worker; } /* Perform run */ for (done = 0; done < units; done++) { - if (_runNextWorker(workers, nbworkers, done)) + if (_runNextWorker(threads, thread_count, done)) { result++; } } /* Wait and clean up workers */ - for (i = 0; i < nbworkers; i++) + for (i = 0; i < thread_count; i++) { - if (workers[i].status != PARALLEL_WORKER_STATUS_VOID) + if (threads[i].status != PARALLEL_WORKER_STATUS_VOID) { - workers[i].thread->join(); - delete workers[i].thread; - if (workers[i].result) + threads[i].thread->join(); + delete threads[i].thread; + if (threads[i].result) { result++; } diff --git a/src/system/ParallelWork.h b/src/system/ParallelWork.h index 528ce31..9f4b756 100644 --- a/src/system/ParallelWork.h +++ b/src/system/ParallelWork.h @@ -23,22 +23,24 @@ public: typedef struct { Thread* thread; - ParallelWork* work; + ParallelWorker* worker; ParallelWorkerStatus status; int unit; int result; - } ParallelWorker; + } ParallelWorkerThread; public: /** * Create a parallel work handler. * - * This will spawn an optimal number of threads to process a given number of work units. + * This will spawn a number of threads. + */ + ParallelWork(ParallelWorker *worker, int units); + + /** + * Create a parallel work handler. * - * @param func The callback that will be called from threads to process one unit. - * @param units Number of units to handle. - * @param data Custom data that will be passed to the callback. - * @return The newly allocated handler. + * This is a compatibility constructor for older code, use the constructor with ParallelWorker instead. */ ParallelWork(ParallelUnitFunction func, int units, void* data); @@ -52,15 +54,15 @@ public: /** * Start working on the units. * - * @param workers Number of threads to spaws, -1 for an optimal number. + * @param threads Number of threads to spaws, -1 for an optimal number. */ - int perform(int workers=-1); + int perform(int thread_count=-1); int units; int running; - ParallelUnitFunction unit_function; - ParallelWorker workers[PARALLEL_MAX_THREADS]; - void* data; + ParallelWorker *worker; + bool worker_compat; + ParallelWorkerThread threads[PARALLEL_MAX_THREADS]; }; } diff --git a/src/system/ParallelWorker.cpp b/src/system/ParallelWorker.cpp new file mode 100644 index 0000000..0e64c57 --- /dev/null +++ b/src/system/ParallelWorker.cpp @@ -0,0 +1,9 @@ +#include "ParallelWorker.h" + +ParallelWorker::ParallelWorker() +{ +} + +ParallelWorker::~ParallelWorker() +{ +} diff --git a/src/system/ParallelWorker.h b/src/system/ParallelWorker.h new file mode 100644 index 0000000..b77f08c --- /dev/null +++ b/src/system/ParallelWorker.h @@ -0,0 +1,29 @@ +#ifndef PARALLELWORKER_H +#define PARALLELWORKER_H + +#include "system_global.h" + +namespace paysages { +namespace system { + +/** + * @brief Worker that can be used by the ParallelWork object to perform tasks in several threads. + */ +class SYSTEMSHARED_EXPORT ParallelWorker +{ +public: + ParallelWorker(); + virtual ~ParallelWorker(); + + /** + * Abstract method to reimplement to process a work unit. + * + * This method will be called from any thread in the thread pool used by the ParallelWork. + */ + virtual int processParallelUnit(int unit) = 0; +}; + +} +} + +#endif // PARALLELWORKER_H diff --git a/src/system/system.pro b/src/system/system.pro index 5de52fa..73a8234 100644 --- a/src/system/system.pro +++ b/src/system/system.pro @@ -25,7 +25,8 @@ SOURCES += \ CacheFile.cpp \ PictureWriter.cpp \ Logs.cpp \ - ParallelPool.cpp + ParallelPool.cpp \ + ParallelWorker.cpp HEADERS += \ system_global.h \ @@ -40,7 +41,8 @@ HEADERS += \ CacheFile.h \ PictureWriter.h \ Logs.h \ - ParallelPool.h + ParallelPool.h \ + ParallelWorker.h unix:!symbian { maemo5 { diff --git a/src/system/system_global.h b/src/system/system_global.h index 52e9755..c490cdf 100644 --- a/src/system/system_global.h +++ b/src/system/system_global.h @@ -18,6 +18,7 @@ namespace system { class ParallelQueue; class ParallelWork; class ParallelPool; + class ParallelWorker; class Thread; class Mutex; } From 0566f2bdd8e4639718ac04ebf41df92913d5c94e Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Mon, 18 Aug 2014 15:20:04 +0200 Subject: [PATCH 09/29] Refactored ParallelWork for better performance --- src/interface/desktop/WidgetPreviewCanvas.cpp | 3 +- .../software/SoftwareCanvasRenderer.cpp | 4 +- src/system/ParallelWork.cpp | 163 +++++++++++------- src/system/ParallelWork.h | 33 ++-- src/system/Semaphore.cpp | 6 + src/system/Semaphore.h | 25 +++ src/system/Thread.h | 2 +- src/system/system.pro | 6 +- src/system/system_global.h | 1 + 9 files changed, 156 insertions(+), 87 deletions(-) create mode 100644 src/system/Semaphore.cpp create mode 100644 src/system/Semaphore.h diff --git a/src/interface/desktop/WidgetPreviewCanvas.cpp b/src/interface/desktop/WidgetPreviewCanvas.cpp index 47d989a..e1463f9 100644 --- a/src/interface/desktop/WidgetPreviewCanvas.cpp +++ b/src/interface/desktop/WidgetPreviewCanvas.cpp @@ -12,7 +12,7 @@ WidgetPreviewCanvas::WidgetPreviewCanvas(QWidget *parent) : pixbuf = new QImage(); inited = false; - startTimer(1000); + startTimer(500); } WidgetPreviewCanvas::~WidgetPreviewCanvas() @@ -65,5 +65,6 @@ void WidgetPreviewCanvas::timerEvent(QTimerEvent *) } canvas->getPreview()->updateLive(this); + update(); } } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 4007e32..4106ffd 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -78,8 +78,8 @@ void SoftwareCanvasRenderer::postProcess(CanvasPortion *portion, bool threaded) { // Subdivide in chunks int chunk_size = 32; - int chunks_x = portion->getWidth() / chunk_size + 1; - int chunks_y = portion->getHeight() / chunk_size + 1; + int chunks_x = (portion->getWidth() - 1) / chunk_size + 1; + int chunks_y = (portion->getHeight() - 1) / chunk_size + 1; int units = chunks_x * chunks_y; // Render chunks in parallel diff --git a/src/system/ParallelWork.cpp b/src/system/ParallelWork.cpp index 9fb57ef..a80bb0a 100644 --- a/src/system/ParallelWork.cpp +++ b/src/system/ParallelWork.cpp @@ -2,6 +2,8 @@ #include "Thread.h" #include "System.h" +#include "Semaphore.h" +#include "Mutex.h" #include "ParallelWorker.h" #include @@ -27,6 +29,56 @@ private: void* data; }; +/** + * Thread sub-class to perform units of work + */ +class ParallelWork::ParallelThread:public Thread +{ +public: + ParallelThread(ParallelWork *work): + Thread(), work(work), sem(0) + { + interrupted = false; + unit = -1; + } + + void feedUnit(int unit) + { + this->unit = unit; + sem.release(); + } + + void interrupt() + { + interrupted = true; + sem.release(); + } + +protected: + virtual void run() override + { + while (unit >= 0 or not interrupted) + { + // Wait for a unit (or interrupt) + sem.acquire(); + + // Process the unit + if (unit >= 0) + { + work->worker->processParallelUnit(unit); + work->returnThread(this); + unit = -1; + } + } + } + +private: + ParallelWork* work; + Semaphore sem; + int unit; + bool interrupted; +}; + ParallelWork::ParallelWork(ParallelWorker *worker, int units) { this->units = units; @@ -52,58 +104,12 @@ ParallelWork::~ParallelWork() } } -static void* _workerThreadCallback(ParallelWork::ParallelWorkerThread* thread) -{ - thread->result = thread->worker->processParallelUnit(thread->unit); - thread->status = ParallelWork::PARALLEL_WORKER_STATUS_DONE; - return NULL; -} - -static int _runNextWorker(ParallelWork::ParallelWorkerThread threads[], int thread_count, int unit) -{ - int i; - - while (1) - { - for (i = 0; i < thread_count; i++) - { - ParallelWork::ParallelWorkerThread* worker = threads + i; - if (worker->status == ParallelWork::PARALLEL_WORKER_STATUS_VOID) - { - worker->status = ParallelWork::PARALLEL_WORKER_STATUS_RUNNING; - worker->result = 0; - worker->unit = unit; - worker->thread = new Thread((ThreadFunction)_workerThreadCallback); - worker->thread->start(worker); - - return 0; - } - else if (worker->status == ParallelWork::PARALLEL_WORKER_STATUS_DONE) - { - int result = worker->result; - - worker->status = ParallelWork::PARALLEL_WORKER_STATUS_RUNNING; - worker->result = 0; - worker->unit = unit; - worker->thread->join(); - delete worker->thread; - worker->thread = new Thread((ThreadFunction)_workerThreadCallback); - worker->thread->start(worker); - - return result; - } - } - Thread::timeSleepMs(50); - } -} - int ParallelWork::perform(int thread_count) { - int i, done, result; + int i, done; assert(not running); - result = 0; - + // Get thread count if (thread_count <= 0) { thread_count = System::getCoreCount(); @@ -112,38 +118,65 @@ int ParallelWork::perform(int thread_count) { thread_count = PARALLEL_MAX_THREADS; } + this->thread_count = thread_count; running = 1; - /* Init workers */ + // Init threads + semaphore = new Semaphore(thread_count); + mutex = new Mutex(); + threads = new ParallelThread*[thread_count]; + available = new ParallelThread*[thread_count]; + available_offset = 0; + available_length = thread_count; for (i = 0; i < thread_count; i++) { - threads[i].status = PARALLEL_WORKER_STATUS_VOID; - threads[i].worker = worker; + threads[i] = available[i] = new ParallelThread(this); + threads[i]->start(); } - /* Perform run */ + // Perform all units for (done = 0; done < units; done++) { - if (_runNextWorker(threads, thread_count, done)) + // Take first available thread + semaphore->acquire(); + mutex->acquire(); + ParallelThread *thread = available[available_offset]; + available_offset++; + if (available_offset >= thread_count) { - result++; + available_offset = 0; } + available_length--; + mutex->release(); + + // Feed the unit to it + thread->feedUnit(done); } - /* Wait and clean up workers */ + // Wait for all threads to end, then cleanup for (i = 0; i < thread_count; i++) { - if (threads[i].status != PARALLEL_WORKER_STATUS_VOID) - { - threads[i].thread->join(); - delete threads[i].thread; - if (threads[i].result) - { - result++; - } - } + threads[i]->interrupt(); } + for (i = 0; i < thread_count; i++) + { + threads[i]->join(); + delete threads[i]; + } + delete[] threads; + delete[] available; + delete semaphore; + delete mutex; running = 0; - return result; + return done; +} + +void ParallelWork::returnThread(ParallelWork::ParallelThread *thread) +{ + mutex->acquire(); + available[(available_offset + available_length) % thread_count] = thread; + available_length++; + semaphore->release(); + mutex->release(); } diff --git a/src/system/ParallelWork.h b/src/system/ParallelWork.h index 9f4b756..3e6d923 100644 --- a/src/system/ParallelWork.h +++ b/src/system/ParallelWork.h @@ -13,21 +13,11 @@ class SYSTEMSHARED_EXPORT ParallelWork public: typedef int (*ParallelUnitFunction)(ParallelWork* work, int unit, void* data); - typedef enum - { - PARALLEL_WORKER_STATUS_VOID, - PARALLEL_WORKER_STATUS_RUNNING, - PARALLEL_WORKER_STATUS_DONE - } ParallelWorkerStatus; - - typedef struct - { - Thread* thread; - ParallelWorker* worker; - ParallelWorkerStatus status; - int unit; - int result; - } ParallelWorkerThread; + /** + * Obscure thread class. + */ + class ParallelThread; + friend class ParallelThread; public: /** @@ -58,11 +48,22 @@ public: */ int perform(int thread_count=-1); +private: + void returnThread(ParallelThread *thread); + +private: int units; int running; ParallelWorker *worker; bool worker_compat; - ParallelWorkerThread threads[PARALLEL_MAX_THREADS]; + + int thread_count; + Mutex* mutex; + Semaphore* semaphore; + ParallelThread** threads; + ParallelThread** available; + int available_offset; + int available_length; }; } diff --git a/src/system/Semaphore.cpp b/src/system/Semaphore.cpp new file mode 100644 index 0000000..65ca0c7 --- /dev/null +++ b/src/system/Semaphore.cpp @@ -0,0 +1,6 @@ +#include "Semaphore.h" + +Semaphore::Semaphore(int resources): + QSemaphore(resources) +{ +} diff --git a/src/system/Semaphore.h b/src/system/Semaphore.h new file mode 100644 index 0000000..659cee2 --- /dev/null +++ b/src/system/Semaphore.h @@ -0,0 +1,25 @@ +#ifndef SEMAPHORE_H +#define SEMAPHORE_H + +#include "system_global.h" + +#include + +namespace paysages +{ +namespace system +{ + +class Semaphore: private QSemaphore +{ +public: + Semaphore(int resources); + + inline void acquire() {QSemaphore::acquire();} + inline void release() {QSemaphore::release();} +}; + +} +} + +#endif // SEMAPHORE_H diff --git a/src/system/Thread.h b/src/system/Thread.h index 699e381..5c49233 100644 --- a/src/system/Thread.h +++ b/src/system/Thread.h @@ -29,7 +29,7 @@ public: * \brief Start the thread * \param data User data to pass to the threaded function */ - void start(void* data); + void start(void* data=0); /*! * \brief Wait for the thread to end, and collect its result. diff --git a/src/system/system.pro b/src/system/system.pro index 73a8234..2e2f3c1 100644 --- a/src/system/system.pro +++ b/src/system/system.pro @@ -26,7 +26,8 @@ SOURCES += \ PictureWriter.cpp \ Logs.cpp \ ParallelPool.cpp \ - ParallelWorker.cpp + ParallelWorker.cpp \ + Semaphore.cpp HEADERS += \ system_global.h \ @@ -42,7 +43,8 @@ HEADERS += \ PictureWriter.h \ Logs.h \ ParallelPool.h \ - ParallelWorker.h + ParallelWorker.h \ + Semaphore.h unix:!symbian { maemo5 { diff --git a/src/system/system_global.h b/src/system/system_global.h index c490cdf..3b003bc 100644 --- a/src/system/system_global.h +++ b/src/system/system_global.h @@ -21,6 +21,7 @@ namespace system { class ParallelWorker; class Thread; class Mutex; + class Semaphore; } } using namespace paysages::system; From b5ee4c432fa8434db03aa0401d163bd09542ec5f Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Mon, 18 Aug 2014 16:04:46 +0200 Subject: [PATCH 10/29] Added parallel pixel shader for second-pass rendering --- src/render/software/CanvasPixelShader.cpp | 41 +++++++++++++------ src/render/software/CanvasPixelShader.h | 3 +- src/render/software/Rasterizer.cpp | 2 +- src/render/software/SkyRasterizer.cpp | 2 +- .../software/SoftwareCanvasRenderer.cpp | 11 +++-- src/render/software/TerrainRasterizer.cpp | 2 +- src/render/software/WaterRasterizer.cpp | 2 +- 7 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/render/software/CanvasPixelShader.cpp b/src/render/software/CanvasPixelShader.cpp index 6af6479..43f1940 100644 --- a/src/render/software/CanvasPixelShader.cpp +++ b/src/render/software/CanvasPixelShader.cpp @@ -7,30 +7,45 @@ #include "CanvasFragment.h" #include "Rasterizer.h" -CanvasPixelShader::CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int chunks_x, int chunks_y): - renderer(renderer), portion(portion), chunk_size(chunk_size), chunks_x(chunks_x), chunks_y(chunks_y) +CanvasPixelShader::CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y): + renderer(renderer), portion(portion), chunk_size(chunk_size), sub_chunk_size(sub_chunk_size), chunks_x(chunks_x), chunks_y(chunks_y) { } int CanvasPixelShader::processParallelUnit(int unit) { // Locate the chunk we work on + int prev_sub_chunk_size = chunk_size * 2; int chunk_x = unit % chunks_x; int chunk_y = unit / chunks_x; + int base_x = chunk_x * chunk_size; + int base_y = chunk_y * chunk_size; + int limit_x = portion->getWidth() - base_x; + int limit_y = portion->getHeight() - base_y; - // Resolve the pixel color - int x = chunk_x * chunk_size; - int y = chunk_y * chunk_size; - const CanvasPixel &pixel = portion->at(x, y); - int n = pixel.getFragmentCount(); - Color composite = COLOR_BLACK; - for (int i = 0; i < n; i++) + limit_x = (limit_x > chunk_size) ? chunk_size : limit_x; + limit_y = (limit_y > chunk_size) ? chunk_size : limit_y; + + for (int x = 0; x < limit_x; x += sub_chunk_size) { - const CanvasFragment &fragment = pixel.getFragment(i); - const Rasterizer &rasterizer = renderer.getRasterizer(fragment.getClient()); - composite.mask(rasterizer.shadeFragment(fragment)); + for (int y = 0; y < limit_y; y += sub_chunk_size) + { + if (x % prev_sub_chunk_size != 0 or y % prev_sub_chunk_size != 0) + { + // Resolve the pixel color + const CanvasPixel &pixel = portion->at(base_x + x, base_y + y); + int n = pixel.getFragmentCount(); + Color composite = COLOR_BLACK; + for (int i = 0; i < n; i++) + { + const CanvasFragment &fragment = pixel.getFragment(i); + const Rasterizer &rasterizer = renderer.getRasterizer(fragment.getClient()); + composite.mask(rasterizer.shadeFragment(fragment)); + } + portion->setColor(base_x + x, base_y + y, composite); + } + } } - portion->setColor(x, y, composite); return 0; } diff --git a/src/render/software/CanvasPixelShader.h b/src/render/software/CanvasPixelShader.h index 700bdd9..ce321c1 100644 --- a/src/render/software/CanvasPixelShader.h +++ b/src/render/software/CanvasPixelShader.h @@ -18,7 +18,7 @@ namespace software { class CanvasPixelShader: public ParallelWorker { public: - CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int chunks_x, int chunks_y); + CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y); virtual int processParallelUnit(int unit); @@ -26,6 +26,7 @@ private: const SoftwareCanvasRenderer &renderer; CanvasPortion *portion; int chunk_size; + int sub_chunk_size; int chunks_x; int chunks_y; }; diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index 009d984..43e4b57 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -339,7 +339,7 @@ void Rasterizer::renderScanLines(CanvasPortion *canvas, RenderScanlines* scanlin Color frag_color = *color; if (cury == starty || cury == endy) { - frag_color.mask(Color(0.0, 0.0, 0.0, 0.3)); + frag_color.mask(Color(0.0, 0.0, 0.0, 0.1)); } fragment.setColor(frag_color); diff --git a/src/render/software/SkyRasterizer.cpp b/src/render/software/SkyRasterizer.cpp index dedff67..b8251c7 100644 --- a/src/render/software/SkyRasterizer.cpp +++ b/src/render/software/SkyRasterizer.cpp @@ -12,7 +12,7 @@ #define SPHERE_SIZE 20000.0 SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, int client_id): - Rasterizer(renderer, client_id, Color(0.3, 0.7, 1.0)) + Rasterizer(renderer, client_id, Color(0.9, 0.9, 1.0)) { } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 4106ffd..a70ba88 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -77,13 +77,16 @@ void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded) void SoftwareCanvasRenderer::postProcess(CanvasPortion *portion, bool threaded) { // Subdivide in chunks - int chunk_size = 32; + int chunk_size = 64; int chunks_x = (portion->getWidth() - 1) / chunk_size + 1; int chunks_y = (portion->getHeight() - 1) / chunk_size + 1; int units = chunks_x * chunks_y; // Render chunks in parallel - CanvasPixelShader shader(*this, portion, chunk_size, chunks_x, chunks_y); - ParallelWork work(&shader, units); - work.perform(); + for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2) + { + CanvasPixelShader shader(*this, portion, chunk_size, sub_chunk_size, chunks_x, chunks_y); + ParallelWork work(&shader, units); + work.perform(); + } } diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index b677b81..ac0afdf 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -12,7 +12,7 @@ #include "CanvasFragment.h" TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id): - Rasterizer(renderer, client_id, Color(0.5, 0.3, 0.3)) + Rasterizer(renderer, client_id, Color(1.0, 0.9, 0.9)) { } diff --git a/src/render/software/WaterRasterizer.cpp b/src/render/software/WaterRasterizer.cpp index 92face3..ee9d681 100644 --- a/src/render/software/WaterRasterizer.cpp +++ b/src/render/software/WaterRasterizer.cpp @@ -6,7 +6,7 @@ #include "CanvasFragment.h" WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, int client_id): - Rasterizer(renderer, client_id, Color(0.1, 0.3, 0.6)) + Rasterizer(renderer, client_id, Color(0.9, 0.95, 1.0)) { } From 9c2d545e6abbc1b38b3d6218c30bdc6431d5b4f8 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Mon, 18 Aug 2014 16:25:44 +0200 Subject: [PATCH 11/29] Fixed parallel canvas shading --- src/render/software/CanvasPixelShader.cpp | 17 +++++++++++++---- src/system/ParallelWork.cpp | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/render/software/CanvasPixelShader.cpp b/src/render/software/CanvasPixelShader.cpp index 43f1940..318d071 100644 --- a/src/render/software/CanvasPixelShader.cpp +++ b/src/render/software/CanvasPixelShader.cpp @@ -16,8 +16,8 @@ int CanvasPixelShader::processParallelUnit(int unit) { // Locate the chunk we work on int prev_sub_chunk_size = chunk_size * 2; - int chunk_x = unit % chunks_x; - int chunk_y = unit / chunks_x; + int chunk_x = unit / chunks_y; + int chunk_y = unit % chunks_y; int base_x = chunk_x * chunk_size; int base_y = chunk_y * chunk_size; int limit_x = portion->getWidth() - base_x; @@ -26,11 +26,12 @@ int CanvasPixelShader::processParallelUnit(int unit) limit_x = (limit_x > chunk_size) ? chunk_size : limit_x; limit_y = (limit_y > chunk_size) ? chunk_size : limit_y; + // Iterate on sub-chunks for (int x = 0; x < limit_x; x += sub_chunk_size) { for (int y = 0; y < limit_y; y += sub_chunk_size) { - if (x % prev_sub_chunk_size != 0 or y % prev_sub_chunk_size != 0) + if (sub_chunk_size == chunk_size or x % prev_sub_chunk_size != 0 or y % prev_sub_chunk_size != 0) { // Resolve the pixel color const CanvasPixel &pixel = portion->at(base_x + x, base_y + y); @@ -42,7 +43,15 @@ int CanvasPixelShader::processParallelUnit(int unit) const Rasterizer &rasterizer = renderer.getRasterizer(fragment.getClient()); composite.mask(rasterizer.shadeFragment(fragment)); } - portion->setColor(base_x + x, base_y + y, composite); + + // Fill the square area + for (int fx = 0; fx + x < limit_x and fx < sub_chunk_size; fx++) + { + for (int fy = 0; fy + y < limit_y and fy < sub_chunk_size; fy++) + { + portion->setColor(base_x + x + fx, base_y + y + fy, composite); + } + } } } } diff --git a/src/system/ParallelWork.cpp b/src/system/ParallelWork.cpp index a80bb0a..c77aca3 100644 --- a/src/system/ParallelWork.cpp +++ b/src/system/ParallelWork.cpp @@ -66,8 +66,8 @@ protected: if (unit >= 0) { work->worker->processParallelUnit(unit); - work->returnThread(this); unit = -1; + work->returnThread(this); } } } From c9fa33984b7149ec87dec8867e55e9cb44d63529 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Mon, 18 Aug 2014 16:33:09 +0200 Subject: [PATCH 12/29] Restored color profile in canvas preview --- src/render/software/CanvasPreview.cpp | 5 ++++- src/render/software/CanvasPreview.h | 2 ++ src/render/software/Rasterizer.cpp | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/render/software/CanvasPreview.cpp b/src/render/software/CanvasPreview.cpp index 61b63ef..e37b41d 100644 --- a/src/render/software/CanvasPreview.cpp +++ b/src/render/software/CanvasPreview.cpp @@ -3,6 +3,7 @@ #include "Color.h" #include "CanvasLiveClient.h" #include "Mutex.h" +#include "ColorProfile.h" #include @@ -18,12 +19,14 @@ CanvasPreview::CanvasPreview() dirty_up = -1; lock = new Mutex(); + profile = new ColorProfile(); } CanvasPreview::~CanvasPreview() { delete [] pixels; delete lock; + delete profile; } void CanvasPreview::setSize(int real_width, int real_height, int preview_width, int preview_height) @@ -77,7 +80,7 @@ void CanvasPreview::updateLive(CanvasLiveClient *client) { for (x = dirty_left; x <= dirty_right; x++) { - client->canvasPainted(x, y, pixels[y * width + x]); + client->canvasPainted(x, y, profile->apply(pixels[y * width + x])); } } diff --git a/src/render/software/CanvasPreview.h b/src/render/software/CanvasPreview.h index e6607d3..35ef00a 100644 --- a/src/render/software/CanvasPreview.h +++ b/src/render/software/CanvasPreview.h @@ -36,6 +36,8 @@ private: int width; int height; + ColorProfile *profile; + int dirty_left; int dirty_right; int dirty_down; diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index 43e4b57..009d984 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -339,7 +339,7 @@ void Rasterizer::renderScanLines(CanvasPortion *canvas, RenderScanlines* scanlin Color frag_color = *color; if (cury == starty || cury == endy) { - frag_color.mask(Color(0.0, 0.0, 0.0, 0.1)); + frag_color.mask(Color(0.0, 0.0, 0.0, 0.3)); } fragment.setColor(frag_color); From 3a2ec1c75fcded907e83b5228f9ab146c308b088 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Mon, 18 Aug 2014 17:16:17 +0200 Subject: [PATCH 13/29] Only allocate canvas portion pixels when needed This will allow for larger renders in constant memory footprint --- src/interface/desktop/formrender.cpp | 4 +-- src/render/software/Canvas.cpp | 9 +++-- src/render/software/CanvasPortion.cpp | 19 +++++++--- src/render/software/CanvasPortion.h | 7 ++++ src/render/software/CanvasPreview.cpp | 35 ++++++++++++++----- src/render/software/CanvasPreview.h | 5 +++ .../software/SoftwareCanvasRenderer.cpp | 4 ++- 7 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/interface/desktop/formrender.cpp b/src/interface/desktop/formrender.cpp index cbc6157..489e7bb 100644 --- a/src/interface/desktop/formrender.cpp +++ b/src/interface/desktop/formrender.cpp @@ -36,8 +36,8 @@ BaseForm(parent, true) addInput(new InputCamera(this, tr("Camera"), _camera)); addInputInt(tr("Quality"), &_params.quality, 1, 10, 1, 1); - addInputInt(tr("Image width"), &_params.width, 100, 2000, 10, 100); - addInputInt(tr("Image height"), &_params.height, 100, 1200, 10, 100); + addInputInt(tr("Image width"), &_params.width, 100, 4000, 10, 100); + addInputInt(tr("Image height"), &_params.height, 100, 3000, 10, 100); addInputInt(tr("Anti aliasing"), &_params.antialias, 1, 4, 1, 1); button = addButton(tr("Start new render")); diff --git a/src/render/software/Canvas.cpp b/src/render/software/Canvas.cpp index 809b170..875b8fc 100644 --- a/src/render/software/Canvas.cpp +++ b/src/render/software/Canvas.cpp @@ -67,8 +67,13 @@ void Canvas::setSize(int width, int height) this->width = width; this->height = height; - // TODO Smaller preview - preview->setSize(width, height, width, height); + // Smaller preview + while (width > 800 and height > 800) + { + width = width / 2; + height = height / 2; + } + preview->setSize(this->width, this->height, width, height); } CanvasPortion *Canvas::at(int x, int y) const diff --git a/src/render/software/CanvasPortion.cpp b/src/render/software/CanvasPortion.cpp index 93acae0..ff0b15e 100644 --- a/src/render/software/CanvasPortion.cpp +++ b/src/render/software/CanvasPortion.cpp @@ -8,19 +8,23 @@ #define CHECK_COORDINATES() assert(x >= 0); \ assert(x < width); \ assert(y >= 0); \ - assert(y < height) + assert(y < height); \ + assert(pixels != NULL) CanvasPortion::CanvasPortion(CanvasPreview* preview): preview(preview) { width = 1; height = 1; - pixels = new CanvasPixel[1]; + pixels = NULL; } CanvasPortion::~CanvasPortion() { - delete[] pixels; + if (pixels) + { + delete[] pixels; + } } int CanvasPortion::getFragmentCount(int x, int y) const @@ -50,9 +54,16 @@ void CanvasPortion::setSize(int width, int height) { this->width = width; this->height = height; +} - delete[] pixels; +void CanvasPortion::preparePixels() +{ + if (pixels) + { + delete[] pixels; + } pixels = new CanvasPixel[width * height]; + clear(); } void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment) diff --git a/src/render/software/CanvasPortion.h b/src/render/software/CanvasPortion.h index 49d88d4..9d45f42 100644 --- a/src/render/software/CanvasPortion.h +++ b/src/render/software/CanvasPortion.h @@ -10,6 +10,8 @@ namespace software { * Rectangular portion of a Canvas. * * Contains the pixels of a canvas region (CanvasPixel). + * + * Pixels are not allocated until preparePixels is called. */ class SOFTWARESHARED_EXPORT CanvasPortion { @@ -25,6 +27,11 @@ public: void clear(); void setSize(int width, int height); + /** + * Prepare (allocate in memory) the pixels area. + */ + void preparePixels(); + /** * Add a fragment to the pixel located at (x, y). * diff --git a/src/render/software/CanvasPreview.cpp b/src/render/software/CanvasPreview.cpp index e37b41d..cb63c03 100644 --- a/src/render/software/CanvasPreview.cpp +++ b/src/render/software/CanvasPreview.cpp @@ -18,6 +18,11 @@ CanvasPreview::CanvasPreview() dirty_down = 1; dirty_up = -1; + scaled = false; + factor = 1.0; + factor_x = 1.0; + factor_y = 1.0; + lock = new Mutex(); profile = new ColorProfile(); } @@ -44,6 +49,11 @@ void CanvasPreview::setSize(int real_width, int real_height, int preview_width, dirty_down = height; dirty_up = -1; + scaled = (real_width != preview_height or real_height != preview_height); + factor_x = (double)real_width / (double)preview_width; + factor_y = (double)real_height / (double)preview_height; + factor = factor_x * factor_y; + lock->release(); reset(); @@ -94,17 +104,26 @@ void CanvasPreview::updateLive(CanvasLiveClient *client) void CanvasPreview::pushPixel(int real_x, int real_y, const Color &old_color, const Color &new_color) { + int x, y; + lock->acquire(); - // TODO Assert-check and transform coordinates - int x = real_x; - int y = real_y; - double fact = 1.0; + // TODO Assert-check + if (scaled) + { + x = round(real_x / factor_x); + y = round(real_y / factor_y); + } + else + { + x = real_x; + y = real_y; + } - Color* pixel = pixels + (real_y * width + real_x); - pixel->r = pixel->r - old_color.r * fact + new_color.r * fact; - pixel->g = pixel->g - old_color.g * fact + new_color.g * fact; - pixel->b = pixel->b - old_color.b * fact + new_color.b * fact; + Color* pixel = pixels + (y * width + x); + pixel->r = pixel->r - old_color.r / factor + new_color.r / factor; + pixel->g = pixel->g - old_color.g / factor + new_color.g / factor; + pixel->b = pixel->b - old_color.b / factor + new_color.b / factor; // Set pixel dirty if (x < dirty_left) diff --git a/src/render/software/CanvasPreview.h b/src/render/software/CanvasPreview.h index 35ef00a..f67cc39 100644 --- a/src/render/software/CanvasPreview.h +++ b/src/render/software/CanvasPreview.h @@ -42,6 +42,11 @@ private: int dirty_right; int dirty_down; int dirty_up; + + bool scaled; + double factor; + double factor_x; + double factor_y; }; } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index a70ba88..fde61ee 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -43,7 +43,6 @@ void SoftwareCanvasRenderer::render() { // TEMP started = true; - CanvasPortion *portion = canvas->at(0, 0); render_width = canvas->getWidth(); render_height = canvas->getHeight(); render_quality = 3; @@ -52,6 +51,9 @@ void SoftwareCanvasRenderer::render() prepare(); + // TODO Iterate portions + CanvasPortion *portion = canvas->at(0, 0); + portion->preparePixels(); rasterize(portion, true); postProcess(portion, true); } From 31b74c660e89244b197730b67b6d8eae260b8344 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Mon, 18 Aug 2014 17:33:15 +0200 Subject: [PATCH 14/29] Iterate over portions to render the whole canvas --- src/render/software/Canvas.cpp | 4 ++- src/render/software/CanvasPortion.cpp | 19 +++++++++++--- src/render/software/CanvasPortion.h | 11 +++++++- src/render/software/CanvasPreview.cpp | 3 ++- src/render/software/Rasterizer.cpp | 26 +++++++++++-------- .../software/SoftwareCanvasRenderer.cpp | 19 ++++++++++---- 6 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/render/software/Canvas.cpp b/src/render/software/Canvas.cpp index 875b8fc..4e4e746 100644 --- a/src/render/software/Canvas.cpp +++ b/src/render/software/Canvas.cpp @@ -50,7 +50,9 @@ void Canvas::setSize(int width, int height) CanvasPortion *portion = new CanvasPortion(preview); portion->setSize((x == horizontal_portion_count - 1) ? width - done_width : portion_width, - (y == vertical_portion_count - 1) ? height - done_height : portion_height); + (y == vertical_portion_count - 1) ? height - done_height : portion_height, + done_width, + done_height); done_width += portion->getWidth(); if (x == horizontal_portion_count - 1) diff --git a/src/render/software/CanvasPortion.cpp b/src/render/software/CanvasPortion.cpp index ff0b15e..193404a 100644 --- a/src/render/software/CanvasPortion.cpp +++ b/src/render/software/CanvasPortion.cpp @@ -16,6 +16,8 @@ CanvasPortion::CanvasPortion(CanvasPreview* preview): { width = 1; height = 1; + xoffset = 0; + yoffset = 0; pixels = NULL; } @@ -50,10 +52,12 @@ void CanvasPortion::clear() } } -void CanvasPortion::setSize(int width, int height) +void CanvasPortion::setSize(int width, int height, int xoffset, int yoffset) { this->width = width; this->height = height; + this->xoffset = xoffset; + this->yoffset = yoffset; } void CanvasPortion::preparePixels() @@ -66,6 +70,15 @@ void CanvasPortion::preparePixels() clear(); } +void CanvasPortion::discardPixels() +{ + if (pixels) + { + delete[] pixels; + pixels = NULL; + } +} + void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment) { CHECK_COORDINATES(); @@ -77,7 +90,7 @@ void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment) if (preview) { - preview->pushPixel(x, y, old_color, pixel.getComposite()); + preview->pushPixel(xoffset + x, yoffset + y, old_color, pixel.getComposite()); } } @@ -99,6 +112,6 @@ void CanvasPortion::setColor(int x, int y, const Color &color) if (preview) { - preview->pushPixel(x, y, old_color, pixel.getComposite()); + preview->pushPixel(xoffset + x, yoffset + y, old_color, pixel.getComposite()); } } diff --git a/src/render/software/CanvasPortion.h b/src/render/software/CanvasPortion.h index 9d45f42..59d0153 100644 --- a/src/render/software/CanvasPortion.h +++ b/src/render/software/CanvasPortion.h @@ -21,17 +21,24 @@ public: inline int getWidth() const {return width;} inline int getHeight() const {return height;} + inline int getXOffset() const {return xoffset;} + inline int getYOffset() const {return yoffset;} int getFragmentCount(int x, int y) const; const CanvasFragment *getFrontFragment(int x, int y) const; void clear(); - void setSize(int width, int height); + void setSize(int width, int height, int xoffset=0, int yoffset=0); /** * Prepare (allocate in memory) the pixels area. */ void preparePixels(); + /** + * Discard the memory used by pixels. + */ + void discardPixels(); + /** * Add a fragment to the pixel located at (x, y). * @@ -56,6 +63,8 @@ public: private: int width; int height; + int xoffset; + int yoffset; CanvasPixel *pixels; CanvasPreview* preview; }; diff --git a/src/render/software/CanvasPreview.cpp b/src/render/software/CanvasPreview.cpp index cb63c03..f7cf1fc 100644 --- a/src/render/software/CanvasPreview.cpp +++ b/src/render/software/CanvasPreview.cpp @@ -108,7 +108,6 @@ void CanvasPreview::pushPixel(int real_x, int real_y, const Color &old_color, co lock->acquire(); - // TODO Assert-check if (scaled) { x = round(real_x / factor_x); @@ -120,6 +119,8 @@ void CanvasPreview::pushPixel(int real_x, int real_y, const Color &old_color, co y = real_y; } + // TODO Assert-check on x and y + Color* pixel = pixels + (y * width + x); pixel->r = pixel->r - old_color.r / factor + new_color.r / factor; pixel->g = pixel->g - old_color.g / factor + new_color.g / factor; diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index 009d984..af9c6ff 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -48,33 +48,37 @@ void Rasterizer::pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pix double limit_width = (double)(canvas->getWidth() - 1); double limit_height = (double)(canvas->getHeight() - 1); + Vector3 canvas_offset(canvas->getXOffset(), canvas->getYOffset(), 0.0); + Vector3 dpixel1 = pixel1.sub(canvas_offset); + Vector3 dpixel2 = pixel2.sub(canvas_offset); + Vector3 dpixel3 = pixel3.sub(canvas_offset); + /* Filter if outside screen */ - if (pixel1.z < 1.0 || pixel2.z < 1.0 || pixel3.z < 1.0 || (pixel1.x < 0.0 && pixel2.x < 0.0 && pixel3.x < 0.0) || (pixel1.y < 0.0 && pixel2.y < 0.0 && pixel3.y < 0.0) || (pixel1.x > limit_width && pixel2.x > limit_width && pixel3.x > limit_width) || (pixel1.y > limit_height && pixel2.y > limit_height && pixel3.y > limit_height)) + if (dpixel1.z < 1.0 || dpixel2.z < 1.0 || dpixel3.z < 1.0 || (dpixel1.x < 0.0 && dpixel2.x < 0.0 && dpixel3.x < 0.0) || (dpixel1.y < 0.0 && dpixel2.y < 0.0 && dpixel3.y < 0.0) || (dpixel1.x > limit_width && dpixel2.x > limit_width && dpixel3.x > limit_width) || (dpixel1.y > limit_height && dpixel2.y > limit_height && dpixel3.y > limit_height)) { return; } /* Prepare vertices */ - // FIXME Apply canvas portion offset - point1.pixel.x = pixel1.x; - point1.pixel.y = pixel1.y; - point1.pixel.z = pixel1.z; + point1.pixel.x = dpixel1.x; + point1.pixel.y = dpixel1.y; + point1.pixel.z = dpixel1.z; point1.location.x = location1.x; point1.location.y = location1.y; point1.location.z = location1.z; point1.client = client_id; - point2.pixel.x = pixel2.x; - point2.pixel.y = pixel2.y; - point2.pixel.z = pixel2.z; + point2.pixel.x = dpixel2.x; + point2.pixel.y = dpixel2.y; + point2.pixel.z = dpixel2.z; point2.location.x = location2.x; point2.location.y = location2.y; point2.location.z = location2.z; point2.client = client_id; - point3.pixel.x = pixel3.x; - point3.pixel.y = pixel3.y; - point3.pixel.z = pixel3.z; + point3.pixel.x = dpixel3.x; + point3.pixel.y = dpixel3.y; + point3.pixel.z = dpixel3.z; point3.location.x = location3.x; point3.location.y = location3.y; point3.location.z = location3.z; diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index fde61ee..41890c5 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -51,11 +51,20 @@ void SoftwareCanvasRenderer::render() prepare(); - // TODO Iterate portions - CanvasPortion *portion = canvas->at(0, 0); - portion->preparePixels(); - rasterize(portion, true); - postProcess(portion, true); + // Iterate portions + int nx = canvas->getHorizontalPortionCount(); + int ny = canvas->getVerticalPortionCount(); + for (int y = 0; y < ny; y++) + { + for (int x = 0; x < nx; x++) + { + CanvasPortion *portion = canvas->at(x, y); + portion->preparePixels(); + rasterize(portion, true); + postProcess(portion, true); + portion->discardPixels(); + } + } } const std::vector &SoftwareCanvasRenderer::getRasterizers() const From 8f24d545684e88e0c189126fc4c1816805bff44e Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Tue, 19 Aug 2014 09:18:55 +0200 Subject: [PATCH 15/29] Restored render interruption --- src/render/software/CanvasPixelShader.cpp | 5 +++ src/render/software/CanvasPixelShader.h | 2 +- src/render/software/Rasterizer.cpp | 7 ++++ src/render/software/Rasterizer.h | 2 + src/render/software/SkyRasterizer.h | 4 +- .../software/SoftwareCanvasRenderer.cpp | 37 +++++++++++++++++-- src/render/software/SoftwareCanvasRenderer.h | 14 ++++--- src/render/software/SoftwareRenderer.h | 2 +- src/render/software/TerrainRasterizer.cpp | 4 -- src/render/software/TerrainRasterizer.h | 11 +----- src/render/software/WaterRasterizer.h | 4 +- src/system/ParallelWork.cpp | 5 +++ src/system/ParallelWork.h | 7 ++++ src/system/ParallelWorker.cpp | 6 +++ src/system/ParallelWorker.h | 8 ++++ 15 files changed, 90 insertions(+), 28 deletions(-) diff --git a/src/render/software/CanvasPixelShader.cpp b/src/render/software/CanvasPixelShader.cpp index 318d071..f1362aa 100644 --- a/src/render/software/CanvasPixelShader.cpp +++ b/src/render/software/CanvasPixelShader.cpp @@ -31,6 +31,11 @@ int CanvasPixelShader::processParallelUnit(int unit) { for (int y = 0; y < limit_y; y += sub_chunk_size) { + if (interrupted) + { + return 0; + } + if (sub_chunk_size == chunk_size or x % prev_sub_chunk_size != 0 or y % prev_sub_chunk_size != 0) { // Resolve the pixel color diff --git a/src/render/software/CanvasPixelShader.h b/src/render/software/CanvasPixelShader.h index ce321c1..c5fe190 100644 --- a/src/render/software/CanvasPixelShader.h +++ b/src/render/software/CanvasPixelShader.h @@ -20,7 +20,7 @@ class CanvasPixelShader: public ParallelWorker public: CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y); - virtual int processParallelUnit(int unit); + virtual int processParallelUnit(int unit) override; private: const SoftwareCanvasRenderer &renderer; diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index af9c6ff..a4e6067 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -35,6 +35,8 @@ Rasterizer::Rasterizer(SoftwareRenderer* renderer, int client_id, const Color &c renderer(renderer), client_id(client_id) { this->color = new Color(color); + + interrupted = false; } Rasterizer::~Rasterizer() @@ -42,6 +44,11 @@ Rasterizer::~Rasterizer() delete color; } +void Rasterizer::interrupt() +{ + interrupted = true; +} + void Rasterizer::pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3) { ScanPoint point1, point2, point3; diff --git a/src/render/software/Rasterizer.h b/src/render/software/Rasterizer.h index e364df6..a4157e8 100644 --- a/src/render/software/Rasterizer.h +++ b/src/render/software/Rasterizer.h @@ -22,6 +22,7 @@ public: virtual void rasterizeToCanvas(CanvasPortion* canvas) = 0; virtual Color shadeFragment(const CanvasFragment &fragment) const = 0; + virtual void interrupt(); protected: void pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3); @@ -34,6 +35,7 @@ protected: Color* color; SoftwareRenderer *renderer; int client_id; + bool interrupted; private: void scanGetDiff(ScanPoint *v1, ScanPoint *v2, ScanPoint *result); diff --git a/src/render/software/SkyRasterizer.h b/src/render/software/SkyRasterizer.h index 89436b9..39b09ab 100644 --- a/src/render/software/SkyRasterizer.h +++ b/src/render/software/SkyRasterizer.h @@ -13,8 +13,8 @@ class SOFTWARESHARED_EXPORT SkyRasterizer: public Rasterizer public: SkyRasterizer(SoftwareRenderer* renderer, int client_id); - virtual void rasterizeToCanvas(CanvasPortion* canvas); - virtual Color shadeFragment(const CanvasFragment &fragment) const; + virtual void rasterizeToCanvas(CanvasPortion* canvas) override; + virtual Color shadeFragment(const CanvasFragment &fragment) const override; }; } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 41890c5..9fdda8f 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -19,6 +19,8 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer() rasterizers.push_back(new SkyRasterizer(this, 0)); rasterizers.push_back(new WaterRasterizer(this, 1)); rasterizers.push_back(new TerrainRasterizer(this, 2)); + + current_work = NULL; } SoftwareCanvasRenderer::~SoftwareCanvasRenderer() @@ -59,14 +61,33 @@ void SoftwareCanvasRenderer::render() for (int x = 0; x < nx; x++) { CanvasPortion *portion = canvas->at(x, y); - portion->preparePixels(); - rasterize(portion, true); - postProcess(portion, true); + + if (not render_interrupt) + { + portion->preparePixels(); + rasterize(portion, true); + } + + if (not render_interrupt) + { + applyPixelShader(portion, true); + } + portion->discardPixels(); } } } +void SoftwareCanvasRenderer::interrupt() +{ + SoftwareRenderer::interrupt(); + + if (current_work) + { + current_work->interrupt(); + } +} + const std::vector &SoftwareCanvasRenderer::getRasterizers() const { return rasterizers; @@ -85,7 +106,7 @@ void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded) } } -void SoftwareCanvasRenderer::postProcess(CanvasPortion *portion, bool threaded) +void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion, bool threaded) { // Subdivide in chunks int chunk_size = 64; @@ -96,8 +117,16 @@ void SoftwareCanvasRenderer::postProcess(CanvasPortion *portion, bool threaded) // Render chunks in parallel for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2) { + if (render_interrupt) + { + break; + } + CanvasPixelShader shader(*this, portion, chunk_size, sub_chunk_size, chunks_x, chunks_y); ParallelWork work(&shader, units); + + current_work = &work; work.perform(); + current_work = NULL; } } diff --git a/src/render/software/SoftwareCanvasRenderer.h b/src/render/software/SoftwareCanvasRenderer.h index e18f150..93cf0cb 100644 --- a/src/render/software/SoftwareCanvasRenderer.h +++ b/src/render/software/SoftwareCanvasRenderer.h @@ -36,6 +36,8 @@ public: */ void render(); + virtual void interrupt() override; + /** * @brief Get the list of objects that can be rasterized to polygons on a canvas. */ @@ -52,19 +54,21 @@ protected: * * If 'threaded' is true, the rasterization will take advantage of multiple CPU cores. */ - void rasterize(CanvasPortion* portion, bool threaded); + void rasterize(CanvasPortion *portion, bool threaded=false); /** - * @brief Apply post-processing to fragments stored in the CanvasPortion. + * @brief Apply pixel shader to fragments stored in the CanvasPortion. * - * If 'threaded' is true, the post-processing will take advantage of multiple CPU cores. + * If 'threaded' is true, the shader will take advantage of multiple CPU cores. */ - void postProcess(CanvasPortion* portion, bool threaded=true); + void applyPixelShader(CanvasPortion *portion, bool threaded=true); private: - Canvas* canvas; + Canvas *canvas; std::vector rasterizers; bool started; + + ParallelWork *current_work; }; } diff --git a/src/render/software/SoftwareRenderer.h b/src/render/software/SoftwareRenderer.h index 04f8ded..cb6b278 100644 --- a/src/render/software/SoftwareRenderer.h +++ b/src/render/software/SoftwareRenderer.h @@ -67,7 +67,7 @@ public: void disableAtmosphere(); void disableAtmosphere(const std::vector &lights); - void interrupt(); + virtual void interrupt(); inline Scenery* getScenery() const {return scenery;} diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index ac0afdf..c0713a4 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -226,10 +226,6 @@ int TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chu return !renderer->render_interrupt; } -void TerrainRasterizer::rasterize() -{ -} - void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas) { queue = new ParallelQueue(); diff --git a/src/render/software/TerrainRasterizer.h b/src/render/software/TerrainRasterizer.h index 0e6537f..0ae3d7b 100644 --- a/src/render/software/TerrainRasterizer.h +++ b/src/render/software/TerrainRasterizer.h @@ -43,15 +43,8 @@ public: void renderQuad(CanvasPortion* canvas, double x, double z, double size, double water_height); - /** - * Start the final rasterization of terrain. - * - * This will push the rasterized quads in the render area, waiting for post process. - */ - virtual void rasterize(); - - virtual void rasterizeToCanvas(CanvasPortion* canvas); - virtual Color shadeFragment(const CanvasFragment &fragment) const; + virtual void rasterizeToCanvas(CanvasPortion* canvas) override; + virtual Color shadeFragment(const CanvasFragment &fragment) const override; private: ParallelQueue* queue; diff --git a/src/render/software/WaterRasterizer.h b/src/render/software/WaterRasterizer.h index 902d179..4d587ae 100644 --- a/src/render/software/WaterRasterizer.h +++ b/src/render/software/WaterRasterizer.h @@ -15,8 +15,8 @@ public: void rasterizeQuad(CanvasPortion* canvas, double x, double z, double size); - virtual void rasterizeToCanvas(CanvasPortion* canvas); - virtual Color shadeFragment(const CanvasFragment &fragment) const; + virtual void rasterizeToCanvas(CanvasPortion* canvas) override; + virtual Color shadeFragment(const CanvasFragment &fragment) const override; }; } diff --git a/src/system/ParallelWork.cpp b/src/system/ParallelWork.cpp index c77aca3..24a6096 100644 --- a/src/system/ParallelWork.cpp +++ b/src/system/ParallelWork.cpp @@ -172,6 +172,11 @@ int ParallelWork::perform(int thread_count) return done; } +void ParallelWork::interrupt() +{ + worker->interrupt(); +} + void ParallelWork::returnThread(ParallelWork::ParallelThread *thread) { mutex->acquire(); diff --git a/src/system/ParallelWork.h b/src/system/ParallelWork.h index 3e6d923..f1b6133 100644 --- a/src/system/ParallelWork.h +++ b/src/system/ParallelWork.h @@ -48,6 +48,13 @@ public: */ int perform(int thread_count=-1); + /** + * Tell the threads to interrupt what they are doing. + * + * This will also call interrupt() on the worker. + */ + void interrupt(); + private: void returnThread(ParallelThread *thread); diff --git a/src/system/ParallelWorker.cpp b/src/system/ParallelWorker.cpp index 0e64c57..d08dc7b 100644 --- a/src/system/ParallelWorker.cpp +++ b/src/system/ParallelWorker.cpp @@ -2,8 +2,14 @@ ParallelWorker::ParallelWorker() { + interrupted = false; } ParallelWorker::~ParallelWorker() { } + +void ParallelWorker::interrupt() +{ + interrupted = true; +} diff --git a/src/system/ParallelWorker.h b/src/system/ParallelWorker.h index b77f08c..2b90518 100644 --- a/src/system/ParallelWorker.h +++ b/src/system/ParallelWorker.h @@ -21,6 +21,14 @@ public: * This method will be called from any thread in the thread pool used by the ParallelWork. */ virtual int processParallelUnit(int unit) = 0; + + /** + * Method to reimplement to know when to interrupt the processing of units. + */ + virtual void interrupt(); + +protected: + bool interrupted; }; } From dc3584cefced7f59fa1960b7983194ea7f75f276 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Tue, 19 Aug 2014 11:25:27 +0200 Subject: [PATCH 16/29] Check canvas preview coordinates to avoid segfault --- src/interface/desktop/WidgetPreviewCanvas.cpp | 2 +- src/render/software/Canvas.cpp | 2 +- src/render/software/CanvasPreview.cpp | 22 ++++++-- src/render/software/CanvasPreview.h | 2 + src/tests/CanvasPortion_Test.cpp | 6 +++ src/tests/CanvasPreview_Test.cpp | 50 +++++++++++++++++++ src/tests/tests.pro | 3 +- 7 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 src/tests/CanvasPreview_Test.cpp diff --git a/src/interface/desktop/WidgetPreviewCanvas.cpp b/src/interface/desktop/WidgetPreviewCanvas.cpp index e1463f9..36ade57 100644 --- a/src/interface/desktop/WidgetPreviewCanvas.cpp +++ b/src/interface/desktop/WidgetPreviewCanvas.cpp @@ -25,7 +25,7 @@ void WidgetPreviewCanvas::setCanvas(const Canvas *canvas) this->canvas = canvas; } -void WidgetPreviewCanvas::paintEvent(QPaintEvent *event) +void WidgetPreviewCanvas::paintEvent(QPaintEvent *) { QPainter painter(this); painter.drawImage(0, 0, *pixbuf); diff --git a/src/render/software/Canvas.cpp b/src/render/software/Canvas.cpp index 4e4e746..7cf1439 100644 --- a/src/render/software/Canvas.cpp +++ b/src/render/software/Canvas.cpp @@ -70,7 +70,7 @@ void Canvas::setSize(int width, int height) this->height = height; // Smaller preview - while (width > 800 and height > 800) + while (width > 1000 or height > 700) { width = width / 2; height = height / 2; diff --git a/src/render/software/CanvasPreview.cpp b/src/render/software/CanvasPreview.cpp index f7cf1fc..5012911 100644 --- a/src/render/software/CanvasPreview.cpp +++ b/src/render/software/CanvasPreview.cpp @@ -7,6 +7,12 @@ #include +#define CHECK_COORDINATES(_x_, _y_) \ + assert(_x_ >= 0); \ + assert(_y_ >= 0); \ + assert(_x_ < this->width); \ + assert(_y_ < this->height) \ + CanvasPreview::CanvasPreview() { width = 1; @@ -34,6 +40,13 @@ CanvasPreview::~CanvasPreview() delete profile; } +const Color &CanvasPreview::getFinalPixel(int x, int y) const +{ + CHECK_COORDINATES(x, y); + + return pixels[y * width + x]; +} + void CanvasPreview::setSize(int real_width, int real_height, int preview_width, int preview_height) { lock->acquire(); @@ -110,8 +123,11 @@ void CanvasPreview::pushPixel(int real_x, int real_y, const Color &old_color, co if (scaled) { - x = round(real_x / factor_x); - y = round(real_y / factor_y); + x = int(real_x / factor_x); + y = int(real_y / factor_y); + + x = (x >= width) ? width - 1 : x; + y = (y >= height) ? height - 1 : y; } else { @@ -119,7 +135,7 @@ void CanvasPreview::pushPixel(int real_x, int real_y, const Color &old_color, co y = real_y; } - // TODO Assert-check on x and y + CHECK_COORDINATES(x, y); Color* pixel = pixels + (y * width + x); pixel->r = pixel->r - old_color.r / factor + new_color.r / factor; diff --git a/src/render/software/CanvasPreview.h b/src/render/software/CanvasPreview.h index f67cc39..dbcc0e4 100644 --- a/src/render/software/CanvasPreview.h +++ b/src/render/software/CanvasPreview.h @@ -18,6 +18,8 @@ public: inline int getWidth() const {return width;} inline int getHeight() const {return height;} + const Color &getFinalPixel(int x, int y) const; + void setSize(int real_width, int real_height, int preview_width, int preview_height); void reset(); diff --git a/src/tests/CanvasPortion_Test.cpp b/src/tests/CanvasPortion_Test.cpp index b88137c..c3e8cd2 100644 --- a/src/tests/CanvasPortion_Test.cpp +++ b/src/tests/CanvasPortion_Test.cpp @@ -21,6 +21,8 @@ TEST(CanvasPortion, pushFragment) int count; portion.setSize(50, 50); + portion.preparePixels(); + portion.pushFragment(10, 15, pushed); count = portion.getFragmentCount(10, 14); @@ -40,6 +42,7 @@ TEST(CanvasPortion, pushFragment_opaque) CanvasFragment pushed; portion.setSize(10, 10); + portion.preparePixels(); pushed = CanvasFragment(2.0, VECTOR_ZERO, 0); portion.pushFragment(2, 2, pushed); @@ -66,6 +69,7 @@ TEST(CanvasPortion, pushFragment_transparent) CanvasFragment pushed; portion.setSize(10, 10); + portion.preparePixels(); pushed = CanvasFragment(2.0, VECTOR_ZERO, 0, false); portion.pushFragment(2, 2, pushed); @@ -92,6 +96,8 @@ TEST(CanvasPortion, clear) CanvasFragment fragment; portion.setSize(10, 10); + portion.preparePixels(); + portion.pushFragment(5, 5, fragment); EXPECT_EQ(0, portion.getFragmentCount(4, 5)); diff --git a/src/tests/CanvasPreview_Test.cpp b/src/tests/CanvasPreview_Test.cpp new file mode 100644 index 0000000..e754267 --- /dev/null +++ b/src/tests/CanvasPreview_Test.cpp @@ -0,0 +1,50 @@ +#include "BaseTestCase.h" + +#include "CanvasPreview.h" +#include "Color.h" + +TEST(CanvasPreview, setSize) +{ + CanvasPreview preview; + + preview.setSize(800, 600, 400, 300); + + EXPECT_EQ(400, preview.getWidth()); + EXPECT_EQ(300, preview.getHeight()); +} + +TEST(CanvasPreview, pushPixel_accumulate) +{ + CanvasPreview preview; + Color col; + preview.setSize(800, 600, 400, 300); + + col = preview.getFinalPixel(0, 0); + EXPECT_COLOR_RGBA(col, 0.0, 0.0, 0.0, 1.0); + + preview.pushPixel(0, 0, COLOR_BLACK, COLOR_RED); + col = preview.getFinalPixel(0, 0); + EXPECT_COLOR_RGBA(col, 0.25, 0.0, 0.0, 1.0); + + preview.pushPixel(0, 1, COLOR_BLACK, COLOR_BLUE); + col = preview.getFinalPixel(0, 0); + EXPECT_COLOR_RGBA(col, 0.25, 0.0, 0.25, 1.0); + + preview.pushPixel(0, 2, COLOR_BLACK, COLOR_BLUE); + col = preview.getFinalPixel(0, 0); + EXPECT_COLOR_RGBA(col, 0.25, 0.0, 0.25, 1.0); + col = preview.getFinalPixel(0, 1); + EXPECT_COLOR_RGBA(col, 0.0, 0.0, 0.25, 1.0); + + preview.pushPixel(0, 1, COLOR_BLUE, COLOR_GREEN); + col = preview.getFinalPixel(0, 0); + EXPECT_COLOR_RGBA(col, 0.25, 0.25, 0.0, 1.0); +} + +TEST(CanvasPreview, pushPixel_border) +{ + CanvasPreview preview; + preview.setSize(759, 237, 9, 14); + + preview.pushPixel(759, 237, COLOR_BLACK, COLOR_RED); +} diff --git a/src/tests/tests.pro b/src/tests/tests.pro index 2efe000..481b17a 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -21,7 +21,8 @@ SOURCES += main.cpp \ VertexArray_Test.cpp \ FractalNoise_Test.cpp \ Canvas_Test.cpp \ - CanvasPortion_Test.cpp + CanvasPortion_Test.cpp \ + CanvasPreview_Test.cpp HEADERS += \ BaseTestCase.h From 915f43503ee71f8befb8c0313e09c7c84a094175 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Tue, 19 Aug 2014 11:32:23 +0200 Subject: [PATCH 17/29] Removed unused ParallelQueue --- src/render/software/CanvasFragment.cpp | 2 +- src/render/software/TerrainRasterizer.cpp | 36 +---- src/render/software/TerrainRasterizer.h | 3 - src/render/software/WaterRasterizer.cpp | 1 - src/system/ParallelQueue.cpp | 181 ---------------------- src/system/ParallelQueue.h | 94 ----------- src/system/system.pro | 2 - src/system/system_global.h | 1 - 8 files changed, 2 insertions(+), 318 deletions(-) delete mode 100644 src/system/ParallelQueue.cpp delete mode 100644 src/system/ParallelQueue.h diff --git a/src/render/software/CanvasFragment.cpp b/src/render/software/CanvasFragment.cpp index 7af7b90..20ce8a0 100644 --- a/src/render/software/CanvasFragment.cpp +++ b/src/render/software/CanvasFragment.cpp @@ -5,7 +5,7 @@ CanvasFragment::CanvasFragment() } CanvasFragment::CanvasFragment(double z, const Vector3 &location, int client, bool opaque): - z(z), location(location), client(client), opaque(opaque) + opaque(opaque), z(z), location(location), client(client) { color = COLOR_WHITE; } diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index c0713a4..9bea440 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -7,7 +7,6 @@ #include "WaterRenderer.h" #include "TexturesRenderer.h" #include "Scenery.h" -#include "ParallelQueue.h" #include "CanvasPortion.h" #include "CanvasFragment.h" @@ -189,38 +188,9 @@ void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, int displaced } } -typedef struct -{ - TerrainRasterizer* rasterizer; - CanvasPortion *canvas; - TerrainRasterizer::TerrainChunkInfo chunk; -} ParallelRasterInfo; - -static int _parallelJobCallback(ParallelQueue*, int, void* data, int stopping) -{ - ParallelRasterInfo* info = (ParallelRasterInfo*)data; - - if (!stopping) - { - info->rasterizer->tessellateChunk(info->canvas, &info->chunk, info->chunk.detail_hint); - } - - delete info; - return 0; -} - int TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double progress) { - ParallelRasterInfo* info = new ParallelRasterInfo; - - info->rasterizer = this; - info->canvas = canvas; - info->chunk = *chunk; - - if (!queue->addJob(_parallelJobCallback, info)) - { - delete info; - } + tessellateChunk(canvas, chunk, chunk->detail_hint); renderer->render_progress = 0.05 * progress; return !renderer->render_interrupt; @@ -228,13 +198,9 @@ int TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chu void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas) { - queue = new ParallelQueue(); - renderer->render_progress = 0.0; getTessellationInfo(canvas, 0); renderer->render_progress = 0.05; - - queue->wait(); } Color TerrainRasterizer::shadeFragment(const CanvasFragment &fragment) const diff --git a/src/render/software/TerrainRasterizer.h b/src/render/software/TerrainRasterizer.h index 0ae3d7b..b3abbfc 100644 --- a/src/render/software/TerrainRasterizer.h +++ b/src/render/software/TerrainRasterizer.h @@ -45,9 +45,6 @@ public: virtual void rasterizeToCanvas(CanvasPortion* canvas) override; virtual Color shadeFragment(const CanvasFragment &fragment) const override; - -private: - ParallelQueue* queue; }; } diff --git a/src/render/software/WaterRasterizer.cpp b/src/render/software/WaterRasterizer.cpp index ee9d681..428843b 100644 --- a/src/render/software/WaterRasterizer.cpp +++ b/src/render/software/WaterRasterizer.cpp @@ -2,7 +2,6 @@ #include "SoftwareRenderer.h" #include "WaterRenderer.h" -#include "ParallelQueue.h" #include "CanvasFragment.h" WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, int client_id): diff --git a/src/system/ParallelQueue.cpp b/src/system/ParallelQueue.cpp deleted file mode 100644 index 496b341..0000000 --- a/src/system/ParallelQueue.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "ParallelQueue.h" - -#include "Mutex.h" -#include "Thread.h" -#include "System.h" -#include - -#define QUEUE_SIZE 1000 - -static void* _queueThreadCallback(ParallelQueue* queue) -{ - ParallelQueue::ParallelJob* job; - - while (!queue->stopping) - { - /* Try to take a job */ - queue->lock->acquire(); - job = queue->jobs + queue->jobs_index_pending; - if (job->state == ParallelQueue::JOB_STATE_PENDING) - { - if (queue->jobs_index_pending >= QUEUE_SIZE - 1) - { - queue->jobs_index_pending = 0; - } - else - { - queue->jobs_index_pending++; - } - job->state = ParallelQueue::JOB_STATE_PROCESSING; - } - else - { - job = NULL; - } - queue->lock->release(); - - if (job) - { - /* Process the job */ - job->process(queue, job->id, job->data, 0); - - queue->lock->acquire(); - if (queue->collect) - { - job->state = ParallelQueue::JOB_STATE_TOCOLLECT; - /* TODO jobs_index_collect ? */ - } - else - { - job->state = ParallelQueue::JOB_STATE_FREE; - queue->jobs_count--; - } - queue->lock->release(); - } - else - { - Thread::timeSleepMs(50); - } - } - return NULL; -} - -ParallelQueue::ParallelQueue(int collect) -{ - int i; - - assert(!collect); /* Not fully implemented yet ! */ - - this->collect = collect; - this->stopping = 0; - this->lock = new Mutex(); - - this->jobs = new ParallelJob[QUEUE_SIZE]; - for (i = 0; i < QUEUE_SIZE; i++) - { - this->jobs[i].state = JOB_STATE_FREE; - } - this->jobs_count = 0; - this->jobs_index_free = 0; - this->jobs_index_collect = 0; - this->jobs_index_pending = 0; - this->jobs_next_id = 1; - - /* Start workers */ - this->workers_count = System::getCoreCount(); - this->workers = new Thread*[this->workers_count]; - for (i = 0; i < this->workers_count; i++) - { - this->workers[i] = new Thread((ThreadFunction)_queueThreadCallback); - this->workers[i]->start(this); - } -} - -ParallelQueue::~ParallelQueue() -{ - interrupt(); - - assert(not collect or jobs[jobs_index_collect].state != JOB_STATE_TOCOLLECT); - assert(jobs_count == 0); - - delete lock; - delete[] jobs; - delete[] workers; -} - -void ParallelQueue::interrupt() -{ - int i; - - if (not stopping) - { - stopping = 1; - - for (i = 0; i < workers_count; i++) - { - workers[i]->join(); - delete workers[i]; - } - } -} - -void ParallelQueue::wait() -{ - while (jobs_count > 0) - { - Thread::timeSleepMs(100); - } -} - -int ParallelQueue::addJob(FuncParallelJob func_process, void* data) -{ - if (stopping) - { - return 0; - } - - /* Wait for a free slot */ - while (jobs[jobs_index_free].state != JOB_STATE_FREE) - { - Thread::timeSleepMs(50); - if (stopping) - { - return 0; - } - } - - /* Prepare the job */ - ParallelJob job; - job.state = JOB_STATE_PENDING; - job.id = jobs_next_id++; - job.process = func_process; - job.data = data; - - /* Add the job to the queue */ - lock->acquire(); - if (stopping) - { - lock->release(); - return 0; - } - jobs[jobs_index_free] = job; - if (jobs_index_free >= QUEUE_SIZE - 1) - { - jobs_index_free = 0; - } - else - { - jobs_index_free++; - } - jobs_count++; - assert(jobs_count <= QUEUE_SIZE); - lock->release(); - - return job.id; -} - -int ParallelQueue::collectJobs(FuncParallelJob) -{ - /* TODO */ - return 0; -} diff --git a/src/system/ParallelQueue.h b/src/system/ParallelQueue.h deleted file mode 100644 index ae40a0d..0000000 --- a/src/system/ParallelQueue.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef PARALLELQUEUE_H -#define PARALLELQUEUE_H - -#include "system_global.h" - -namespace paysages { -namespace system { - -class SYSTEMSHARED_EXPORT ParallelQueue -{ -public: - typedef int (*FuncParallelJob)(ParallelQueue* queue, int job_id, void* data, int stopping); - - typedef enum - { - JOB_STATE_FREE, - JOB_STATE_PENDING, - JOB_STATE_PROCESSING, - JOB_STATE_TOCOLLECT - } EnumJobState; - - typedef struct - { - EnumJobState state; - int id; - FuncParallelJob process; - void* data; - } ParallelJob; - -public: - /** - * Create a parallel processing queue. - * - * This queue will use parallel workers to process jobs added to it. - * @param collect True to collect finished jobs and wait for a call to collectJobs, False to discard finished jobs. - * @return The newly allocated queue. - */ - ParallelQueue(int collect=0); - - /** - * Delete a parallel queue. - * - * This will interrupt the queue. - * If the queue is in collect mode, you should call interrupt, then collectJobs, before calling this. - */ - ~ParallelQueue(); - - /** - * Interrupt the queue processing. - * - * This will wait for running jobs to end, cancel pending jobs (still calling their callbacks with stopping=1) and - * refuse future jobs. - */ - void interrupt(); - - /** - * Wait for all jobs to finish. - * - * This function will return as soon as there is no pending jobs. It is recommended to stop feeding the queue, or this - * function may never return. - */ - void wait(); - - /** - * Add a job to the queue. - * - * Don't call this method concurrently from several threads. - * @param func_process The function that will be called for the job processing. - * @param data The data that will be passed to the callback. - * @return The job ID, 0 if the queue doesn't accept jobs. - */ - int addJob(FuncParallelJob func_process, void* data); - - int collectJobs(FuncParallelJob func_collect); - - int collect; - volatile int stopping; - Mutex* lock; - - int workers_count; - Thread** workers; - - ParallelJob* jobs; - int jobs_count; /** Number of jobs in queue (all status except JOB_STATE_FREE) */ - int jobs_index_free; /** Index of next free position */ - int jobs_index_collect; /** Index of first job to collect */ - int jobs_index_pending; /** Index of first pending job to process */ - int jobs_next_id; -}; - -} -} - -#endif // PARALLELQUEUE_H diff --git a/src/system/system.pro b/src/system/system.pro index 2e2f3c1..ceac911 100644 --- a/src/system/system.pro +++ b/src/system/system.pro @@ -21,7 +21,6 @@ SOURCES += \ RandomGenerator.cpp \ Memory.cpp \ ParallelWork.cpp \ - ParallelQueue.cpp \ CacheFile.cpp \ PictureWriter.cpp \ Logs.cpp \ @@ -38,7 +37,6 @@ HEADERS += \ RandomGenerator.h \ Memory.h \ ParallelWork.h \ - ParallelQueue.h \ CacheFile.h \ PictureWriter.h \ Logs.h \ diff --git a/src/system/system_global.h b/src/system/system_global.h index 3b003bc..80b4d3c 100644 --- a/src/system/system_global.h +++ b/src/system/system_global.h @@ -15,7 +15,6 @@ namespace paysages { namespace system { class PackStream; - class ParallelQueue; class ParallelWork; class ParallelPool; class ParallelWorker; From 0c48fb075f0924eaa00b86f4b6f78c60b465f3f2 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Tue, 19 Aug 2014 11:44:54 +0200 Subject: [PATCH 18/29] Rasterizers now use their own interrupt system --- src/render/software/CanvasPixelShader.cpp | 6 ++---- src/render/software/CanvasPixelShader.h | 2 +- src/render/software/SkyRasterizer.cpp | 2 +- src/render/software/SoftwareCanvasRenderer.cpp | 4 ++++ src/render/software/TerrainRasterizer.cpp | 15 +++++++++------ src/render/software/TerrainRasterizer.h | 2 +- src/render/software/WaterRasterizer.cpp | 2 +- src/system/ParallelWork.cpp | 4 ++-- src/system/ParallelWorker.h | 2 +- 9 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/render/software/CanvasPixelShader.cpp b/src/render/software/CanvasPixelShader.cpp index f1362aa..ee8b9a9 100644 --- a/src/render/software/CanvasPixelShader.cpp +++ b/src/render/software/CanvasPixelShader.cpp @@ -12,7 +12,7 @@ CanvasPixelShader::CanvasPixelShader(const SoftwareCanvasRenderer &renderer, Can { } -int CanvasPixelShader::processParallelUnit(int unit) +void CanvasPixelShader::processParallelUnit(int unit) { // Locate the chunk we work on int prev_sub_chunk_size = chunk_size * 2; @@ -33,7 +33,7 @@ int CanvasPixelShader::processParallelUnit(int unit) { if (interrupted) { - return 0; + return; } if (sub_chunk_size == chunk_size or x % prev_sub_chunk_size != 0 or y % prev_sub_chunk_size != 0) @@ -60,6 +60,4 @@ int CanvasPixelShader::processParallelUnit(int unit) } } } - - return 0; } diff --git a/src/render/software/CanvasPixelShader.h b/src/render/software/CanvasPixelShader.h index c5fe190..76a6c75 100644 --- a/src/render/software/CanvasPixelShader.h +++ b/src/render/software/CanvasPixelShader.h @@ -20,7 +20,7 @@ class CanvasPixelShader: public ParallelWorker public: CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y); - virtual int processParallelUnit(int unit) override; + virtual void processParallelUnit(int unit) override; private: const SoftwareCanvasRenderer &renderer; diff --git a/src/render/software/SkyRasterizer.cpp b/src/render/software/SkyRasterizer.cpp index b8251c7..57866ae 100644 --- a/src/render/software/SkyRasterizer.cpp +++ b/src/render/software/SkyRasterizer.cpp @@ -34,7 +34,7 @@ void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas) for (j = 0; j < res_j; j++) { - if (!renderer->addRenderProgress(0.0)) + if (interrupted) { return; } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 9fdda8f..3d417a3 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -86,6 +86,10 @@ void SoftwareCanvasRenderer::interrupt() { current_work->interrupt(); } + for (auto &rasterizer:getRasterizers()) + { + rasterizer->interrupt(); + } } const std::vector &SoftwareCanvasRenderer::getRasterizers() const diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index 9bea440..815c7aa 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -152,25 +152,29 @@ void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, int displaced for (i = 0; i < chunk_count - 1; i++) { _getChunk(renderer, &chunk, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size, displaced); - if (!processChunk(canvas, &chunk, progress)) + processChunk(canvas, &chunk, progress); + if (interrupted) { return; } _getChunk(renderer, &chunk, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size, displaced); - if (!processChunk(canvas, &chunk, progress)) + processChunk(canvas, &chunk, progress); + if (interrupted) { return; } _getChunk(renderer, &chunk, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size, displaced); - if (!processChunk(canvas, &chunk, progress)) + processChunk(canvas, &chunk, progress); + if (interrupted) { return; } _getChunk(renderer, &chunk, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size, displaced); - if (!processChunk(canvas, &chunk, progress)) + processChunk(canvas, &chunk, progress); + if (interrupted) { return; } @@ -188,12 +192,11 @@ void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, int displaced } } -int TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double progress) +void TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double progress) { tessellateChunk(canvas, chunk, chunk->detail_hint); renderer->render_progress = 0.05 * progress; - return !renderer->render_interrupt; } void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas) diff --git a/src/render/software/TerrainRasterizer.h b/src/render/software/TerrainRasterizer.h index b3abbfc..379c046 100644 --- a/src/render/software/TerrainRasterizer.h +++ b/src/render/software/TerrainRasterizer.h @@ -27,7 +27,7 @@ public: /** * Method called for each chunk tessellated by getTessellationInfo. */ - int processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double progress); + void processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double progress); /** * Tessellate the terrain, calling processChunk for each chunk. diff --git a/src/render/software/WaterRasterizer.cpp b/src/render/software/WaterRasterizer.cpp index 428843b..16c82b1 100644 --- a/src/render/software/WaterRasterizer.cpp +++ b/src/render/software/WaterRasterizer.cpp @@ -55,7 +55,7 @@ void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas) while (radius_int < 20000.0) { - if (!renderer->addRenderProgress(0.0)) + if (interrupted) { return; } diff --git a/src/system/ParallelWork.cpp b/src/system/ParallelWork.cpp index 24a6096..fd6338a 100644 --- a/src/system/ParallelWork.cpp +++ b/src/system/ParallelWork.cpp @@ -18,9 +18,9 @@ public: { } - virtual int processParallelUnit(int unit) + virtual void processParallelUnit(int unit) { - return func(work, unit, data); + func(work, unit, data); } private: diff --git a/src/system/ParallelWorker.h b/src/system/ParallelWorker.h index 2b90518..1d6d8b4 100644 --- a/src/system/ParallelWorker.h +++ b/src/system/ParallelWorker.h @@ -20,7 +20,7 @@ public: * * This method will be called from any thread in the thread pool used by the ParallelWork. */ - virtual int processParallelUnit(int unit) = 0; + virtual void processParallelUnit(int unit) = 0; /** * Method to reimplement to know when to interrupt the processing of units. From 1bf6d9382bfcc982385337930996876135055ed7 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Tue, 19 Aug 2014 12:22:27 +0200 Subject: [PATCH 19/29] Removed size information from SoftwareRenderer + removed full render tests --- .../software/SoftwareCanvasRenderer.cpp | 2 - src/render/software/SoftwareRenderer.cpp | 2 - src/render/software/SoftwareRenderer.h | 2 - src/tests/Bruneton_Test.cpp | 83 ----------------- src/tests/Render_Test.cpp | 90 ------------------- src/tests/tests.pro | 2 - 6 files changed, 181 deletions(-) delete mode 100644 src/tests/Bruneton_Test.cpp delete mode 100644 src/tests/Render_Test.cpp diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 3d417a3..87e45da 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -45,8 +45,6 @@ void SoftwareCanvasRenderer::render() { // TEMP started = true; - render_width = canvas->getWidth(); - render_height = canvas->getHeight(); render_quality = 3; render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight()); diff --git a/src/render/software/SoftwareRenderer.cpp b/src/render/software/SoftwareRenderer.cpp index 3ab791b..a12f762 100644 --- a/src/render/software/SoftwareRenderer.cpp +++ b/src/render/software/SoftwareRenderer.cpp @@ -23,8 +23,6 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery) { render_quality = 5; - render_width = 1; - render_height = 1; render_interrupt = 0; render_progress = 0.0; is_rendering = 0; diff --git a/src/render/software/SoftwareRenderer.h b/src/render/software/SoftwareRenderer.h index cb6b278..3ddc34a 100644 --- a/src/render/software/SoftwareRenderer.h +++ b/src/render/software/SoftwareRenderer.h @@ -20,8 +20,6 @@ public: /* Render base configuration */ int render_quality; - int render_width; - int render_height; CameraDefinition* render_camera; /* Render related */ diff --git a/src/tests/Bruneton_Test.cpp b/src/tests/Bruneton_Test.cpp deleted file mode 100644 index dcce68a..0000000 --- a/src/tests/Bruneton_Test.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "BaseTestCase.h" - -#include "CameraDefinition.h" -#include "SoftwareRenderer.h" -#include "AtmosphereDefinition.h" -#include "AtmosphereRenderer.h" -#include "AtmosphereResult.h" -#include "Scenery.h" -#include "System.h" - -#define OUTPUT_WIDTH 400 -#define OUTPUT_HEIGHT 300 - -static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &location, void*) -{ - return renderer->getAtmosphereRenderer()->applyAerialPerspective(location, COLOR_BLACK).final; -} - -TEST(Bruneton, AerialPerspective1) -{ -#ifndef TESTS_FULL - return; -#endif - Scenery scenery; - SoftwareRenderer renderer(&scenery); - renderer.render_width = 800; - renderer.render_height = 600; - renderer.render_quality = 1; - - renderer.render_camera->setLocation(VECTOR_ZERO); - renderer.render_camera->setTarget(VECTOR_EAST); - renderer.render_camera->setRenderSize(renderer.render_width, renderer.render_height); - - /*RenderArea::RenderParams params = {renderer.render_width, renderer.render_height, 1, 1}; - renderer.render_area->setParams(params); - renderer.render_area->setBackgroundColor(COLOR_BLACK); - renderer.render_area->clear(); - - renderer.pushQuad(Vector3(50.0, -10.0, -50.0), Vector3(1.0, -10.0, -50.0), Vector3(1.0, -10.0, 50.0), Vector3(50.0, -10.0, 50.0), _postProcessFragment, NULL); - renderer.pushQuad(Vector3(10.0, -10.0, -10.0), Vector3(10.0, -10.0, -5.0), Vector3(10.0, 50.0, -5.0), Vector3(10.0, 50.0, -10.0), _postProcessFragment, NULL); - renderer.pushQuad(Vector3(15.0, -10.0, -5.0), Vector3(15.0, -10.0, 0.0), Vector3(15.0, 50.0, 0.0), Vector3(15.0, 50.0, -5.0), _postProcessFragment, NULL); - renderer.pushQuad(Vector3(20.0, -10.0, 5.0), Vector3(20.0, -10.0, 10.0), Vector3(20.0, 50.0, 10.0), Vector3(20.0, 50.0, 5.0), _postProcessFragment, NULL); - renderer.pushQuad(Vector3(30.0, -10.0, 25.0), Vector3(30.0, -10.0, 30.0), Vector3(30.0, 50.0, 30.0), Vector3(30.0, 50.0, 25.0), _postProcessFragment, NULL); - renderer.render_area->postProcess(System::getCoreCount()); - - renderer.render_area->saveToFile("./output/test_bruneton_perspective.png");*/ -} - -TEST(Bruneton, AerialPerspective2) -{ -#ifndef TESTS_FULL - return; -#endif - Scenery scenery; - - AtmosphereDefinition* atmo = scenery.getAtmosphere(); - atmo->hour = 6; - atmo->minute = 30; - atmo->validate(); - - SoftwareRenderer renderer(&scenery); - renderer.render_width = 800; - renderer.render_height = 600; - renderer.render_quality = 1; - - renderer.render_camera->setLocation(VECTOR_ZERO); - renderer.render_camera->setTarget(VECTOR_EAST); - renderer.render_camera->setRenderSize(renderer.render_width, renderer.render_height); - - /*RenderArea::RenderParams params = {renderer.render_width, renderer.render_height, 1, 1}; - renderer.render_area->setParams(params); - renderer.render_area->setBackgroundColor(COLOR_BLACK); - renderer.render_area->clear(); - - renderer.pushQuad(Vector3(50.0, -10.0, -50.0), Vector3(1.0, -10.0, -50.0), Vector3(1.0, -10.0, 50.0), Vector3(50.0, -10.0, 50.0), _postProcessFragment, NULL); - renderer.pushQuad(Vector3(10.0, -10.0, -10.0), Vector3(10.0, -10.0, -5.0), Vector3(10.0, 50.0, -5.0), Vector3(10.0, 50.0, -10.0), _postProcessFragment, NULL); - renderer.pushQuad(Vector3(15.0, -10.0, -5.0), Vector3(15.0, -10.0, 0.0), Vector3(15.0, 50.0, 0.0), Vector3(15.0, 50.0, -5.0), _postProcessFragment, NULL); - renderer.pushQuad(Vector3(20.0, -10.0, 5.0), Vector3(20.0, -10.0, 10.0), Vector3(20.0, 50.0, 10.0), Vector3(20.0, 50.0, 5.0), _postProcessFragment, NULL); - renderer.pushQuad(Vector3(30.0, -10.0, 25.0), Vector3(30.0, -10.0, 30.0), Vector3(30.0, 50.0, 30.0), Vector3(30.0, 50.0, 25.0), _postProcessFragment, NULL); - renderer.render_area->postProcess(System::getCoreCount()); - - renderer.render_area->saveToFile("./output/test_bruneton_perspective1.png");*/ -} diff --git a/src/tests/Render_Test.cpp b/src/tests/Render_Test.cpp deleted file mode 100644 index a98803d..0000000 --- a/src/tests/Render_Test.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "BaseTestCase.h" - -#include -#include "SoftwareRenderer.h" -#include "CameraDefinition.h" -#include "ColorProfile.h" -#include "System.h" - -static Color _postProcessFragment(SoftwareRenderer*, const Vector3 &location, void*) -{ - /* Checker-board */ - double x = fmod(location.x, 0.2); - double z = fmod(location.z, 0.2); - if (x < 0.0) - { - x = 0.2 + x; - } - if (z < 0.0) - { - z = 0.2 + z; - } - if ((x > 0.1) ^ (z > 0.1)) - { - return COLOR_WHITE; - } - else - { - return COLOR_BLACK; - } -} - -static void _render_quad_checker(SoftwareRenderer &renderer) -{ - renderer.render_width = 800; - renderer.render_height = 600; - renderer.render_quality = 1; - //renderer.render_area->setToneMapping(ColorProfile(ColorProfile::TONE_MAPPING_CLAMP, 0.0)); - - renderer.render_camera->setRenderSize(renderer.render_width, renderer.render_height); - renderer.render_camera->setFov(1.57); - - /*RenderConfig params(renderer.render_width, renderer.render_height, 1, 1); - renderer.render_area->setParams(params); - - renderer.render_area->setBackgroundColor(COLOR_BLUE); - renderer.render_area->clear(); - - renderer.pushQuad(Vector3(-1.0, 0.0, 1.0), Vector3(-1.0, 0.0, -1.0), Vector3(1.0, 0.0, -1.0), Vector3(1.0, 0.0, 1.0), _postProcessFragment, NULL); - renderer.render_area->postProcess(System::getCoreCount());*/ -} - -TEST(Render, quad) -{ -#ifndef TESTS_FULL - return; -#endif - SoftwareRenderer renderer; - - renderer.render_camera->setLocationCoords(0.0, 0.5, 2.0); - renderer.render_camera->setTargetCoords(0.0, 0.5, 0.0); - - _render_quad_checker(renderer); - - /*Color col; - col = renderer.render_area->getPixel(399, 599 - 435); - ASSERT_COLOR_RGBA(col, 1.0, 1.0, 1.0, 1.0); - col = renderer.render_area->getPixel(399, 599 - 436); - ASSERT_COLOR_RGBA(col, 0.0, 0.0, 0.0, 1.0); - col = renderer.render_area->getPixel(400, 599 - 435); - ASSERT_COLOR_RGBA(col, 0.0, 0.0, 0.0, 1.0); - col = renderer.render_area->getPixel(400, 599 - 436); - ASSERT_COLOR_RGBA(col, 1.0, 1.0, 1.0, 1.0); - - renderer.render_area->saveToFile("./output/test_render_quad.png");*/ -} - -TEST(Render, quad_cut) -{ -#ifndef TESTS_FULL - return; -#endif - SoftwareRenderer renderer; - - renderer.render_camera->setLocationCoords(0.8, 0.7, 1.0); - renderer.render_camera->setTargetCoords(0.0, 0.0, -0.5); - - _render_quad_checker(renderer); - - //renderer.render_area->saveToFile("./output/test_render_quad_cut.png"); -} diff --git a/src/tests/tests.pro b/src/tests/tests.pro index 481b17a..f01b4e3 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -10,11 +10,9 @@ SOURCES += main.cpp \ Layers_Test.cpp \ PackStream_Test.cpp \ NoiseGenerator_Test.cpp \ - Render_Test.cpp \ TerrainPainting_Test.cpp \ Zone_Test.cpp \ Euclid_Test.cpp \ - Bruneton_Test.cpp \ Camera_Test.cpp \ Clouds_Test.cpp \ FluidMediumManager_Test.cpp \ From 2b135eedac4149294b841c2be23b70774b4f8549 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Tue, 19 Aug 2014 14:20:37 +0200 Subject: [PATCH 20/29] Removed old render_progress in SoftwareRenderer --- src/render/software/Rasterizer.cpp | 12 ++++++++++++ src/render/software/Rasterizer.h | 6 ++++++ src/render/software/SoftwareCanvasRenderer.cpp | 9 +++++---- src/render/software/SoftwareCanvasRenderer.h | 6 +++++- src/render/software/SoftwareRenderer.cpp | 13 ------------- src/render/software/SoftwareRenderer.h | 8 -------- src/render/software/TerrainRasterizer.cpp | 4 ---- 7 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index a4e6067..c75fe08 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -37,6 +37,8 @@ Rasterizer::Rasterizer(SoftwareRenderer* renderer, int client_id, const Color &c this->color = new Color(color); interrupted = false; + predicted_poly_count = 0; + done_poly_count = 0; } Rasterizer::~Rasterizer() @@ -49,6 +51,16 @@ void Rasterizer::interrupt() interrupted = true; } +void Rasterizer::addPredictedPolys(int count) +{ + predicted_poly_count += count; +} + +void Rasterizer::addDonePolys(int count) +{ + done_poly_count += count; +} + void Rasterizer::pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3) { ScanPoint point1, point2, point3; diff --git a/src/render/software/Rasterizer.h b/src/render/software/Rasterizer.h index a4157e8..b633bc2 100644 --- a/src/render/software/Rasterizer.h +++ b/src/render/software/Rasterizer.h @@ -25,6 +25,9 @@ public: virtual void interrupt(); protected: + void addPredictedPolys(int count=1); + void addDonePolys(int count=1); + void pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3); void pushTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3); @@ -43,6 +46,9 @@ private: void pushScanPoint(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point); void pushScanLineEdge(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point1, ScanPoint *point2); void renderScanLines(CanvasPortion *canvas, RenderScanlines *scanlines); + + int predicted_poly_count; + int done_poly_count; }; } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 87e45da..186a0dc 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -14,6 +14,7 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer() { started = false; + interrupted = false; canvas = new Canvas(); rasterizers.push_back(new SkyRasterizer(this, 0)); @@ -60,13 +61,13 @@ void SoftwareCanvasRenderer::render() { CanvasPortion *portion = canvas->at(x, y); - if (not render_interrupt) + if (not interrupted) { portion->preparePixels(); rasterize(portion, true); } - if (not render_interrupt) + if (not interrupted) { applyPixelShader(portion, true); } @@ -78,7 +79,7 @@ void SoftwareCanvasRenderer::render() void SoftwareCanvasRenderer::interrupt() { - SoftwareRenderer::interrupt(); + interrupted = true; if (current_work) { @@ -119,7 +120,7 @@ void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion, bool threa // Render chunks in parallel for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2) { - if (render_interrupt) + if (interrupted) { break; } diff --git a/src/render/software/SoftwareCanvasRenderer.h b/src/render/software/SoftwareCanvasRenderer.h index 93cf0cb..291182a 100644 --- a/src/render/software/SoftwareCanvasRenderer.h +++ b/src/render/software/SoftwareCanvasRenderer.h @@ -36,7 +36,10 @@ public: */ void render(); - virtual void interrupt() override; + /** + * @brief Interrupt the render process. + */ + void interrupt(); /** * @brief Get the list of objects that can be rasterized to polygons on a canvas. @@ -67,6 +70,7 @@ private: Canvas *canvas; std::vector rasterizers; bool started; + bool interrupted; ParallelWork *current_work; }; diff --git a/src/render/software/SoftwareRenderer.cpp b/src/render/software/SoftwareRenderer.cpp index a12f762..548858c 100644 --- a/src/render/software/SoftwareRenderer.cpp +++ b/src/render/software/SoftwareRenderer.cpp @@ -23,9 +23,6 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery) { render_quality = 5; - render_interrupt = 0; - render_progress = 0.0; - is_rendering = 0; render_camera = new CameraDefinition; atmosphere_renderer = new BaseAtmosphereRenderer(this); @@ -145,11 +142,6 @@ void SoftwareRenderer::disableAtmosphere(const std::vector &ligh atmosphere_renderer->setStaticLights(lights); } -void SoftwareRenderer::interrupt() -{ - render_interrupt = 1; -} - Color SoftwareRenderer::applyLightingToSurface(const Vector3 &location, const Vector3 &normal, const SurfaceMaterial &material) { LightStatus status(lighting, location, getCameraLocation(location)); @@ -185,11 +177,6 @@ RayCastingResult SoftwareRenderer::rayWalking(const Vector3 &location, const Vec return result; } -int SoftwareRenderer::addRenderProgress(double) -{ - return not render_interrupt; -} - Vector3 SoftwareRenderer::getCameraLocation(const Vector3 &) { return render_camera->getLocation(); diff --git a/src/render/software/SoftwareRenderer.h b/src/render/software/SoftwareRenderer.h index 3ddc34a..b1d8fa9 100644 --- a/src/render/software/SoftwareRenderer.h +++ b/src/render/software/SoftwareRenderer.h @@ -22,11 +22,6 @@ public: int render_quality; CameraDefinition* render_camera; - /* Render related */ - double render_progress; - int render_interrupt; - int is_rendering; - void* customData[10]; virtual Vector3 getCameraLocation(const Vector3 &target); @@ -34,7 +29,6 @@ public: virtual double getPrecision(const Vector3 &location); virtual Vector3 projectPoint(const Vector3 &point); virtual Vector3 unprojectPoint(const Vector3 &point); - virtual int addRenderProgress(double progress); /*! * \brief Set the scenery to render. @@ -65,8 +59,6 @@ public: void disableAtmosphere(); void disableAtmosphere(const std::vector &lights); - virtual void interrupt(); - inline Scenery* getScenery() const {return scenery;} inline BaseAtmosphereRenderer* getAtmosphereRenderer() const {return atmosphere_renderer;} diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index 815c7aa..14e7b55 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -195,15 +195,11 @@ void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, int displaced void TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double progress) { tessellateChunk(canvas, chunk, chunk->detail_hint); - - renderer->render_progress = 0.05 * progress; } void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas) { - renderer->render_progress = 0.0; getTessellationInfo(canvas, 0); - renderer->render_progress = 0.05; } Color TerrainRasterizer::shadeFragment(const CanvasFragment &fragment) const From 8ef8b0386cc7d569d163a70a8ada1e4fac9a1fa2 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Wed, 20 Aug 2014 14:23:35 +0200 Subject: [PATCH 21/29] Canvas preview widget is immediately sized (so that render dialog don't resize later) --- src/interface/desktop/WidgetPreviewCanvas.cpp | 13 ++++------ src/interface/desktop/WidgetPreviewCanvas.h | 3 ++- .../desktop/common/freeformhelper.cpp | 10 ++++---- src/interface/desktop/dialogrender.cpp | 18 +++----------- src/interface/desktop/dialogrender.h | 4 +--- src/interface/desktop/formrender.cpp | 24 +++++++++---------- .../software/SoftwareCanvasRenderer.cpp | 12 ++++++++-- src/render/software/SoftwareCanvasRenderer.h | 5 ++++ 8 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/interface/desktop/WidgetPreviewCanvas.cpp b/src/interface/desktop/WidgetPreviewCanvas.cpp index 36ade57..74b3fd4 100644 --- a/src/interface/desktop/WidgetPreviewCanvas.cpp +++ b/src/interface/desktop/WidgetPreviewCanvas.cpp @@ -10,7 +10,6 @@ WidgetPreviewCanvas::WidgetPreviewCanvas(QWidget *parent) : QWidget(parent), canvas(NULL) { pixbuf = new QImage(); - inited = false; startTimer(500); } @@ -22,7 +21,11 @@ WidgetPreviewCanvas::~WidgetPreviewCanvas() void WidgetPreviewCanvas::setCanvas(const Canvas *canvas) { - this->canvas = canvas; + if (not this->canvas) + { + this->canvas = canvas; + canvas->getPreview()->initLive(this); + } } void WidgetPreviewCanvas::paintEvent(QPaintEvent *) @@ -58,12 +61,6 @@ void WidgetPreviewCanvas::timerEvent(QTimerEvent *) { if (canvas) { - if (!inited) - { - canvas->getPreview()->initLive(this); - inited = true; - } - canvas->getPreview()->updateLive(this); update(); } diff --git a/src/interface/desktop/WidgetPreviewCanvas.h b/src/interface/desktop/WidgetPreviewCanvas.h index a862fc9..097ce57 100644 --- a/src/interface/desktop/WidgetPreviewCanvas.h +++ b/src/interface/desktop/WidgetPreviewCanvas.h @@ -21,6 +21,8 @@ public: /*! * \brief 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); @@ -35,7 +37,6 @@ protected: private: QImage* pixbuf; const Canvas *canvas; - bool inited; }; } diff --git a/src/interface/desktop/common/freeformhelper.cpp b/src/interface/desktop/common/freeformhelper.cpp index ad0bcae..aee47fa 100644 --- a/src/interface/desktop/common/freeformhelper.cpp +++ b/src/interface/desktop/common/freeformhelper.cpp @@ -247,16 +247,16 @@ void FreeFormHelper::processExploreClicked() void FreeFormHelper::processRenderClicked() { + RenderConfig params(400, 300, 1, 3); + SoftwareCanvasRenderer renderer; + renderer.setConfig(params); renderer.setScenery(DesktopScenery::getCurrent()); emit needAlterRenderer(&renderer); - DialogRender* dialog = new DialogRender(_form_widget, &renderer); - RenderConfig params(400, 300, 1, 3); - dialog->startRender(params); - - delete dialog; + DialogRender dialog(_form_widget, &renderer); + dialog.startRender(); } void FreeFormHelper::processDecimalChange(double value) diff --git a/src/interface/desktop/dialogrender.cpp b/src/interface/desktop/dialogrender.cpp index 0cdcdf2..63344f4 100644 --- a/src/interface/desktop/dialogrender.cpp +++ b/src/interface/desktop/dialogrender.cpp @@ -18,7 +18,6 @@ #include #include "tools.h" -#include "RenderConfig.h" #include "Scenery.h" #include "ColorProfile.h" #include "SoftwareCanvasRenderer.h" @@ -27,22 +26,19 @@ class RenderThread:public QThread { public: - RenderThread(DialogRender* dialog, SoftwareCanvasRenderer* renderer, const RenderConfig ¶ms):QThread() + RenderThread(DialogRender* dialog, SoftwareCanvasRenderer* renderer):QThread() { _dialog = dialog; _renderer = renderer; - _params = params; } void run() { - // FIXME Pass config to render _renderer->render(); _dialog->tellRenderEnded(); } private: DialogRender* _dialog; SoftwareCanvasRenderer* _renderer; - RenderConfig _params; }; DialogRender::DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer): @@ -98,7 +94,6 @@ DialogRender::DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer): _actions->layout()->addWidget(_save_button); // Connections - //connect(this, SIGNAL(renderSizeChanged(int, int)), this, SLOT(applyRenderSize(int, int))); connect(this, SIGNAL(progressChanged(double)), this, SLOT(applyProgress(double))); connect(this, SIGNAL(renderEnded()), this, SLOT(applyRenderEnded())); connect(_save_button, SIGNAL(clicked()), this, SLOT(saveRender())); @@ -119,11 +114,6 @@ DialogRender::~DialogRender() delete pixbuf_lock; } -void DialogRender::tellRenderSize(int width, int height) -{ - emit renderSizeChanged(width, height); -} - void DialogRender::tellProgressChange(double value) { emit progressChanged(value); @@ -134,13 +124,11 @@ void DialogRender::tellRenderEnded() emit renderEnded(); } -void DialogRender::startRender(const RenderConfig ¶ms) +void DialogRender::startRender() { _started = time(NULL); - canvas_renderer->setSize(params.width, params.height, params.antialias); - - _render_thread = new RenderThread(this, canvas_renderer, params); + _render_thread = new RenderThread(this, canvas_renderer); _render_thread->start(); exec(); diff --git a/src/interface/desktop/dialogrender.h b/src/interface/desktop/dialogrender.h index 5091fa5..9206b12 100644 --- a/src/interface/desktop/dialogrender.h +++ b/src/interface/desktop/dialogrender.h @@ -21,10 +21,9 @@ public: explicit DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer); ~DialogRender(); - void tellRenderSize(int width, int height); void tellProgressChange(double value); void tellRenderEnded(); - void startRender(const RenderConfig ¶ms); + void startRender(); void loadLastRender(); QImage* pixbuf; @@ -37,7 +36,6 @@ private slots: void toneMappingChanged(); signals: - void renderSizeChanged(int width, int height); void progressChanged(double value); void renderEnded(); diff --git a/src/interface/desktop/formrender.cpp b/src/interface/desktop/formrender.cpp index 489e7bb..2b9150f 100644 --- a/src/interface/desktop/formrender.cpp +++ b/src/interface/desktop/formrender.cpp @@ -103,15 +103,16 @@ void FormRender::startQuickRender() { delete _renderer; } + + RenderConfig config(400, 300, 1, 3); + _renderer = new SoftwareCanvasRenderer(); _renderer->setScenery(DesktopScenery::getCurrent()); + _renderer->setConfig(config); _renderer_inited = true; - DialogRender* dialog = new DialogRender(this, _renderer); - RenderConfig params(400, 300, 1, 3); - dialog->startRender(params); - - delete dialog; + DialogRender dialog(this, _renderer); + dialog.startRender(); } void FormRender::startRender() @@ -122,21 +123,18 @@ void FormRender::startRender() } _renderer = new SoftwareCanvasRenderer(); _renderer->setScenery(DesktopScenery::getCurrent()); + _renderer->setConfig(_params); _renderer_inited = true; - DialogRender* dialog = new DialogRender(this, _renderer); - dialog->startRender(_params); - - delete dialog; + DialogRender dialog(this, _renderer); + dialog.startRender(); } void FormRender::showRender() { if (_renderer_inited) { - DialogRender* dialog = new DialogRender(this, _renderer); - dialog->loadLastRender(); - - delete dialog; + DialogRender dialog(this, _renderer); + dialog.loadLastRender(); } } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 186a0dc..7b88187 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -10,6 +10,7 @@ #include "ParallelWork.h" #include "CanvasPortion.h" #include "CanvasPixelShader.h" +#include "RenderConfig.h" SoftwareCanvasRenderer::SoftwareCanvasRenderer() { @@ -34,6 +35,15 @@ SoftwareCanvasRenderer::~SoftwareCanvasRenderer() } } +void SoftwareCanvasRenderer::setConfig(const RenderConfig &config) +{ + if (not started) + { + setSize(config.width, config.height, config.antialias); + render_quality = config.quality; + } +} + void SoftwareCanvasRenderer::setSize(int width, int height, int samples) { if (not started) @@ -44,9 +54,7 @@ void SoftwareCanvasRenderer::setSize(int width, int height, int samples) void SoftwareCanvasRenderer::render() { - // TEMP started = true; - render_quality = 3; render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight()); diff --git a/src/render/software/SoftwareCanvasRenderer.h b/src/render/software/SoftwareCanvasRenderer.h index 291182a..58195f3 100644 --- a/src/render/software/SoftwareCanvasRenderer.h +++ b/src/render/software/SoftwareCanvasRenderer.h @@ -24,6 +24,11 @@ public: inline const Canvas *getCanvas() const {return canvas;} + /** + * Set the renderer configuration. + */ + void setConfig(const RenderConfig &config); + /** * @brief Set the rendering size in pixels. * From 18a669675f8af7070af87108a7ce34014fdf96e6 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Wed, 20 Aug 2014 14:31:28 +0200 Subject: [PATCH 22/29] Restored tone mapping control of canvas preview --- src/interface/desktop/WidgetPreviewCanvas.cpp | 10 ++++++++++ src/interface/desktop/WidgetPreviewCanvas.h | 13 +++++++++---- src/interface/desktop/dialogrender.cpp | 4 +++- src/render/software/CanvasPreview.cpp | 6 ++++++ src/render/software/CanvasPreview.h | 1 + 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/interface/desktop/WidgetPreviewCanvas.cpp b/src/interface/desktop/WidgetPreviewCanvas.cpp index 74b3fd4..f52e72c 100644 --- a/src/interface/desktop/WidgetPreviewCanvas.cpp +++ b/src/interface/desktop/WidgetPreviewCanvas.cpp @@ -28,6 +28,16 @@ void WidgetPreviewCanvas::setCanvas(const Canvas *canvas) } } +void WidgetPreviewCanvas::setToneMapping(const ColorProfile &profile) +{ + if (canvas) + { + canvas->getPreview()->setToneMapping(profile); + canvas->getPreview()->updateLive(this); + update(); + } +} + void WidgetPreviewCanvas::paintEvent(QPaintEvent *) { QPainter painter(this); diff --git a/src/interface/desktop/WidgetPreviewCanvas.h b/src/interface/desktop/WidgetPreviewCanvas.h index 097ce57..3933d55 100644 --- a/src/interface/desktop/WidgetPreviewCanvas.h +++ b/src/interface/desktop/WidgetPreviewCanvas.h @@ -9,8 +9,8 @@ namespace paysages { namespace desktop { -/*! - * \brief Widget to display a live-updated preview of a Canvas software rendering. +/** + * Widget to display a live-updated preview of a Canvas software rendering. */ class WidgetPreviewCanvas : public QWidget, public CanvasLiveClient { @@ -19,13 +19,18 @@ public: explicit WidgetPreviewCanvas(QWidget *parent = 0); virtual ~WidgetPreviewCanvas(); - /*! - * \brief Set the canvas to watch and display, null to stop watching. + /** + * 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); + /** + * Set the tone mapping to apply to pixel colors. + */ + void setToneMapping(const ColorProfile &profile); + virtual void paintEvent(QPaintEvent* event); protected: diff --git a/src/interface/desktop/dialogrender.cpp b/src/interface/desktop/dialogrender.cpp index 63344f4..636fd81 100644 --- a/src/interface/desktop/dialogrender.cpp +++ b/src/interface/desktop/dialogrender.cpp @@ -99,6 +99,8 @@ DialogRender::DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer): connect(_save_button, SIGNAL(clicked()), this, SLOT(saveRender())); connect(_tonemapping_control, SIGNAL(currentIndexChanged(int)), this, SLOT(toneMappingChanged())); connect(_exposure_control, SIGNAL(valueChanged(int)), this, SLOT(toneMappingChanged())); + + toneMappingChanged(); } DialogRender::~DialogRender() @@ -166,7 +168,7 @@ void DialogRender::saveRender() void DialogRender::toneMappingChanged() { ColorProfile profile((ColorProfile::ToneMappingOperator)_tonemapping_control->currentIndex(), ((double)_exposure_control->value()) * 0.01); - //canvas_renderer->render_area->setToneMapping(profile); + canvas_preview->setToneMapping(profile); } void DialogRender::loadLastRender() diff --git a/src/render/software/CanvasPreview.cpp b/src/render/software/CanvasPreview.cpp index 5012911..0a31e26 100644 --- a/src/render/software/CanvasPreview.cpp +++ b/src/render/software/CanvasPreview.cpp @@ -72,6 +72,12 @@ void CanvasPreview::setSize(int real_width, int real_height, int preview_width, reset(); } +void CanvasPreview::setToneMapping(const ColorProfile &profile) +{ + profile.copy(this->profile); + setAllDirty(); +} + void CanvasPreview::reset() { lock->acquire(); diff --git a/src/render/software/CanvasPreview.h b/src/render/software/CanvasPreview.h index dbcc0e4..94dd0ce 100644 --- a/src/render/software/CanvasPreview.h +++ b/src/render/software/CanvasPreview.h @@ -21,6 +21,7 @@ public: const Color &getFinalPixel(int x, int y) const; void setSize(int real_width, int real_height, int preview_width, int preview_height); + void setToneMapping(const ColorProfile &profile); void reset(); void initLive(CanvasLiveClient *client); From 14e03208487c8490e081e59a57713bd98c62903f Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Wed, 20 Aug 2014 15:58:37 +0200 Subject: [PATCH 23/29] Restored (partially) render progress --- src/interface/desktop/dialogrender.cpp | 12 +++---- src/interface/desktop/dialogrender.h | 7 ++-- .../software/SoftwareCanvasRenderer.cpp | 36 ++++++++++++------- src/render/software/SoftwareCanvasRenderer.h | 17 ++++----- 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/interface/desktop/dialogrender.cpp b/src/interface/desktop/dialogrender.cpp index 636fd81..5c66121 100644 --- a/src/interface/desktop/dialogrender.cpp +++ b/src/interface/desktop/dialogrender.cpp @@ -116,11 +116,6 @@ DialogRender::~DialogRender() delete pixbuf_lock; } -void DialogRender::tellProgressChange(double value) -{ - emit progressChanged(value); -} - void DialogRender::tellRenderEnded() { emit renderEnded(); @@ -133,6 +128,8 @@ void DialogRender::startRender() _render_thread = new RenderThread(this, canvas_renderer); _render_thread->start(); + startTimer(100); + exec(); } @@ -179,14 +176,15 @@ void DialogRender::loadLastRender() exec(); } -void DialogRender::applyProgress(double value) +void DialogRender::timerEvent(QTimerEvent *) { double diff = difftime(time(NULL), _started); int hours = (int)floor(diff / 3600.0); int minutes = (int)floor((diff - 3600.0 * hours) / 60.0); int seconds = (int)floor(diff - 3600.0 * hours - 60.0 * minutes); _timer->setText(tr("%1:%2.%3").arg(hours).arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0'))); - _progress->setValue((int)(value * 1000.0)); + + _progress->setValue((int)(canvas_renderer->getProgress() * 1000.0)); _progress->update(); } diff --git a/src/interface/desktop/dialogrender.h b/src/interface/desktop/dialogrender.h index 9206b12..57b33e3 100644 --- a/src/interface/desktop/dialogrender.h +++ b/src/interface/desktop/dialogrender.h @@ -18,25 +18,24 @@ class DialogRender : public QDialog { Q_OBJECT public: - explicit DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer); + explicit DialogRender(QWidget *parent, SoftwareCanvasRenderer *renderer); ~DialogRender(); - void tellProgressChange(double value); void tellRenderEnded(); void startRender(); void loadLastRender(); + virtual void timerEvent(QTimerEvent *event) override; + QImage* pixbuf; QMutex* pixbuf_lock; private slots: - void applyProgress(double value); void saveRender(); void applyRenderEnded(); void toneMappingChanged(); signals: - void progressChanged(double value); void renderEnded(); private: diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 7b88187..74803ef 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -17,6 +17,7 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer() started = false; interrupted = false; canvas = new Canvas(); + progress = 0.0; rasterizers.push_back(new SkyRasterizer(this, 0)); rasterizers.push_back(new WaterRasterizer(this, 1)); @@ -55,6 +56,7 @@ void SoftwareCanvasRenderer::setSize(int width, int height, int samples) void SoftwareCanvasRenderer::render() { started = true; + progress = 0.0; render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight()); @@ -63,6 +65,8 @@ void SoftwareCanvasRenderer::render() // Iterate portions int nx = canvas->getHorizontalPortionCount(); int ny = canvas->getVerticalPortionCount(); + int i = 0; + int n = nx * ny; for (int y = 0; y < ny; y++) { for (int x = 0; x < nx; x++) @@ -71,16 +75,20 @@ void SoftwareCanvasRenderer::render() if (not interrupted) { + progress_segment = 0.2 / (double)n; portion->preparePixels(); - rasterize(portion, true); + rasterize(portion); } if (not interrupted) { - applyPixelShader(portion, true); + progress_segment = 0.8 / (double)n; + applyPixelShader(portion); } portion->discardPixels(); + i++; + progress = (double)i / (double)n; } } } @@ -93,31 +101,27 @@ void SoftwareCanvasRenderer::interrupt() { current_work->interrupt(); } - for (auto &rasterizer:getRasterizers()) + for (auto &rasterizer:rasterizers) { rasterizer->interrupt(); } } -const std::vector &SoftwareCanvasRenderer::getRasterizers() const -{ - return rasterizers; -} - const Rasterizer &SoftwareCanvasRenderer::getRasterizer(int client_id) const { - return *(getRasterizers()[client_id]); + return *(rasterizers[client_id]); } -void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded) +void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion) { - for (auto &rasterizer:getRasterizers()) + for (auto &rasterizer:rasterizers) { rasterizer->rasterizeToCanvas(portion); + progress += progress_segment / (double)rasterizers.size(); } } -void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion, bool threaded) +void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion) { // Subdivide in chunks int chunk_size = 64; @@ -125,6 +129,13 @@ void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion, bool threa int chunks_y = (portion->getHeight() - 1) / chunk_size + 1; int units = chunks_x * chunks_y; + // Estimate chunks + int n = 0; + for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2) + { + n += chunk_size / sub_chunk_size; + } + // Render chunks in parallel for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2) { @@ -139,5 +150,6 @@ void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion, bool threa current_work = &work; work.perform(); current_work = NULL; + progress += progress_segment * (double)(chunk_size / sub_chunk_size) / (double)n; } } diff --git a/src/render/software/SoftwareCanvasRenderer.h b/src/render/software/SoftwareCanvasRenderer.h index 58195f3..a40d69a 100644 --- a/src/render/software/SoftwareCanvasRenderer.h +++ b/src/render/software/SoftwareCanvasRenderer.h @@ -23,6 +23,7 @@ public: virtual ~SoftwareCanvasRenderer(); inline const Canvas *getCanvas() const {return canvas;} + inline double getProgress() const {return progress;} /** * Set the renderer configuration. @@ -46,11 +47,6 @@ public: */ void interrupt(); - /** - * @brief Get the list of objects that can be rasterized to polygons on a canvas. - */ - virtual const std::vector &getRasterizers() const; - /** * Get a rasterizer by its client id. */ @@ -59,19 +55,18 @@ public: protected: /** * @brief Rasterize the scenery into a canvas portion. - * - * If 'threaded' is true, the rasterization will take advantage of multiple CPU cores. */ - void rasterize(CanvasPortion *portion, bool threaded=false); + void rasterize(CanvasPortion *portion); /** * @brief Apply pixel shader to fragments stored in the CanvasPortion. - * - * If 'threaded' is true, the shader will take advantage of multiple CPU cores. */ - void applyPixelShader(CanvasPortion *portion, bool threaded=true); + void applyPixelShader(CanvasPortion *portion); private: + double progress; + double progress_segment; + Canvas *canvas; std::vector rasterizers; bool started; From 13904be001bee51a00deca29900568896bd98fd5 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Wed, 20 Aug 2014 16:45:45 +0200 Subject: [PATCH 24/29] Optimization: replaced some divisions by inverse multiplications --- Makefile | 8 ++++---- src/basics/NoiseGenerator.cpp | 20 ++++++++++---------- src/basics/NoiseGenerator.h | 2 +- src/definition/CameraDefinition.cpp | 5 ++++- src/definition/CameraDefinition.h | 2 ++ src/interface/commandline/main.cpp | 11 ++++++----- src/interface/desktop/dialognoise.cpp | 6 +++--- src/render/software/CanvasPreview.cpp | 18 +++++++++--------- src/render/software/Rasterizer.cpp | 12 ++++++------ src/render/software/TexturesRenderer.cpp | 8 ++++---- 10 files changed, 49 insertions(+), 43 deletions(-) diff --git a/Makefile b/Makefile index 56d7343..f3cb8b7 100644 --- a/Makefile +++ b/Makefile @@ -43,17 +43,17 @@ else endif run_cli:build - LD_LIBRARY_PATH=$(LIBRARY_PATH) ${RUNNER} ${BUILDPATH}/interface/commandline/paysages-cli + LD_LIBRARY_PATH=$(LIBRARY_PATH) ${RUNNER} ${BUILDPATH}/interface/commandline/paysages-cli $(ARGS) run:build - LD_LIBRARY_PATH=$(LIBRARY_PATH) ${RUNNER} ${BUILDPATH}/interface/desktop/paysages-gui + LD_LIBRARY_PATH=$(LIBRARY_PATH) ${RUNNER} ${BUILDPATH}/interface/desktop/paysages-gui $(ARGS) profile:build - LD_LIBRARY_PATH=${LIBRARY_PATH} perf record -g fp ${BUILDPATH}/interface/desktop/paysages-gui $(ARGS) + LD_LIBRARY_PATH=${LIBRARY_PATH} perf record -g ${BUILDPATH}/interface/desktop/paysages-gui $(ARGS) perf report -g profile_cli:build - LD_LIBRARY_PATH=${LIBRARY_PATH} perf record -g fp ${BUILDPATH}/interface/commandline/paysages-cli $(ARGS) + LD_LIBRARY_PATH=${LIBRARY_PATH} perf record -g ${BUILDPATH}/interface/commandline/paysages-cli $(ARGS) perf report -g package:build diff --git a/src/basics/NoiseGenerator.cpp b/src/basics/NoiseGenerator.cpp index 06b3f85..907095b 100644 --- a/src/basics/NoiseGenerator.cpp +++ b/src/basics/NoiseGenerator.cpp @@ -45,7 +45,7 @@ void NoiseGenerator::save(PackStream* stream) { NoiseLevel* level = levels + x; - stream->write(&level->wavelength); + stream->write(&level->frequency); stream->write(&level->amplitude); stream->write(&level->minvalue); } @@ -69,7 +69,7 @@ void NoiseGenerator::load(PackStream* stream) { NoiseLevel* level = levels + x; - stream->read(&level->wavelength); + stream->read(&level->frequency); stream->read(&level->amplitude); stream->read(&level->minvalue); } @@ -215,7 +215,7 @@ void NoiseGenerator::addLevelSimple(double scaling, double minvalue, double maxv { NoiseLevel level; - level.wavelength = scaling; + level.frequency = 1.0 / scaling; level.minvalue = minvalue; level.amplitude = maxvalue - minvalue; @@ -230,7 +230,7 @@ void NoiseGenerator::addLevels(int level_count, NoiseLevel start_level, double s { addLevel(start_level); start_level.minvalue += start_level.amplitude * (1.0 - amplitude_factor) * center_factor; - start_level.wavelength *= scaling_factor; + start_level.frequency /= scaling_factor; start_level.amplitude *= amplitude_factor; } } @@ -239,7 +239,7 @@ void NoiseGenerator::addLevelsSimple(int level_count, double scaling, double min { NoiseLevel level; - level.wavelength = scaling; + level.frequency = 1.0 / scaling; level.minvalue = minvalue; level.amplitude = maxvalue - minvalue; addLevels(level_count, level, 0.5, 0.5, center_factor); @@ -284,7 +284,7 @@ void NoiseGenerator::setLevelSimple(int index, double scaling, double minvalue, { NoiseLevel level; - level.wavelength = scaling; + level.frequency = 1.0 / scaling; level.minvalue = minvalue; level.amplitude = maxvalue - minvalue; @@ -313,7 +313,7 @@ void NoiseGenerator::normalizeAmplitude(double minvalue, double maxvalue, int ad levels[level].amplitude *= factor; if (adjust_scaling) { - levels[level].wavelength *= factor; + levels[level].frequency /= factor; } } height_offset = minvalue + (height_offset - current_minvalue) * factor; @@ -371,7 +371,7 @@ static inline double _fixValue(double value, double ridge, double curve) inline double NoiseGenerator::_get1DLevelValue(NoiseLevel* level, const NoiseState::NoiseOffset &offset, double x) { - return level->minvalue + _fixValue(_func_noise_1d(x / level->wavelength + offset.x), function.ridge_factor, function.curve_factor) * level->amplitude; + return level->minvalue + _fixValue(_func_noise_1d(x * level->frequency + offset.x), function.ridge_factor, function.curve_factor) * level->amplitude; } double NoiseGenerator::get1DLevel(int level, double x) @@ -428,7 +428,7 @@ double NoiseGenerator::get1DDetail(double x, double detail) inline double NoiseGenerator::_get2DLevelValue(NoiseLevel* level, const NoiseState::NoiseOffset &offset, double x, double y) { - return level->minvalue + _fixValue(_func_noise_2d(x / level->wavelength + offset.x, y / level->wavelength + offset.y), function.ridge_factor, function.curve_factor) * level->amplitude; + return level->minvalue + _fixValue(_func_noise_2d(x * level->frequency + offset.x, y * level->frequency + offset.y), function.ridge_factor, function.curve_factor) * level->amplitude; } double NoiseGenerator::get2DLevel(int level, double x, double y) @@ -485,7 +485,7 @@ double NoiseGenerator::get2DDetail(double x, double y, double detail) inline double NoiseGenerator::_get3DLevelValue(NoiseLevel* level, const NoiseState::NoiseOffset &offset, double x, double y, double z) { - return level->minvalue + _fixValue(_func_noise_3d(x / level->wavelength + offset.x, y / level->wavelength + offset.y, z / level->wavelength + offset.z), function.ridge_factor, function.curve_factor) * level->amplitude; + return level->minvalue + _fixValue(_func_noise_3d(x * level->frequency + offset.x, y * level->frequency + offset.y, z * level->frequency + offset.z), function.ridge_factor, function.curve_factor) * level->amplitude; } double NoiseGenerator::get3DLevel(int level, double x, double y, double z) diff --git a/src/basics/NoiseGenerator.h b/src/basics/NoiseGenerator.h index 89eb688..ca94f6f 100644 --- a/src/basics/NoiseGenerator.h +++ b/src/basics/NoiseGenerator.h @@ -28,7 +28,7 @@ public: typedef struct { - double wavelength; + double frequency; double amplitude; double minvalue; } NoiseLevel; diff --git a/src/definition/CameraDefinition.cpp b/src/definition/CameraDefinition.cpp index 5fcfce6..1f43199 100644 --- a/src/definition/CameraDefinition.cpp +++ b/src/definition/CameraDefinition.cpp @@ -90,11 +90,14 @@ void CameraDefinition::validate() projector = mperspective.mult(Matrix4::newLookAt(location, target, up)); unprojector = projector.inversed(); + + inv_x_factor = 1.0 / (0.5 * width); + inv_y_factor = 1.0 / (0.5 * height); } double CameraDefinition::getRealDepth(const Vector3 &projected) const { - Vector3 v(projected.x / (0.5 * width) - 1.0, -(projected.y / (0.5 * height) - 1.0), projected.z); + Vector3 v(projected.x * inv_x_factor - 1.0, -(projected.y * inv_x_factor - 1.0), projected.z); return unperspective.transform(v).z; } diff --git a/src/definition/CameraDefinition.h b/src/definition/CameraDefinition.h index faab350..3268381 100644 --- a/src/definition/CameraDefinition.h +++ b/src/definition/CameraDefinition.h @@ -85,6 +85,8 @@ private: Matrix4 projector; Matrix4 unprojector; Matrix4 unperspective; + double inv_x_factor; + double inv_y_factor; }; } diff --git a/src/interface/commandline/main.cpp b/src/interface/commandline/main.cpp index 447ce61..665d7ef 100644 --- a/src/interface/commandline/main.cpp +++ b/src/interface/commandline/main.cpp @@ -9,13 +9,13 @@ #include "Scenery.h" #include "RenderConfig.h" -void startRender(SoftwareRenderer *renderer, char *outputpath, const RenderConfig ¶ms) +void startRender(SoftwareCanvasRenderer *renderer, char *outputpath) { - /*printf("\rRendering %s ... \n", outputpath); - renderer->start(params); + printf("\rRendering %s ... \n", outputpath); + renderer->render(); printf("\rSaving %s ... \n", outputpath); remove(outputpath); - renderer->render_area->saveToFile(outputpath);*/ + //renderer->render_area->saveToFile(outputpath); } void displayHelp() @@ -179,12 +179,13 @@ int main(int argc, char** argv) camera->setLocation(camera->getLocation().add(step)); renderer = new SoftwareCanvasRenderer(); + renderer->setConfig(conf_render_params); renderer->setScenery(scenery); if (outputcount >= conf_first_picture) { sprintf(outputpath, "output/pic%05d.png", outputcount); - startRender(renderer, outputpath, conf_render_params); + startRender(renderer, outputpath); } delete renderer; diff --git a/src/interface/desktop/dialognoise.cpp b/src/interface/desktop/dialognoise.cpp index b63f52e..57a826e 100644 --- a/src/interface/desktop/dialognoise.cpp +++ b/src/interface/desktop/dialognoise.cpp @@ -282,7 +282,7 @@ void DialogNoise::addLevel() NoiseGenerator::NoiseLevel level; level.amplitude = 0.1; - level.wavelength = 0.1; + level.frequency = 0.1; _current->addLevel(level); @@ -330,7 +330,7 @@ void DialogNoise::levelChanged(int row) ((PreviewLevel*)previewLevel)->setLevel(row); slider_height->setValue(_current_level_params.amplitude * 1000.0); - slider_scaling->setValue(_current_level_params.wavelength * 1000.0); + slider_scaling->setValue(_current_level_params.frequency * 1000.0); } // TODO else ... } @@ -345,7 +345,7 @@ void DialogNoise::heightChanged(int value) void DialogNoise::scalingChanged(int value) { - _current_level_params.wavelength = ((double)value) / 1000.0; + _current_level_params.frequency = ((double)value) / 1000.0; _current->setLevel(_current_level, _current_level_params); previewLevel->redraw(); previewTotal->redraw(); diff --git a/src/render/software/CanvasPreview.cpp b/src/render/software/CanvasPreview.cpp index 0a31e26..6e49eec 100644 --- a/src/render/software/CanvasPreview.cpp +++ b/src/render/software/CanvasPreview.cpp @@ -63,8 +63,8 @@ void CanvasPreview::setSize(int real_width, int real_height, int preview_width, dirty_up = -1; scaled = (real_width != preview_height or real_height != preview_height); - factor_x = (double)real_width / (double)preview_width; - factor_y = (double)real_height / (double)preview_height; + factor_x = (double)preview_width / (double)real_width; + factor_y = (double)preview_height / (double)real_height; factor = factor_x * factor_y; lock->release(); @@ -125,12 +125,10 @@ void CanvasPreview::pushPixel(int real_x, int real_y, const Color &old_color, co { int x, y; - lock->acquire(); - if (scaled) { - x = int(real_x / factor_x); - y = int(real_y / factor_y); + x = int(real_x * factor_x); + y = int(real_y * factor_y); x = (x >= width) ? width - 1 : x; y = (y >= height) ? height - 1 : y; @@ -143,10 +141,12 @@ void CanvasPreview::pushPixel(int real_x, int real_y, const Color &old_color, co CHECK_COORDINATES(x, y); + lock->acquire(); + Color* pixel = pixels + (y * width + x); - pixel->r = pixel->r - old_color.r / factor + new_color.r / factor; - pixel->g = pixel->g - old_color.g / factor + new_color.g / factor; - pixel->b = pixel->b - old_color.b / factor + new_color.b / factor; + pixel->r = pixel->r - old_color.r * factor + new_color.r * factor; + pixel->g = pixel->g - old_color.g * factor + new_color.g * factor; + pixel->b = pixel->b - old_color.b * factor + new_color.b * factor; // Set pixel dirty if (x < dirty_left) diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index c75fe08..ed8ff8f 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -174,16 +174,16 @@ void Rasterizer::scanInterpolate(CameraDefinition* camera, ScanPoint* v1, ScanPo { Vector3 vec1(v1->pixel.x, v1->pixel.y, v1->pixel.z); Vector3 vecdiff(diff->pixel.x, diff->pixel.y, diff->pixel.z); - double v1depth = camera->getRealDepth(vec1); - double v2depth = camera->getRealDepth(vec1.add(vecdiff)); - double factor = ((1.0 - value) / v1depth + value / v2depth); + double v1depth = 1.0 / camera->getRealDepth(vec1); + double v2depth = 1.0 / camera->getRealDepth(vec1.add(vecdiff)); + double factor = 1.0 / ((1.0 - value) * v1depth + value * v2depth); result->pixel.x = v1->pixel.x + diff->pixel.x * value; result->pixel.y = v1->pixel.y + diff->pixel.y * value; result->pixel.z = v1->pixel.z + diff->pixel.z * value; - result->location.x = ((1.0 - value) * (v1->location.x / v1depth) + value * (v1->location.x + diff->location.x) / v2depth) / factor; - result->location.y = ((1.0 - value) * (v1->location.y / v1depth) + value * (v1->location.y + diff->location.y) / v2depth) / factor; - result->location.z = ((1.0 - value) * (v1->location.z / v1depth) + value * (v1->location.z + diff->location.z) / v2depth) / factor; + result->location.x = ((1.0 - value) * (v1->location.x * v1depth) + value * (v1->location.x + diff->location.x) * v2depth) * factor; + result->location.y = ((1.0 - value) * (v1->location.y * v1depth) + value * (v1->location.y + diff->location.y) * v2depth) * factor; + result->location.z = ((1.0 - value) * (v1->location.z * v1depth) + value * (v1->location.z + diff->location.z) * v2depth) * factor; result->client = v1->client; } diff --git a/src/render/software/TexturesRenderer.cpp b/src/render/software/TexturesRenderer.cpp index 056881a..6dce8e0 100644 --- a/src/render/software/TexturesRenderer.cpp +++ b/src/render/software/TexturesRenderer.cpp @@ -40,10 +40,10 @@ double TexturesRenderer::getTriplanarNoise(NoiseGenerator *noise, const Vector3 double mXY = fabs(normal.z); double mXZ = fabs(normal.y); double mYZ = fabs(normal.x); - double total = mXY + mXZ + mYZ; - mXY /= total; - mXZ /= total; - mYZ /= total; + double total = 1.0 / (mXY + mXZ + mYZ); + mXY *= total; + mXZ *= total; + mYZ *= total; return noiseXY * mXY + noiseXZ * mXZ + noiseYZ * mYZ; } From 0bb1cf5bedba772a9f4484936637189290109481 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Thu, 21 Aug 2014 09:58:11 +0200 Subject: [PATCH 25/29] Added canvas portion writing to disk --- src/render/software/Canvas.cpp | 5 +++-- src/render/software/CanvasPortion.cpp | 31 ++++++++++++++++++++++++--- src/render/software/CanvasPortion.h | 16 ++++++++++---- src/system/FileSystem.cpp | 8 +++++++ src/system/FileSystem.h | 23 ++++++++++++++++++++ src/system/system.pro | 6 ++++-- src/system/system_global.h | 1 + 7 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 src/system/FileSystem.cpp create mode 100644 src/system/FileSystem.h diff --git a/src/render/software/Canvas.cpp b/src/render/software/Canvas.cpp index 7cf1439..67cd6c0 100644 --- a/src/render/software/Canvas.cpp +++ b/src/render/software/Canvas.cpp @@ -11,7 +11,7 @@ Canvas::Canvas() vertical_portion_count = 1; width = 1; height = 1; - portions.push_back(new CanvasPortion()); + portions.push_back(new CanvasPortion); preview = new CanvasPreview; } @@ -41,13 +41,14 @@ void Canvas::setSize(int width, int height) int done_width = 0; int done_height = 0; + int index = 0; for (int y = 0; y < vertical_portion_count; y++) { done_width = 0; for (int x = 0; x < horizontal_portion_count; x++) { - CanvasPortion *portion = new CanvasPortion(preview); + CanvasPortion *portion = new CanvasPortion(index++, preview); portion->setSize((x == horizontal_portion_count - 1) ? width - done_width : portion_width, (y == vertical_portion_count - 1) ? height - done_height : portion_height, diff --git a/src/render/software/CanvasPortion.cpp b/src/render/software/CanvasPortion.cpp index 193404a..c29fec9 100644 --- a/src/render/software/CanvasPortion.cpp +++ b/src/render/software/CanvasPortion.cpp @@ -4,6 +4,8 @@ #include "CanvasPixel.h" #include "CanvasPreview.h" +#include "PackStream.h" +#include "FileSystem.h" #define CHECK_COORDINATES() assert(x >= 0); \ assert(x < width); \ @@ -11,8 +13,8 @@ assert(y < height); \ assert(pixels != NULL) -CanvasPortion::CanvasPortion(CanvasPreview* preview): - preview(preview) +CanvasPortion::CanvasPortion(int index, CanvasPreview* preview): + index(index), preview(preview) { width = 1; height = 1; @@ -70,15 +72,38 @@ void CanvasPortion::preparePixels() clear(); } -void CanvasPortion::discardPixels() +void CanvasPortion::discardPixels(bool save) { if (pixels) { + if (save) + { + saveToDisk(); + } delete[] pixels; pixels = NULL; } } +void CanvasPortion::saveToDisk() +{ + if (pixels) + { + std::string filepath = FileSystem::getTempFile("paysages_portion_" + std::to_string(index) + ".dat"); + PackStream stream; + stream.bindToFile(filepath, true); + stream.write(&width); + stream.write(&height); + for (int x = 0; x < width; x++) + { + for (int y = 0; y < height; y++) + { + pixels[y * width + x].getComposite().save(&stream); + } + } + } +} + void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment) { CHECK_COORDINATES(); diff --git a/src/render/software/CanvasPortion.h b/src/render/software/CanvasPortion.h index 59d0153..326b826 100644 --- a/src/render/software/CanvasPortion.h +++ b/src/render/software/CanvasPortion.h @@ -16,8 +16,8 @@ namespace software { class SOFTWARESHARED_EXPORT CanvasPortion { public: - CanvasPortion(CanvasPreview* preview=NULL); - ~CanvasPortion(); + CanvasPortion(int index=0, CanvasPreview *preview=NULL); + virtual ~CanvasPortion(); inline int getWidth() const {return width;} inline int getHeight() const {return height;} @@ -36,8 +36,15 @@ public: /** * Discard the memory used by pixels. + * + * If save is true, the portion will be saved to disk before. */ - void discardPixels(); + void discardPixels(bool save=true); + + /** + * Save the portion to a picture file on disk. + */ + void saveToDisk(); /** * Add a fragment to the pixel located at (x, y). @@ -61,12 +68,13 @@ public: void setColor(int x, int y, const Color &color); private: + int index; int width; int height; int xoffset; int yoffset; CanvasPixel *pixels; - CanvasPreview* preview; + CanvasPreview *preview; }; } diff --git a/src/system/FileSystem.cpp b/src/system/FileSystem.cpp new file mode 100644 index 0000000..2ee3e45 --- /dev/null +++ b/src/system/FileSystem.cpp @@ -0,0 +1,8 @@ +#include "FileSystem.h" + +#include + +std::string FileSystem::getTempFile(const std::string &filename) +{ + return QDir::temp().filePath(QString::fromStdString(filename)).toStdString(); +} diff --git a/src/system/FileSystem.h b/src/system/FileSystem.h new file mode 100644 index 0000000..afd2b3f --- /dev/null +++ b/src/system/FileSystem.h @@ -0,0 +1,23 @@ +#ifndef FILESYSTEM_H +#define FILESYSTEM_H + +#include "system_global.h" + +namespace paysages { +namespace system { + +class SYSTEMSHARED_EXPORT FileSystem +{ +public: + /** + * Get an absolute path to a temporary file. + * + * filename must not contain directory separators. + */ + static std::string getTempFile(const std::string &filename); +}; + +} +} + +#endif // FILESYSTEM_H diff --git a/src/system/system.pro b/src/system/system.pro index ceac911..0c1de8c 100644 --- a/src/system/system.pro +++ b/src/system/system.pro @@ -26,7 +26,8 @@ SOURCES += \ Logs.cpp \ ParallelPool.cpp \ ParallelWorker.cpp \ - Semaphore.cpp + Semaphore.cpp \ + FileSystem.cpp HEADERS += \ system_global.h \ @@ -42,7 +43,8 @@ HEADERS += \ Logs.h \ ParallelPool.h \ ParallelWorker.h \ - Semaphore.h + Semaphore.h \ + FileSystem.h unix:!symbian { maemo5 { diff --git a/src/system/system_global.h b/src/system/system_global.h index 80b4d3c..769b128 100644 --- a/src/system/system_global.h +++ b/src/system/system_global.h @@ -21,6 +21,7 @@ namespace system { class Thread; class Mutex; class Semaphore; + class PictureWriter; } } using namespace paysages::system; From 6c4a16966c1365aa6692c02b602cb268858ef227 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Thu, 21 Aug 2014 10:11:44 +0200 Subject: [PATCH 26/29] Larger maximal canvas portion size --- src/render/software/Canvas.cpp | 4 ++-- src/tests/Canvas_Test.cpp | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/render/software/Canvas.cpp b/src/render/software/Canvas.cpp index 67cd6c0..4a0c7f6 100644 --- a/src/render/software/Canvas.cpp +++ b/src/render/software/Canvas.cpp @@ -27,8 +27,8 @@ Canvas::~Canvas() void Canvas::setSize(int width, int height) { - horizontal_portion_count = 1 + (width - 1) / 400; - vertical_portion_count = 1 + (height - 1) / 400; + horizontal_portion_count = 1 + (width - 1) / 800; + vertical_portion_count = 1 + (height - 1) / 800; int portion_width = width / horizontal_portion_count; int portion_height = height / vertical_portion_count; diff --git a/src/tests/Canvas_Test.cpp b/src/tests/Canvas_Test.cpp index 39edf16..4070c91 100644 --- a/src/tests/Canvas_Test.cpp +++ b/src/tests/Canvas_Test.cpp @@ -28,15 +28,15 @@ TEST(Canvas, SizingAndCutting) ASSERT_EQ(1, canvas.getVerticalPortionCount()); checkPortion(canvas, 0, 0, 200, 100); - canvas.setSize(600, 501); - EXPECT_EQ(600, canvas.getWidth()); - EXPECT_EQ(501, canvas.getHeight()); - EXPECT_EQ(600, canvas.getPreview()->getWidth()); - EXPECT_EQ(501, canvas.getPreview()->getHeight()); + canvas.setSize(1100, 901); + EXPECT_EQ(1100, canvas.getWidth()); + EXPECT_EQ(901, canvas.getHeight()); + EXPECT_EQ(550, canvas.getPreview()->getWidth()); + EXPECT_EQ(450, canvas.getPreview()->getHeight()); ASSERT_EQ(2, canvas.getHorizontalPortionCount()); ASSERT_EQ(2, canvas.getVerticalPortionCount()); - checkPortion(canvas, 0, 0, 300, 250); - checkPortion(canvas, 0, 1, 300, 251); - checkPortion(canvas, 1, 0, 300, 250); - checkPortion(canvas, 1, 1, 300, 251); + checkPortion(canvas, 0, 0, 550, 450); + checkPortion(canvas, 0, 1, 550, 451); + checkPortion(canvas, 1, 0, 550, 450); + checkPortion(canvas, 1, 1, 550, 451); } From c39ef6adce0d9f21e2342aa18fabe54e9c5f89f1 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Thu, 21 Aug 2014 12:36:28 +0200 Subject: [PATCH 27/29] Restored final picture saving (in constant memory usage) --- src/interface/commandline/main.cpp | 3 +- src/interface/desktop/dialogrender.cpp | 6 +- src/render/software/Canvas.cpp | 22 +++++ src/render/software/Canvas.h | 8 ++ src/render/software/CanvasPictureWriter.cpp | 89 +++++++++++++++++++ src/render/software/CanvasPictureWriter.h | 54 +++++++++++ src/render/software/CanvasPortion.cpp | 23 ++++- src/render/software/CanvasPortion.h | 8 ++ src/render/software/CanvasPreview.h | 1 + .../software/SoftwareCanvasRenderer.cpp | 9 ++ src/render/software/SoftwareCanvasRenderer.h | 8 ++ src/render/software/software.pro | 6 +- src/render/software/software_global.h | 1 + src/system/FileSystem.cpp | 6 ++ src/system/FileSystem.h | 5 ++ src/system/PackStream.cpp | 10 +++ src/system/PackStream.h | 3 + src/tests/PackStream_Test.cpp | 43 +++++++++ 18 files changed, 296 insertions(+), 9 deletions(-) create mode 100644 src/render/software/CanvasPictureWriter.cpp create mode 100644 src/render/software/CanvasPictureWriter.h diff --git a/src/interface/commandline/main.cpp b/src/interface/commandline/main.cpp index 665d7ef..5de8824 100644 --- a/src/interface/commandline/main.cpp +++ b/src/interface/commandline/main.cpp @@ -8,6 +8,7 @@ #include "SoftwareCanvasRenderer.h" #include "Scenery.h" #include "RenderConfig.h" +#include "ColorProfile.h" void startRender(SoftwareCanvasRenderer *renderer, char *outputpath) { @@ -15,7 +16,7 @@ void startRender(SoftwareCanvasRenderer *renderer, char *outputpath) renderer->render(); printf("\rSaving %s ... \n", outputpath); remove(outputpath); - //renderer->render_area->saveToFile(outputpath); + renderer->saveToDisk(outputpath); } void displayHelp() diff --git a/src/interface/desktop/dialogrender.cpp b/src/interface/desktop/dialogrender.cpp index 5c66121..71620bf 100644 --- a/src/interface/desktop/dialogrender.cpp +++ b/src/interface/desktop/dialogrender.cpp @@ -22,6 +22,7 @@ #include "ColorProfile.h" #include "SoftwareCanvasRenderer.h" #include "WidgetPreviewCanvas.h" +#include "Canvas.h" class RenderThread:public QThread { @@ -150,12 +151,11 @@ void DialogRender::saveRender() { filepath = filepath.append(".png"); } - std::string filepathstr = filepath.toStdString(); - /*if (canvas_renderer->render_area->saveToFile((char*)filepathstr.c_str())) + if (canvas_renderer->saveToDisk(filepath.toStdString())) { QMessageBox::information(this, "Message", QString(tr("The picture %1 has been saved.")).arg(filepath)); } - else*/ + else { QMessageBox::critical(this, "Message", QString(tr("Can't write to file : %1")).arg(filepath)); } diff --git a/src/render/software/Canvas.cpp b/src/render/software/Canvas.cpp index 4a0c7f6..6c796f7 100644 --- a/src/render/software/Canvas.cpp +++ b/src/render/software/Canvas.cpp @@ -4,6 +4,7 @@ #include "CanvasPortion.h" #include "CanvasPreview.h" +#include "CanvasPictureWriter.h" Canvas::Canvas() { @@ -86,3 +87,24 @@ CanvasPortion *Canvas::at(int x, int y) const return portions[y * horizontal_portion_count + x]; } + +CanvasPortion *Canvas::atPixel(int x, int y) const +{ + assert(x >= 0 && x < width); + assert(y >= 0 && y < height); + + int pwidth = portions[0]->getWidth(); + int pheight = portions[0]->getHeight(); + + return at(x / pwidth, y / pheight); +} + +bool Canvas::saveToDisk(const std::string &filepath, const ColorProfile &profile, int antialias) const +{ + assert(antialias >= 1); + + CanvasPictureWriter writer(this); + writer.setColorProfile(profile); + writer.setAntialias(antialias); + return writer.saveCanvas(filepath); +} diff --git a/src/render/software/Canvas.h b/src/render/software/Canvas.h index edd8e80..c326bca 100644 --- a/src/render/software/Canvas.h +++ b/src/render/software/Canvas.h @@ -24,11 +24,19 @@ public: inline int getVerticalPortionCount() const {return vertical_portion_count;} CanvasPortion *at(int x, int y) const; + CanvasPortion *atPixel(int x, int y) const; inline int getWidth() const {return width;} inline int getHeight() const {return height;} inline CanvasPreview *getPreview() const {return preview;} + /** + * Save the canvas to a picture file on disk. + * + * Returns true if the save was successful. + */ + bool saveToDisk(const std::string &filepath, const ColorProfile &profile, int antialias) const; + private: std::vector portions; int horizontal_portion_count; diff --git a/src/render/software/CanvasPictureWriter.cpp b/src/render/software/CanvasPictureWriter.cpp new file mode 100644 index 0000000..b0cdb74 --- /dev/null +++ b/src/render/software/CanvasPictureWriter.cpp @@ -0,0 +1,89 @@ +#include "CanvasPictureWriter.h" + +#include + +#include "Canvas.h" +#include "CanvasPortion.h" +#include "ColorProfile.h" +#include "PackStream.h" + +CanvasPictureWriter::CanvasPictureWriter(const Canvas *canvas): + canvas(canvas) +{ + profile = new ColorProfile(); + antialias = 1; + width = canvas->getWidth(); + height = canvas->getHeight(); +} + +CanvasPictureWriter::~CanvasPictureWriter() +{ + delete profile; +} + +void CanvasPictureWriter::setAntialias(int antialias) +{ + assert(antialias >= 1); + assert(canvas->getWidth() % antialias == 0); + assert(canvas->getHeight() % antialias == 0); + + this->antialias = antialias; + this->width = canvas->getWidth() / antialias; + this->height = canvas->getHeight() / antialias; +} + +void CanvasPictureWriter::setColorProfile(const ColorProfile &profile) +{ + profile.copy(this->profile); +} + +bool CanvasPictureWriter::saveCanvas(const std::string &filepath) +{ + return save(filepath, width, height); +} + +unsigned int CanvasPictureWriter::getPixel(int x, int y) +{ + if (antialias > 1) + { + int basex = x * antialias; + int basey = y * antialias; + double factor = 1.0 / (antialias * antialias); + Color comp = COLOR_BLACK; + + for (int ix = 0; ix < antialias; ix++) + { + for (int iy = 0; iy < antialias; iy++) + { + Color col = getRawPixel(basex + ix, basey + iy); + comp.r += col.r * factor; + comp.g += col.g * factor; + comp.b += col.b * factor; + } + } + + return profile->apply(comp).to32BitBGRA(); + } + else + { + return profile->apply(getRawPixel(x, y)).to32BitBGRA(); + } +} + +Color CanvasPictureWriter::getRawPixel(int x, int y) +{ + // Get the portion this pixel is in + CanvasPortion *portion = canvas->atPixel(x, y); + + // Get the pack stream positioned at the pixel + PackStream stream; + if (not portion->getReadStream(stream, x - portion->getXOffset(), y - portion->getYOffset())) + { + return COLOR_BLACK; + } + + // Load the pixel and apply tone mapping + Color col; + col.load(&stream); + return col; +} diff --git a/src/render/software/CanvasPictureWriter.h b/src/render/software/CanvasPictureWriter.h new file mode 100644 index 0000000..6f7895f --- /dev/null +++ b/src/render/software/CanvasPictureWriter.h @@ -0,0 +1,54 @@ +#ifndef CANVASPICTUREWRITER_H +#define CANVASPICTUREWRITER_H + +#include "software_global.h" + +#include "PictureWriter.h" + +namespace paysages { +namespace software { + +/** + * Picture writer to create the final image from canvas portions. + */ +class SOFTWARESHARED_EXPORT CanvasPictureWriter: public PictureWriter +{ +public: + CanvasPictureWriter(const Canvas *canvas); + virtual ~CanvasPictureWriter(); + + /** + * Set the antialias factor, 1 for no antialiasing. + */ + void setAntialias(int antialias); + + /** + * Set the color profile to apply to final pixels. + */ + void setColorProfile(const ColorProfile &profile); + + /** + * Start the saving process. + * + * Returns true if saving was successful. + */ + bool saveCanvas(const std::string &filepath); + +protected: + virtual unsigned int getPixel(int x, int y) override; + +private: + Color getRawPixel(int x, int y); + +private: + const Canvas *canvas; + int antialias; + int width; + int height; + ColorProfile *profile; +}; + +} +} + +#endif // CANVASPICTUREWRITER_H diff --git a/src/render/software/CanvasPortion.cpp b/src/render/software/CanvasPortion.cpp index c29fec9..4aee76f 100644 --- a/src/render/software/CanvasPortion.cpp +++ b/src/render/software/CanvasPortion.cpp @@ -89,14 +89,14 @@ void CanvasPortion::saveToDisk() { if (pixels) { - std::string filepath = FileSystem::getTempFile("paysages_portion_" + std::to_string(index) + ".dat"); + filepath = FileSystem::getTempFile("paysages_portion_" + std::to_string(index) + ".dat"); PackStream stream; stream.bindToFile(filepath, true); stream.write(&width); stream.write(&height); - for (int x = 0; x < width; x++) + for (int y = 0; y < height; y++) { - for (int y = 0; y < height; y++) + for (int x = 0; x < width; x++) { pixels[y * width + x].getComposite().save(&stream); } @@ -104,6 +104,23 @@ void CanvasPortion::saveToDisk() } } +bool CanvasPortion::getReadStream(PackStream &stream, int x, int y) +{ + if (FileSystem::isFile(filepath)) + { + int unused_i; + double unused_d; + stream.bindToFile(filepath); + stream.skip(unused_i, 2); + stream.skip(unused_d, (y * width + x - 1) * 4); + return true; + } + else + { + return false; + } +} + void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment) { CHECK_COORDINATES(); diff --git a/src/render/software/CanvasPortion.h b/src/render/software/CanvasPortion.h index 326b826..1131e16 100644 --- a/src/render/software/CanvasPortion.h +++ b/src/render/software/CanvasPortion.h @@ -46,6 +46,13 @@ public: */ void saveToDisk(); + /** + * Bind a stream to pixel data, and position it on a given pixel. + * + * Returns true if the stream was successfully located, false if it was not possible. + */ + bool getReadStream(PackStream &stream, int x=0, int y=0); + /** * Add a fragment to the pixel located at (x, y). * @@ -75,6 +82,7 @@ private: int yoffset; CanvasPixel *pixels; CanvasPreview *preview; + std::string filepath; }; } diff --git a/src/render/software/CanvasPreview.h b/src/render/software/CanvasPreview.h index 94dd0ce..20f4a35 100644 --- a/src/render/software/CanvasPreview.h +++ b/src/render/software/CanvasPreview.h @@ -17,6 +17,7 @@ public: inline int getWidth() const {return width;} inline int getHeight() const {return height;} + inline const ColorProfile *getToneMapping() const {return profile;} const Color &getFinalPixel(int x, int y) const; diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 74803ef..922b12d 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -11,6 +11,8 @@ #include "CanvasPortion.h" #include "CanvasPixelShader.h" #include "RenderConfig.h" +#include "ColorProfile.h" +#include "CanvasPreview.h" SoftwareCanvasRenderer::SoftwareCanvasRenderer() { @@ -18,6 +20,7 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer() interrupted = false; canvas = new Canvas(); progress = 0.0; + samples = 1; rasterizers.push_back(new SkyRasterizer(this, 0)); rasterizers.push_back(new WaterRasterizer(this, 1)); @@ -50,6 +53,7 @@ void SoftwareCanvasRenderer::setSize(int width, int height, int samples) if (not started) { canvas->setSize(width * samples, height * samples); + this->samples = samples; } } @@ -112,6 +116,11 @@ const Rasterizer &SoftwareCanvasRenderer::getRasterizer(int client_id) const return *(rasterizers[client_id]); } +bool SoftwareCanvasRenderer::saveToDisk(const std::string &filepath) const +{ + return getCanvas()->saveToDisk(filepath, *getCanvas()->getPreview()->getToneMapping(), samples); +} + void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion) { for (auto &rasterizer:rasterizers) diff --git a/src/render/software/SoftwareCanvasRenderer.h b/src/render/software/SoftwareCanvasRenderer.h index a40d69a..e157248 100644 --- a/src/render/software/SoftwareCanvasRenderer.h +++ b/src/render/software/SoftwareCanvasRenderer.h @@ -52,6 +52,13 @@ public: */ const Rasterizer &getRasterizer(int client_id) const; + /** + * Save the rendered canvas to a picture file on disk. + * + * Returns true if the save was successful. + */ + bool saveToDisk(const std::string &filepath) const; + protected: /** * @brief Rasterize the scenery into a canvas portion. @@ -68,6 +75,7 @@ private: double progress_segment; Canvas *canvas; + int samples; std::vector rasterizers; bool started; bool interrupted; diff --git a/src/render/software/software.pro b/src/render/software/software.pro index 4543bf3..15472e7 100644 --- a/src/render/software/software.pro +++ b/src/render/software/software.pro @@ -46,7 +46,8 @@ SOURCES += SoftwareRenderer.cpp \ CanvasLiveClient.cpp \ CanvasPreview.cpp \ RenderConfig.cpp \ - CanvasPixelShader.cpp + CanvasPixelShader.cpp \ + CanvasPictureWriter.cpp HEADERS += SoftwareRenderer.h\ software_global.h \ @@ -82,7 +83,8 @@ HEADERS += SoftwareRenderer.h\ CanvasLiveClient.h \ CanvasPreview.h \ RenderConfig.h \ - CanvasPixelShader.h + CanvasPixelShader.h \ + CanvasPictureWriter.h unix:!symbian { maemo5 { diff --git a/src/render/software/software_global.h b/src/render/software/software_global.h index 0aa9636..637b85d 100644 --- a/src/render/software/software_global.h +++ b/src/render/software/software_global.h @@ -54,6 +54,7 @@ namespace software { class CanvasLiveClient; class CanvasPreview; class CanvasPixelShader; + class CanvasPictureWriter; } } diff --git a/src/system/FileSystem.cpp b/src/system/FileSystem.cpp index 2ee3e45..ae43dc2 100644 --- a/src/system/FileSystem.cpp +++ b/src/system/FileSystem.cpp @@ -1,8 +1,14 @@ #include "FileSystem.h" #include +#include std::string FileSystem::getTempFile(const std::string &filename) { return QDir::temp().filePath(QString::fromStdString(filename)).toStdString(); } + +bool FileSystem::isFile(const std::string &filepath) +{ + return QFileInfo(QString::fromStdString(filepath)).exists(); +} diff --git a/src/system/FileSystem.h b/src/system/FileSystem.h index afd2b3f..f59e596 100644 --- a/src/system/FileSystem.h +++ b/src/system/FileSystem.h @@ -15,6 +15,11 @@ public: * filename must not contain directory separators. */ static std::string getTempFile(const std::string &filename); + + /** + * Returns true if the given path points to a file. + */ + static bool isFile(const std::string &filepath); }; } diff --git a/src/system/PackStream.cpp b/src/system/PackStream.cpp index d7f9149..49010b1 100644 --- a/src/system/PackStream.cpp +++ b/src/system/PackStream.cpp @@ -114,3 +114,13 @@ std::string PackStream::readString() return ""; } } + +void PackStream::skip(const int &value, int count) +{ + stream->skipRawData(sizeof(value) * count); +} + +void PackStream::skip(const double &value, int count) +{ + stream->skipRawData(sizeof(value) * count); +} diff --git a/src/system/PackStream.h b/src/system/PackStream.h index 127adf6..2de2d03 100644 --- a/src/system/PackStream.h +++ b/src/system/PackStream.h @@ -32,6 +32,9 @@ public: void read(char* value, int max_length); std::string readString(); + void skip(const int &value, int count=1); + void skip(const double &value, int count=1); + private: QFile* file; QDataStream* stream; diff --git a/src/tests/PackStream_Test.cpp b/src/tests/PackStream_Test.cpp index d2e7407..92b5c4e 100644 --- a/src/tests/PackStream_Test.cpp +++ b/src/tests/PackStream_Test.cpp @@ -49,3 +49,46 @@ TEST(PackStream, All) } delete stream; } + +TEST(PackStream, Skip) +{ + PackStream* stream; + int i1=1, i2=2, i3=3; + double d1=1.1, d2=2.2; + + stream = new PackStream(); + stream->bindToFile("/tmp/test_paysages_pack", true); + + stream->write(&i1); + stream->write(&i2); + stream->write(&d1); + stream->write(&d2); + stream->write(&i3); + + delete stream; + + int resi; + double resd; + + stream = new PackStream(); + stream->bindToFile("/tmp/test_paysages_pack"); + stream->skip(i1, 1); + stream->read(&resi); + EXPECT_EQ(2, resi); + delete stream; + + stream = new PackStream(); + stream->bindToFile("/tmp/test_paysages_pack"); + stream->skip(i1, 2); + stream->read(&resd); + EXPECT_DOUBLE_EQ(1.1, resd); + delete stream; + + stream = new PackStream(); + stream->bindToFile("/tmp/test_paysages_pack"); + stream->skip(i1, 2); + stream->skip(d1, 2); + stream->read(&resi); + EXPECT_EQ(3, resi); + delete stream; +} From 04f6ab732d092afcbf2d617b6dff7102abfc41f0 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Thu, 21 Aug 2014 14:53:49 +0200 Subject: [PATCH 28/29] Normalize colors before writing to final picture --- src/interface/desktop/dialogrender.cpp | 1 - src/render/software/CanvasPictureWriter.cpp | 17 +++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/interface/desktop/dialogrender.cpp b/src/interface/desktop/dialogrender.cpp index 71620bf..58293b7 100644 --- a/src/interface/desktop/dialogrender.cpp +++ b/src/interface/desktop/dialogrender.cpp @@ -95,7 +95,6 @@ DialogRender::DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer): _actions->layout()->addWidget(_save_button); // Connections - connect(this, SIGNAL(progressChanged(double)), this, SLOT(applyProgress(double))); connect(this, SIGNAL(renderEnded()), this, SLOT(applyRenderEnded())); connect(_save_button, SIGNAL(clicked()), this, SLOT(saveRender())); connect(_tonemapping_control, SIGNAL(currentIndexChanged(int)), this, SLOT(toneMappingChanged())); diff --git a/src/render/software/CanvasPictureWriter.cpp b/src/render/software/CanvasPictureWriter.cpp index b0cdb74..b71ace5 100644 --- a/src/render/software/CanvasPictureWriter.cpp +++ b/src/render/software/CanvasPictureWriter.cpp @@ -44,16 +44,19 @@ bool CanvasPictureWriter::saveCanvas(const std::string &filepath) unsigned int CanvasPictureWriter::getPixel(int x, int y) { + Color comp; + if (antialias > 1) { int basex = x * antialias; int basey = y * antialias; double factor = 1.0 / (antialias * antialias); - Color comp = COLOR_BLACK; - for (int ix = 0; ix < antialias; ix++) + comp = COLOR_BLACK; + + for (int iy = 0; iy < antialias; iy++) { - for (int iy = 0; iy < antialias; iy++) + for (int ix = 0; ix < antialias; ix++) { Color col = getRawPixel(basex + ix, basey + iy); comp.r += col.r * factor; @@ -61,13 +64,15 @@ unsigned int CanvasPictureWriter::getPixel(int x, int y) comp.b += col.b * factor; } } - - return profile->apply(comp).to32BitBGRA(); } else { - return profile->apply(getRawPixel(x, y)).to32BitBGRA(); + comp = getRawPixel(x, y); } + + comp = profile->apply(comp); + comp.normalize(); + return comp.to32BitBGRA(); } Color CanvasPictureWriter::getRawPixel(int x, int y) From 1afcb907c475e52b48e5a96a87d06d8c1849d9e4 Mon Sep 17 00:00:00 2001 From: Michael Lemaire Date: Thu, 21 Aug 2014 15:30:09 +0200 Subject: [PATCH 29/29] Optimized and fixed canvas portion merging in final picture --- src/render/software/Canvas.cpp | 6 ++-- src/render/software/CanvasPictureWriter.cpp | 34 +++++++++++++++++---- src/render/software/CanvasPictureWriter.h | 4 +++ src/render/software/CanvasPortion.cpp | 15 +++++++-- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/render/software/Canvas.cpp b/src/render/software/Canvas.cpp index 6c796f7..8c9d0df 100644 --- a/src/render/software/Canvas.cpp +++ b/src/render/software/Canvas.cpp @@ -6,6 +6,8 @@ #include "CanvasPreview.h" #include "CanvasPictureWriter.h" +#define CUTTER_SIZE 800 + Canvas::Canvas() { horizontal_portion_count = 1; @@ -28,8 +30,8 @@ Canvas::~Canvas() void Canvas::setSize(int width, int height) { - horizontal_portion_count = 1 + (width - 1) / 800; - vertical_portion_count = 1 + (height - 1) / 800; + horizontal_portion_count = 1 + (width - 1) / CUTTER_SIZE; + vertical_portion_count = 1 + (height - 1) / CUTTER_SIZE; int portion_width = width / horizontal_portion_count; int portion_height = height / vertical_portion_count; diff --git a/src/render/software/CanvasPictureWriter.cpp b/src/render/software/CanvasPictureWriter.cpp index b71ace5..22d1775 100644 --- a/src/render/software/CanvasPictureWriter.cpp +++ b/src/render/software/CanvasPictureWriter.cpp @@ -14,11 +14,19 @@ CanvasPictureWriter::CanvasPictureWriter(const Canvas *canvas): antialias = 1; width = canvas->getWidth(); height = canvas->getHeight(); + + last_portion = NULL; + last_stream = NULL; + last_y = 0; } CanvasPictureWriter::~CanvasPictureWriter() { delete profile; + if (last_stream) + { + delete last_stream; + } } void CanvasPictureWriter::setAntialias(int antialias) @@ -80,15 +88,29 @@ Color CanvasPictureWriter::getRawPixel(int x, int y) // Get the portion this pixel is in CanvasPortion *portion = canvas->atPixel(x, y); - // Get the pack stream positioned at the pixel - PackStream stream; - if (not portion->getReadStream(stream, x - portion->getXOffset(), y - portion->getYOffset())) + // While we stay in the same portion line, read is sequential in the stream + if (portion != last_portion or last_y != y) { - return COLOR_BLACK; + // Get the pack stream positioned at the pixel + if (last_stream) + { + delete last_stream; + } + last_stream = new PackStream; + if (portion->getReadStream(*last_stream, x - portion->getXOffset(), y - portion->getYOffset())) + { + last_portion = portion; + last_y = y; + } + else + { + // Portion has no stream + return COLOR_BLACK; + } } - // Load the pixel and apply tone mapping + // Load the pixel Color col; - col.load(&stream); + col.load(last_stream); return col; } diff --git a/src/render/software/CanvasPictureWriter.h b/src/render/software/CanvasPictureWriter.h index 6f7895f..a07d3df 100644 --- a/src/render/software/CanvasPictureWriter.h +++ b/src/render/software/CanvasPictureWriter.h @@ -46,6 +46,10 @@ private: int width; int height; ColorProfile *profile; + + CanvasPortion *last_portion; + int last_y; + PackStream *last_stream; }; } diff --git a/src/render/software/CanvasPortion.cpp b/src/render/software/CanvasPortion.cpp index 4aee76f..805cb02 100644 --- a/src/render/software/CanvasPortion.cpp +++ b/src/render/software/CanvasPortion.cpp @@ -108,11 +108,20 @@ bool CanvasPortion::getReadStream(PackStream &stream, int x, int y) { if (FileSystem::isFile(filepath)) { + if (not stream.bindToFile(filepath)) + { + return false; + } + int unused_i; - double unused_d; - stream.bindToFile(filepath); stream.skip(unused_i, 2); - stream.skip(unused_d, (y * width + x - 1) * 4); + + if (x > 0 or y > 0) + { + double unused_d; + stream.skip(unused_d, (y * width + x) * 4); + } + return true; } else