WIP on new canvas system
This commit is contained in:
parent
8099361cc9
commit
cf58bea1b7
28 changed files with 700 additions and 99 deletions
|
@ -1,48 +1,69 @@
|
||||||
#include "WidgetPreviewCanvas.h"
|
#include "WidgetPreviewCanvas.h"
|
||||||
|
|
||||||
|
#include "tools.h"
|
||||||
#include "Canvas.h"
|
#include "Canvas.h"
|
||||||
#include "CanvasPreview.h"
|
#include "CanvasPreview.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
WidgetPreviewCanvas::WidgetPreviewCanvas(QWidget *parent) :
|
WidgetPreviewCanvas::WidgetPreviewCanvas(QWidget *parent) :
|
||||||
QWidget(parent), canvas(NULL)
|
QWidget(parent), canvas(NULL)
|
||||||
{
|
{
|
||||||
|
pixbuf = new QImage();
|
||||||
|
inited = false;
|
||||||
|
|
||||||
startTimer(1000);
|
startTimer(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WidgetPreviewCanvas::~WidgetPreviewCanvas()
|
||||||
|
{
|
||||||
|
delete pixbuf;
|
||||||
|
}
|
||||||
|
|
||||||
void WidgetPreviewCanvas::setCanvas(const Canvas *canvas)
|
void WidgetPreviewCanvas::setCanvas(const Canvas *canvas)
|
||||||
{
|
{
|
||||||
this->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)
|
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)
|
void WidgetPreviewCanvas::canvasCleared(const Color &col)
|
||||||
{
|
{
|
||||||
// TODO
|
pixbuf->fill(colorToQColor(col));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WidgetPreviewCanvas::canvasPainted(int x, int y, const Color &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 *)
|
void WidgetPreviewCanvas::timerEvent(QTimerEvent *)
|
||||||
{
|
{
|
||||||
// Refresh the view
|
|
||||||
CanvasPreview *preview = canvas->getPreview();
|
|
||||||
if (canvas)
|
if (canvas)
|
||||||
{
|
{
|
||||||
int width = preview->getWidth();
|
if (!inited)
|
||||||
int height = preview->getHeight();
|
|
||||||
|
|
||||||
if (QSize(width, height) != this->size())
|
|
||||||
{
|
{
|
||||||
setMaximumSize(width, height);
|
canvas->getPreview()->initLive(this);
|
||||||
setMinimumSize(width, height);
|
inited = true;
|
||||||
resize(width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canvas->getPreview()->updateLive(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,15 @@ class WidgetPreviewCanvas : public QWidget, public CanvasLiveClient
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WidgetPreviewCanvas(QWidget *parent = 0);
|
explicit WidgetPreviewCanvas(QWidget *parent = 0);
|
||||||
|
virtual ~WidgetPreviewCanvas();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Set the canvas to watch and display, null to stop watching.
|
* \brief Set the canvas to watch and display, null to stop watching.
|
||||||
*/
|
*/
|
||||||
void setCanvas(const Canvas *canvas);
|
void setCanvas(const Canvas *canvas);
|
||||||
|
|
||||||
|
virtual void paintEvent(QPaintEvent* event);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void canvasResized(int width, int height);
|
virtual void canvasResized(int width, int height);
|
||||||
virtual void canvasCleared(const Color &col);
|
virtual void canvasCleared(const Color &col);
|
||||||
|
@ -30,7 +33,9 @@ protected:
|
||||||
virtual void timerEvent(QTimerEvent *event);
|
virtual void timerEvent(QTimerEvent *event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QImage* pixbuf;
|
||||||
const Canvas *canvas;
|
const Canvas *canvas;
|
||||||
|
bool inited;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "dialogexplorer.h"
|
#include "dialogexplorer.h"
|
||||||
#include "DesktopScenery.h"
|
#include "DesktopScenery.h"
|
||||||
#include "BasePreview.h"
|
#include "BasePreview.h"
|
||||||
#include "SoftwareRenderer.h"
|
#include "SoftwareCanvasRenderer.h"
|
||||||
#include "CameraDefinition.h"
|
#include "CameraDefinition.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
|
@ -246,7 +246,8 @@ void FreeFormHelper::processExploreClicked()
|
||||||
|
|
||||||
void FreeFormHelper::processRenderClicked()
|
void FreeFormHelper::processRenderClicked()
|
||||||
{
|
{
|
||||||
SoftwareRenderer renderer(DesktopScenery::getCurrent());
|
SoftwareCanvasRenderer renderer;
|
||||||
|
renderer.setScenery(DesktopScenery::getCurrent());
|
||||||
|
|
||||||
emit needAlterRenderer(&renderer);
|
emit needAlterRenderer(&renderer);
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ static void _renderUpdate(double progress)
|
||||||
class RenderThread:public QThread
|
class RenderThread:public QThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RenderThread(DialogRender* dialog, SoftwareRenderer* renderer, RenderArea::RenderParams params):QThread()
|
RenderThread(DialogRender* dialog, SoftwareCanvasRenderer* renderer, RenderArea::RenderParams params):QThread()
|
||||||
{
|
{
|
||||||
_dialog = dialog;
|
_dialog = dialog;
|
||||||
_renderer = renderer;
|
_renderer = renderer;
|
||||||
|
@ -59,12 +59,13 @@ public:
|
||||||
}
|
}
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
|
_renderer->render();
|
||||||
_renderer->start(_params);
|
_renderer->start(_params);
|
||||||
_dialog->tellRenderEnded();
|
_dialog->tellRenderEnded();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
DialogRender* _dialog;
|
DialogRender* _dialog;
|
||||||
SoftwareRenderer* _renderer;
|
SoftwareCanvasRenderer* _renderer;
|
||||||
RenderArea::RenderParams _params;
|
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)
|
QDialog(parent, Qt::WindowTitleHint | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint)
|
||||||
{
|
{
|
||||||
pixbuf_lock = new QMutex();
|
pixbuf_lock = new QMutex();
|
||||||
pixbuf = new QImage(1, 1, QImage::Format_ARGB32);
|
pixbuf = new QImage(1, 1, QImage::Format_ARGB32);
|
||||||
_current_dialog = this;
|
_current_dialog = this;
|
||||||
_render_thread = NULL;
|
_render_thread = NULL;
|
||||||
_renderer = renderer;
|
canvas_renderer = renderer;
|
||||||
|
|
||||||
setModal(true);
|
setModal(true);
|
||||||
setWindowTitle(tr("Paysages 3D - Render"));
|
setWindowTitle(tr("Paysages 3D - Render"));
|
||||||
|
@ -105,7 +106,6 @@ DialogRender::DialogRender(QWidget *parent, SoftwareRenderer* renderer):
|
||||||
_scroll->setWidget(area);
|
_scroll->setWidget(area);
|
||||||
layout()->addWidget(_scroll);
|
layout()->addWidget(_scroll);
|
||||||
|
|
||||||
canvas_renderer = new SoftwareCanvasRenderer();
|
|
||||||
canvas_preview = new WidgetPreviewCanvas(this);
|
canvas_preview = new WidgetPreviewCanvas(this);
|
||||||
canvas_preview->setCanvas(canvas_renderer->getCanvas());
|
canvas_preview->setCanvas(canvas_renderer->getCanvas());
|
||||||
layout()->addWidget(canvas_preview);
|
layout()->addWidget(canvas_preview);
|
||||||
|
@ -159,7 +159,7 @@ DialogRender::~DialogRender()
|
||||||
{
|
{
|
||||||
if (_render_thread)
|
if (_render_thread)
|
||||||
{
|
{
|
||||||
_renderer->interrupt();
|
canvas_renderer->interrupt();
|
||||||
_render_thread->wait();
|
_render_thread->wait();
|
||||||
|
|
||||||
delete _render_thread;
|
delete _render_thread;
|
||||||
|
@ -190,9 +190,9 @@ void DialogRender::startRender(RenderArea::RenderParams params)
|
||||||
canvas_renderer->setSize(params.width, params.height, params.antialias);
|
canvas_renderer->setSize(params.width, params.height, params.antialias);
|
||||||
|
|
||||||
applyRenderSize(params.width, params.height);
|
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();
|
_render_thread->start();
|
||||||
|
|
||||||
exec();
|
exec();
|
||||||
|
@ -218,7 +218,7 @@ void DialogRender::saveRender()
|
||||||
filepath = filepath.append(".png");
|
filepath = filepath.append(".png");
|
||||||
}
|
}
|
||||||
std::string filepathstr = filepath.toStdString();
|
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));
|
QMessageBox::information(this, "Message", QString(tr("The picture %1 has been saved.")).arg(filepath));
|
||||||
}
|
}
|
||||||
|
@ -232,13 +232,13 @@ void DialogRender::saveRender()
|
||||||
void DialogRender::toneMappingChanged()
|
void DialogRender::toneMappingChanged()
|
||||||
{
|
{
|
||||||
ColorProfile profile((ColorProfile::ToneMappingOperator)_tonemapping_control->currentIndex(), ((double)_exposure_control->value()) * 0.01);
|
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()
|
void DialogRender::loadLastRender()
|
||||||
{
|
{
|
||||||
applyRenderSize(_renderer->render_width, _renderer->render_height);
|
applyRenderSize(canvas_renderer->render_width, canvas_renderer->render_height);
|
||||||
_renderer->setPreviewCallbacks(_renderStart, _renderDraw, _renderUpdate);
|
canvas_renderer->setPreviewCallbacks(_renderStart, _renderDraw, _renderUpdate);
|
||||||
renderEnded();
|
renderEnded();
|
||||||
toneMappingChanged();
|
toneMappingChanged();
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ class DialogRender : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit DialogRender(QWidget *parent, SoftwareRenderer* renderer);
|
explicit DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer);
|
||||||
~DialogRender();
|
~DialogRender();
|
||||||
|
|
||||||
void tellRenderSize(int width, int height);
|
void tellRenderSize(int width, int height);
|
||||||
|
@ -56,7 +56,6 @@ private:
|
||||||
QPushButton* _save_button;
|
QPushButton* _save_button;
|
||||||
QThread* _render_thread;
|
QThread* _render_thread;
|
||||||
QLabel* _timer;
|
QLabel* _timer;
|
||||||
SoftwareRenderer* _renderer;
|
|
||||||
QProgressBar* _progress;
|
QProgressBar* _progress;
|
||||||
time_t _started;
|
time_t _started;
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "DesktopScenery.h"
|
#include "DesktopScenery.h"
|
||||||
#include "PackStream.h"
|
#include "PackStream.h"
|
||||||
#include "SoftwareRenderer.h"
|
#include "SoftwareCanvasRenderer.h"
|
||||||
#include "BasePreview.h"
|
#include "BasePreview.h"
|
||||||
#include "CloudsDefinition.h"
|
#include "CloudsDefinition.h"
|
||||||
#include "CameraDefinition.h"
|
#include "CameraDefinition.h"
|
||||||
|
@ -103,7 +103,8 @@ void FormRender::startQuickRender()
|
||||||
{
|
{
|
||||||
delete _renderer;
|
delete _renderer;
|
||||||
}
|
}
|
||||||
_renderer = new SoftwareRenderer(DesktopScenery::getCurrent());
|
_renderer = new SoftwareCanvasRenderer();
|
||||||
|
_renderer->setScenery(DesktopScenery::getCurrent());
|
||||||
_renderer_inited = true;
|
_renderer_inited = true;
|
||||||
|
|
||||||
DialogRender* dialog = new DialogRender(this, _renderer);
|
DialogRender* dialog = new DialogRender(this, _renderer);
|
||||||
|
@ -119,7 +120,8 @@ void FormRender::startRender()
|
||||||
{
|
{
|
||||||
delete _renderer;
|
delete _renderer;
|
||||||
}
|
}
|
||||||
_renderer = new SoftwareRenderer(DesktopScenery::getCurrent());
|
_renderer = new SoftwareCanvasRenderer();
|
||||||
|
_renderer->setScenery(DesktopScenery::getCurrent());
|
||||||
_renderer_inited = true;
|
_renderer_inited = true;
|
||||||
|
|
||||||
DialogRender* dialog = new DialogRender(this, _renderer);
|
DialogRender* dialog = new DialogRender(this, _renderer);
|
||||||
|
|
|
@ -31,7 +31,7 @@ protected slots:
|
||||||
private:
|
private:
|
||||||
RenderArea::RenderParams _params;
|
RenderArea::RenderParams _params;
|
||||||
CameraDefinition* _camera;
|
CameraDefinition* _camera;
|
||||||
SoftwareRenderer* _renderer;
|
SoftwareCanvasRenderer* _renderer;
|
||||||
bool _renderer_inited;
|
bool _renderer_inited;
|
||||||
BasePreview* _preview_landscape;
|
BasePreview* _preview_landscape;
|
||||||
Base2dPreviewRenderer* _preview_landscape_renderer;
|
Base2dPreviewRenderer* _preview_landscape_renderer;
|
||||||
|
|
|
@ -13,7 +13,7 @@ Canvas::Canvas()
|
||||||
height = 1;
|
height = 1;
|
||||||
portions.push_back(new CanvasPortion());
|
portions.push_back(new CanvasPortion());
|
||||||
|
|
||||||
preview = new CanvasPreview();
|
preview = new CanvasPreview;
|
||||||
}
|
}
|
||||||
|
|
||||||
Canvas::~Canvas()
|
Canvas::~Canvas()
|
||||||
|
@ -27,8 +27,8 @@ Canvas::~Canvas()
|
||||||
|
|
||||||
void Canvas::setSize(int width, int height)
|
void Canvas::setSize(int width, int height)
|
||||||
{
|
{
|
||||||
horizontal_portion_count = 1 + width / 400;
|
horizontal_portion_count = 1 + (width - 1) / 400;
|
||||||
vertical_portion_count = 1 + height / 400;
|
vertical_portion_count = 1 + (height - 1) / 400;
|
||||||
|
|
||||||
int portion_width = width / horizontal_portion_count;
|
int portion_width = width / horizontal_portion_count;
|
||||||
int portion_height = height / vertical_portion_count;
|
int portion_height = height / vertical_portion_count;
|
||||||
|
@ -47,7 +47,7 @@ void Canvas::setSize(int width, int height)
|
||||||
done_width = 0;
|
done_width = 0;
|
||||||
for (int x = 0; x < horizontal_portion_count; x++)
|
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,
|
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);
|
||||||
|
|
|
@ -7,5 +7,10 @@ CanvasFragment::CanvasFragment()
|
||||||
CanvasFragment::CanvasFragment(double z, const Vector3 &location, int client, bool opaque):
|
CanvasFragment::CanvasFragment(double z, const Vector3 &location, int client, bool opaque):
|
||||||
z(z), location(location), client(client), opaque(opaque)
|
z(z), location(location), client(client), opaque(opaque)
|
||||||
{
|
{
|
||||||
color = COLOR_BLACK;
|
color = COLOR_WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanvasFragment::setColor(const Color &col)
|
||||||
|
{
|
||||||
|
color = col;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ public:
|
||||||
CanvasFragment();
|
CanvasFragment();
|
||||||
CanvasFragment(double z, const Vector3 &location, int client=0, bool opaque=true);
|
CanvasFragment(double z, const Vector3 &location, int client=0, bool opaque=true);
|
||||||
|
|
||||||
|
void setColor(const Color &col);
|
||||||
|
|
||||||
inline bool getOpaque() const {return opaque;}
|
inline bool getOpaque() const {return opaque;}
|
||||||
inline double getZ() const {return z;}
|
inline double getZ() const {return z;}
|
||||||
inline const Vector3 &getLocation() const {return location;}
|
inline const Vector3 &getLocation() const {return location;}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
CanvasPixel::CanvasPixel()
|
CanvasPixel::CanvasPixel()
|
||||||
{
|
{
|
||||||
count = 0;
|
count = 0;
|
||||||
|
composite = COLOR_BLACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CanvasFragment *CanvasPixel::getFrontFragment() const
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,17 @@ public:
|
||||||
CanvasPixel();
|
CanvasPixel();
|
||||||
|
|
||||||
inline int getFragmentCount() const {return count;}
|
inline int getFragmentCount() const {return count;}
|
||||||
|
inline const Color &getComposite() const {return composite;}
|
||||||
const CanvasFragment *getFrontFragment() const;
|
const CanvasFragment *getFrontFragment() const;
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void pushFragment(const CanvasFragment &fragment);
|
void pushFragment(const CanvasFragment &fragment);
|
||||||
|
void updateComposite();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int count;
|
int count;
|
||||||
CanvasFragment fragments[MAX_FRAGMENT_COUNT];
|
CanvasFragment fragments[MAX_FRAGMENT_COUNT];
|
||||||
|
Color composite;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,15 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include "CanvasPixel.h"
|
#include "CanvasPixel.h"
|
||||||
|
#include "CanvasPreview.h"
|
||||||
|
|
||||||
#define CHECK_COORDINATES() assert(x >= 0); \
|
#define CHECK_COORDINATES() assert(x >= 0); \
|
||||||
assert(x < width); \
|
assert(x < width); \
|
||||||
assert(y >= 0); \
|
assert(y >= 0); \
|
||||||
assert(y < height)
|
assert(y < height)
|
||||||
|
|
||||||
CanvasPortion::CanvasPortion()
|
CanvasPortion::CanvasPortion(CanvasPreview* preview):
|
||||||
|
preview(preview)
|
||||||
{
|
{
|
||||||
width = 1;
|
width = 1;
|
||||||
height = 1;
|
height = 1;
|
||||||
|
@ -58,5 +60,12 @@ void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment)
|
||||||
CHECK_COORDINATES();
|
CHECK_COORDINATES();
|
||||||
|
|
||||||
CanvasPixel &pixel = pixels[y * width + x];
|
CanvasPixel &pixel = pixels[y * width + x];
|
||||||
|
Color old_color = pixel.getComposite();
|
||||||
|
|
||||||
pixel.pushFragment(fragment);
|
pixel.pushFragment(fragment);
|
||||||
|
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
preview->pushPixel(x, y, old_color, pixel.getComposite());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace software {
|
||||||
class SOFTWARESHARED_EXPORT CanvasPortion
|
class SOFTWARESHARED_EXPORT CanvasPortion
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CanvasPortion();
|
CanvasPortion(CanvasPreview* preview=NULL);
|
||||||
~CanvasPortion();
|
~CanvasPortion();
|
||||||
|
|
||||||
inline int getWidth() const {return width;}
|
inline int getWidth() const {return width;}
|
||||||
|
@ -36,6 +36,7 @@ private:
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
CanvasPixel *pixels;
|
CanvasPixel *pixels;
|
||||||
|
CanvasPreview* preview;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,137 @@
|
||||||
#include "CanvasPreview.h"
|
#include "CanvasPreview.h"
|
||||||
|
|
||||||
|
#include "Color.h"
|
||||||
|
#include "CanvasLiveClient.h"
|
||||||
|
#include "Mutex.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
CanvasPreview::CanvasPreview()
|
CanvasPreview::CanvasPreview()
|
||||||
{
|
{
|
||||||
width = 1;
|
width = 1;
|
||||||
height = 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()
|
CanvasPreview::~CanvasPreview()
|
||||||
{
|
{
|
||||||
delete [] pixels;
|
delete [] pixels;
|
||||||
|
delete lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasPreview::setSize(int real_width, int real_height, int preview_width, int preview_height)
|
void CanvasPreview::setSize(int real_width, int real_height, int preview_width, int preview_height)
|
||||||
{
|
{
|
||||||
|
lock->acquire();
|
||||||
|
|
||||||
delete [] pixels;
|
delete [] pixels;
|
||||||
pixels = new CanvasPreviewPixel[preview_width * preview_height];
|
pixels = new Color[preview_width * preview_height];
|
||||||
|
|
||||||
width = preview_width;
|
width = preview_width;
|
||||||
height = preview_height;
|
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,6 @@
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace software {
|
namespace software {
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
double red;
|
|
||||||
double green;
|
|
||||||
double blue;
|
|
||||||
} CanvasPreviewPixel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Smaller preview of a Canvas rendering, that can be watched live.
|
* @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 setSize(int real_width, int real_height, int preview_width, int preview_height);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void initLive(CanvasLiveClient &client);
|
void initLive(CanvasLiveClient *client);
|
||||||
void updateLive(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:
|
private:
|
||||||
CanvasPreviewPixel *pixels;
|
Mutex *lock;
|
||||||
|
|
||||||
|
Color *pixels;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
|
||||||
|
int dirty_left;
|
||||||
|
int dirty_right;
|
||||||
|
int dirty_down;
|
||||||
|
int dirty_up;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,337 @@
|
||||||
#include "Rasterizer.h"
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,13 +6,40 @@
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace software {
|
namespace software {
|
||||||
|
|
||||||
|
typedef struct ScanPoint ScanPoint;
|
||||||
|
typedef struct RenderScanlines RenderScanlines;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Base abstract class for scenery pieces that can be rasterized to polygons.
|
* @brief Base abstract class for scenery pieces that can be rasterized to polygons.
|
||||||
*/
|
*/
|
||||||
class SOFTWARESHARED_EXPORT Rasterizer
|
class SOFTWARESHARED_EXPORT Rasterizer
|
||||||
{
|
{
|
||||||
public:
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,12 @@
|
||||||
#include "AtmosphereRenderer.h"
|
#include "AtmosphereRenderer.h"
|
||||||
#include "AtmosphereResult.h"
|
#include "AtmosphereResult.h"
|
||||||
#include "CloudsRenderer.h"
|
#include "CloudsRenderer.h"
|
||||||
|
#include "Rasterizer.h"
|
||||||
|
|
||||||
#define SPHERE_SIZE 20000.0
|
#define SPHERE_SIZE 20000.0
|
||||||
|
|
||||||
SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer):
|
SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, int client_id):
|
||||||
renderer(renderer)
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,11 +11,10 @@ namespace software {
|
||||||
class SOFTWARESHARED_EXPORT SkyRasterizer: public Rasterizer
|
class SOFTWARESHARED_EXPORT SkyRasterizer: public Rasterizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SkyRasterizer(SoftwareRenderer* renderer);
|
SkyRasterizer(SoftwareRenderer* renderer, int client_id);
|
||||||
void rasterize();
|
|
||||||
|
|
||||||
private:
|
virtual void rasterize();
|
||||||
SoftwareRenderer* renderer;
|
virtual void rasterizeToCanvas(CanvasPortion* canvas);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,29 @@
|
||||||
#include "Rasterizer.h"
|
#include "Rasterizer.h"
|
||||||
#include "SoftwareRenderer.h"
|
#include "SoftwareRenderer.h"
|
||||||
#include "Canvas.h"
|
#include "Canvas.h"
|
||||||
|
#include "TerrainRasterizer.h"
|
||||||
|
#include "WaterRasterizer.h"
|
||||||
|
#include "SkyRasterizer.h"
|
||||||
|
#include "CameraDefinition.h"
|
||||||
|
|
||||||
SoftwareCanvasRenderer::SoftwareCanvasRenderer()
|
SoftwareCanvasRenderer::SoftwareCanvasRenderer()
|
||||||
{
|
{
|
||||||
started = false;
|
started = false;
|
||||||
renderer = new SoftwareRenderer();
|
|
||||||
canvas = new Canvas();
|
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()
|
SoftwareCanvasRenderer::~SoftwareCanvasRenderer()
|
||||||
{
|
{
|
||||||
delete renderer;
|
|
||||||
delete canvas;
|
delete canvas;
|
||||||
|
|
||||||
|
for (auto &rasterizer: rasterizers)
|
||||||
|
{
|
||||||
|
delete rasterizer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareCanvasRenderer::setSize(int width, int height, int samples)
|
void SoftwareCanvasRenderer::setSize(int width, int height, int samples)
|
||||||
|
@ -31,17 +42,22 @@ void SoftwareCanvasRenderer::render()
|
||||||
started = true;
|
started = true;
|
||||||
CanvasPortion *portion = canvas->at(0, 0);
|
CanvasPortion *portion = canvas->at(0, 0);
|
||||||
|
|
||||||
|
render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight());
|
||||||
|
|
||||||
rasterize(portion, true);
|
rasterize(portion, true);
|
||||||
postProcess(portion, true);
|
postProcess(portion, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<Rasterizer *> &SoftwareCanvasRenderer::getRasterizers() const
|
||||||
|
{
|
||||||
|
return rasterizers;
|
||||||
|
}
|
||||||
|
|
||||||
void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded)
|
void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded)
|
||||||
{
|
{
|
||||||
std::vector<Rasterizer> rasterizers;
|
for (auto &rasterizer:getRasterizers())
|
||||||
renderer->getRasterizers(&rasterizers);
|
|
||||||
|
|
||||||
for (auto &rasterizer:rasterizers)
|
|
||||||
{
|
{
|
||||||
|
rasterizer->rasterizeToCanvas(portion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "software_global.h"
|
#include "software_global.h"
|
||||||
|
|
||||||
|
#include "SoftwareRenderer.h"
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace software {
|
namespace software {
|
||||||
|
|
||||||
|
@ -14,11 +16,11 @@ namespace software {
|
||||||
*
|
*
|
||||||
* It tries to keep a canvas portion rasterized ahead of the post processing.
|
* It tries to keep a canvas portion rasterized ahead of the post processing.
|
||||||
*/
|
*/
|
||||||
class SOFTWARESHARED_EXPORT SoftwareCanvasRenderer
|
class SOFTWARESHARED_EXPORT SoftwareCanvasRenderer: public SoftwareRenderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SoftwareCanvasRenderer();
|
SoftwareCanvasRenderer();
|
||||||
~SoftwareCanvasRenderer();
|
virtual ~SoftwareCanvasRenderer();
|
||||||
|
|
||||||
inline const Canvas *getCanvas() const {return canvas;}
|
inline const Canvas *getCanvas() const {return canvas;}
|
||||||
|
|
||||||
|
@ -34,6 +36,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Get the list of objects that can be rasterized to polygons on a canvas.
|
||||||
|
*/
|
||||||
|
virtual const std::vector<Rasterizer*> &getRasterizers() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Rasterize the scenery into a canvas portion.
|
* @brief Rasterize the scenery into a canvas portion.
|
||||||
|
@ -50,8 +57,8 @@ protected:
|
||||||
void postProcess(CanvasPortion* portion, bool threaded=true);
|
void postProcess(CanvasPortion* portion, bool threaded=true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SoftwareRenderer* renderer;
|
|
||||||
Canvas* canvas;
|
Canvas* canvas;
|
||||||
|
std::vector<Rasterizer*> rasterizers;
|
||||||
bool started;
|
bool started;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -108,22 +108,15 @@ void SoftwareRenderer::prepare()
|
||||||
//fluid_medium->registerMedium(water_renderer);
|
//fluid_medium->registerMedium(water_renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareRenderer::getRasterizers(std::vector<Rasterizer> *array)
|
|
||||||
{
|
|
||||||
array->push_back(TerrainRasterizer(this));
|
|
||||||
array->push_back(WaterRasterizer(this));
|
|
||||||
array->push_back(SkyRasterizer(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoftwareRenderer::rasterize()
|
void SoftwareRenderer::rasterize()
|
||||||
{
|
{
|
||||||
TerrainRasterizer terrain(this);
|
TerrainRasterizer terrain(this, 0);
|
||||||
terrain.renderSurface();
|
terrain.rasterize();
|
||||||
|
|
||||||
WaterRasterizer water(this);
|
WaterRasterizer water(this, 1);
|
||||||
water.renderSurface();
|
water.rasterize();
|
||||||
|
|
||||||
SkyRasterizer sky(this);
|
SkyRasterizer sky(this, 2);
|
||||||
sky.rasterize();
|
sky.rasterize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,11 +59,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void prepare();
|
virtual void prepare();
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Get the list of objects that can be rasterized to polygons on a canvas.
|
|
||||||
*/
|
|
||||||
virtual void getRasterizers(std::vector<Rasterizer> *array);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Start the rasterization process.
|
* \brief Start the rasterization process.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
#include "Scenery.h"
|
#include "Scenery.h"
|
||||||
#include "ParallelQueue.h"
|
#include "ParallelQueue.h"
|
||||||
|
|
||||||
TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer):
|
TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id):
|
||||||
renderer(renderer)
|
Rasterizer(renderer, client_id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ int TerrainRasterizer::processChunk(TerrainChunkInfo* chunk, double progress)
|
||||||
return !renderer->render_interrupt;
|
return !renderer->render_interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainRasterizer::renderSurface()
|
void TerrainRasterizer::rasterize()
|
||||||
{
|
{
|
||||||
queue = new ParallelQueue();
|
queue = new ParallelQueue();
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ public:
|
||||||
} TerrainChunkInfo;
|
} TerrainChunkInfo;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TerrainRasterizer(SoftwareRenderer* renderer);
|
TerrainRasterizer(SoftwareRenderer* renderer, int client_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method called for each chunk tessellated by getTessellationInfo.
|
* 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.
|
* This will push the rasterized quads in the render area, waiting for post process.
|
||||||
*/
|
*/
|
||||||
void renderSurface();
|
virtual void rasterize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SoftwareRenderer* renderer;
|
|
||||||
ParallelQueue* queue;
|
ParallelQueue* queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
#include "WaterRenderer.h"
|
#include "WaterRenderer.h"
|
||||||
#include "ParallelQueue.h"
|
#include "ParallelQueue.h"
|
||||||
|
|
||||||
WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer):
|
WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, int client_id):
|
||||||
renderer(renderer)
|
Rasterizer(renderer, client_id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ static int _parallelJobCallback(ParallelQueue*, int, void* data, int stopping)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterRasterizer::renderSurface()
|
void WaterRasterizer::rasterize()
|
||||||
{
|
{
|
||||||
ParallelRasterInfo* info;
|
ParallelRasterInfo* info;
|
||||||
ParallelQueue* queue;
|
ParallelQueue* queue;
|
||||||
|
|
|
@ -11,12 +11,9 @@ namespace software {
|
||||||
class WaterRasterizer: public Rasterizer
|
class WaterRasterizer: public Rasterizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WaterRasterizer(SoftwareRenderer* renderer);
|
WaterRasterizer(SoftwareRenderer* renderer, int client_id);
|
||||||
|
|
||||||
void renderSurface();
|
virtual void rasterize();
|
||||||
|
|
||||||
private:
|
|
||||||
SoftwareRenderer* renderer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue