Improved render progress.
A bug was also fixed where some canvas pixels were shaded twice, leading to a performance loss.
This commit is contained in:
parent
e8d91e30ac
commit
7c7b6043c5
18 changed files with 320 additions and 101 deletions
|
@ -6,16 +6,18 @@
|
||||||
#include "CanvasPixel.h"
|
#include "CanvasPixel.h"
|
||||||
#include "CanvasFragment.h"
|
#include "CanvasFragment.h"
|
||||||
#include "Rasterizer.h"
|
#include "Rasterizer.h"
|
||||||
|
#include "RenderProgress.h"
|
||||||
|
|
||||||
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)
|
CanvasPixelShader::CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, RenderProgress *progress, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y):
|
||||||
|
renderer(renderer), portion(portion), progress(progress), chunk_size(chunk_size), sub_chunk_size(sub_chunk_size), chunks_x(chunks_x), chunks_y(chunks_y)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasPixelShader::processParallelUnit(int unit)
|
void CanvasPixelShader::processParallelUnit(int unit)
|
||||||
{
|
{
|
||||||
// Locate the chunk we work on
|
// Locate the chunk we work on
|
||||||
int prev_sub_chunk_size = chunk_size * 2;
|
int prev_sub_chunk_size = sub_chunk_size * 2;
|
||||||
int chunk_x = unit / chunks_y;
|
int chunk_x = unit / chunks_y;
|
||||||
int chunk_y = unit % chunks_y;
|
int chunk_y = unit % chunks_y;
|
||||||
int base_x = chunk_x * chunk_size;
|
int base_x = chunk_x * chunk_size;
|
||||||
|
@ -29,6 +31,7 @@ void CanvasPixelShader::processParallelUnit(int unit)
|
||||||
// Iterate on sub-chunks
|
// Iterate on sub-chunks
|
||||||
for (int x = 0; x < limit_x; x += sub_chunk_size)
|
for (int x = 0; x < limit_x; x += sub_chunk_size)
|
||||||
{
|
{
|
||||||
|
int done = 0;
|
||||||
for (int y = 0; y < limit_y; y += sub_chunk_size)
|
for (int y = 0; y < limit_y; y += sub_chunk_size)
|
||||||
{
|
{
|
||||||
if (interrupted)
|
if (interrupted)
|
||||||
|
@ -57,7 +60,10 @@ void CanvasPixelShader::processParallelUnit(int unit)
|
||||||
portion->setColor(base_x + x + fx, base_y + y + fy, composite);
|
portion->setColor(base_x + x + fx, base_y + y + fy, composite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
progress->add(done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,14 @@ namespace software {
|
||||||
class CanvasPixelShader: public ParallelWorker
|
class CanvasPixelShader: public ParallelWorker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y);
|
CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, RenderProgress *progress, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y);
|
||||||
|
|
||||||
virtual void processParallelUnit(int unit) override;
|
virtual void processParallelUnit(int unit) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const SoftwareCanvasRenderer &renderer;
|
const SoftwareCanvasRenderer &renderer;
|
||||||
CanvasPortion *portion;
|
CanvasPortion *portion;
|
||||||
|
RenderProgress *progress;
|
||||||
int chunk_size;
|
int chunk_size;
|
||||||
int sub_chunk_size;
|
int sub_chunk_size;
|
||||||
int chunks_x;
|
int chunks_x;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "CanvasPortion.h"
|
#include "CanvasPortion.h"
|
||||||
#include "CanvasFragment.h"
|
#include "CanvasFragment.h"
|
||||||
#include "Vector3.h"
|
#include "Vector3.h"
|
||||||
|
#include "RenderProgress.h"
|
||||||
|
|
||||||
struct paysages::software::ScanPoint
|
struct paysages::software::ScanPoint
|
||||||
{
|
{
|
||||||
|
@ -31,14 +32,12 @@ struct paysages::software::RenderScanlines
|
||||||
int right;
|
int right;
|
||||||
};
|
};
|
||||||
|
|
||||||
Rasterizer::Rasterizer(SoftwareRenderer* renderer, int client_id, const Color &color):
|
Rasterizer::Rasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id, const Color &color):
|
||||||
renderer(renderer), client_id(client_id)
|
renderer(renderer), progress(progress), client_id(client_id)
|
||||||
{
|
{
|
||||||
this->color = new Color(color);
|
this->color = new Color(color);
|
||||||
|
|
||||||
interrupted = false;
|
interrupted = false;
|
||||||
predicted_poly_count = 0;
|
|
||||||
done_poly_count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rasterizer::~Rasterizer()
|
Rasterizer::~Rasterizer()
|
||||||
|
@ -51,16 +50,6 @@ void Rasterizer::interrupt()
|
||||||
interrupted = true;
|
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)
|
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;
|
ScanPoint point1, point2, point3;
|
||||||
|
|
|
@ -15,19 +15,24 @@ typedef struct RenderScanlines RenderScanlines;
|
||||||
class SOFTWARESHARED_EXPORT Rasterizer
|
class SOFTWARESHARED_EXPORT Rasterizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Rasterizer(SoftwareRenderer *renderer, int client_id, const Color &color);
|
Rasterizer(SoftwareRenderer *renderer, RenderProgress *progress, int client_id, const Color &color);
|
||||||
virtual ~Rasterizer();
|
virtual ~Rasterizer();
|
||||||
|
|
||||||
inline SoftwareRenderer *getRenderer() const {return renderer;}
|
inline SoftwareRenderer *getRenderer() const {return renderer;}
|
||||||
|
|
||||||
virtual void rasterizeToCanvas(CanvasPortion* canvas) = 0;
|
|
||||||
virtual Color shadeFragment(const CanvasFragment &fragment) const = 0;
|
virtual Color shadeFragment(const CanvasFragment &fragment) const = 0;
|
||||||
virtual void interrupt();
|
virtual void interrupt();
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
void addPredictedPolys(int count=1);
|
* Abstract method to prepare for the rasterization process, and return the estimated progress count.
|
||||||
void addDonePolys(int count=1);
|
*/
|
||||||
|
virtual int prepareRasterization() = 0;
|
||||||
|
/**
|
||||||
|
* Abstract method to effectively do the rasterization on a canvas.
|
||||||
|
*/
|
||||||
|
virtual void rasterizeToCanvas(CanvasPortion* canvas) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
void pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3);
|
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 pushTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3);
|
||||||
|
@ -37,6 +42,7 @@ protected:
|
||||||
|
|
||||||
Color* color;
|
Color* color;
|
||||||
SoftwareRenderer *renderer;
|
SoftwareRenderer *renderer;
|
||||||
|
RenderProgress *progress;
|
||||||
int client_id;
|
int client_id;
|
||||||
bool interrupted;
|
bool interrupted;
|
||||||
|
|
||||||
|
@ -46,9 +52,6 @@ private:
|
||||||
void pushScanPoint(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point);
|
void pushScanPoint(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point);
|
||||||
void pushScanLineEdge(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point1, ScanPoint *point2);
|
void pushScanLineEdge(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point1, ScanPoint *point2);
|
||||||
void renderScanLines(CanvasPortion *canvas, RenderScanlines *scanlines);
|
void renderScanLines(CanvasPortion *canvas, RenderScanlines *scanlines);
|
||||||
|
|
||||||
int predicted_poly_count;
|
|
||||||
int done_poly_count;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
54
src/render/software/RenderProgress.cpp
Normal file
54
src/render/software/RenderProgress.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include "RenderProgress.h"
|
||||||
|
|
||||||
|
#include "Mutex.h"
|
||||||
|
|
||||||
|
RenderProgress::RenderProgress(int count)
|
||||||
|
{
|
||||||
|
lock = new Mutex();
|
||||||
|
global = 0.0;
|
||||||
|
step = 1.0 / (double)count;
|
||||||
|
}
|
||||||
|
|
||||||
|
paysages::software::RenderProgress::~RenderProgress()
|
||||||
|
{
|
||||||
|
delete lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderProgress::add(int value)
|
||||||
|
{
|
||||||
|
lock->acquire();
|
||||||
|
|
||||||
|
global += step * (double)value;
|
||||||
|
|
||||||
|
lock->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderProgress::enterSub(int count)
|
||||||
|
{
|
||||||
|
struct RenderSub sub;
|
||||||
|
sub.start = global;
|
||||||
|
sub.end = global + step;
|
||||||
|
sub.count = count;
|
||||||
|
sub.previous_step = step;
|
||||||
|
|
||||||
|
lock->acquire();
|
||||||
|
|
||||||
|
subs.push(sub);
|
||||||
|
step /= (double)count;
|
||||||
|
|
||||||
|
lock->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderProgress::exitSub()
|
||||||
|
{
|
||||||
|
lock->acquire();
|
||||||
|
|
||||||
|
struct RenderSub sub = subs.top();
|
||||||
|
|
||||||
|
global = sub.end;
|
||||||
|
step = sub.previous_step;
|
||||||
|
|
||||||
|
subs.pop();
|
||||||
|
|
||||||
|
lock->release();
|
||||||
|
}
|
43
src/render/software/RenderProgress.h
Normal file
43
src/render/software/RenderProgress.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef RENDERPROGRESS_H
|
||||||
|
#define RENDERPROGRESS_H
|
||||||
|
|
||||||
|
#include "software_global.h"
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace software {
|
||||||
|
|
||||||
|
struct RenderSub {
|
||||||
|
double start;
|
||||||
|
double end;
|
||||||
|
int count;
|
||||||
|
double previous_step;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to keep track of render progress.
|
||||||
|
*/
|
||||||
|
class SOFTWARESHARED_EXPORT RenderProgress
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RenderProgress(int count=1);
|
||||||
|
~RenderProgress();
|
||||||
|
|
||||||
|
inline double get() const {return global;}
|
||||||
|
|
||||||
|
void add(int value=1);
|
||||||
|
void enterSub(int count);
|
||||||
|
void exitSub();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Mutex *lock;
|
||||||
|
double global;
|
||||||
|
double step;
|
||||||
|
std::stack<RenderSub> subs;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // RENDERPROGRESS_H
|
|
@ -8,25 +8,31 @@
|
||||||
#include "CloudsRenderer.h"
|
#include "CloudsRenderer.h"
|
||||||
#include "Rasterizer.h"
|
#include "Rasterizer.h"
|
||||||
#include "CanvasFragment.h"
|
#include "CanvasFragment.h"
|
||||||
|
#include "RenderProgress.h"
|
||||||
|
|
||||||
#define SPHERE_SIZE 20000.0
|
#define SPHERE_SIZE 20000.0
|
||||||
|
|
||||||
SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, int client_id):
|
SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id):
|
||||||
Rasterizer(renderer, client_id, Color(0.9, 0.9, 1.0))
|
Rasterizer(renderer, progress, client_id, Color(0.9, 0.9, 1.0))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SkyRasterizer::prepareRasterization()
|
||||||
|
{
|
||||||
|
res_i = renderer->render_quality * 40;
|
||||||
|
res_j = renderer->render_quality * 20;
|
||||||
|
|
||||||
|
return res_i * res_j;
|
||||||
|
}
|
||||||
|
|
||||||
void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas)
|
void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas)
|
||||||
{
|
{
|
||||||
int res_i, res_j;
|
|
||||||
int i, j;
|
int i, j;
|
||||||
double step_i, step_j;
|
double step_i, step_j;
|
||||||
double current_i, current_j;
|
double current_i, current_j;
|
||||||
Vector3 vertex1, vertex2, vertex3, vertex4;
|
Vector3 vertex1, vertex2, vertex3, vertex4;
|
||||||
Vector3 camera_location, direction;
|
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_i = M_PI * 2.0 / (double)res_i;
|
||||||
step_j = M_PI / (double)res_j;
|
step_j = M_PI / (double)res_j;
|
||||||
|
|
||||||
|
@ -68,6 +74,7 @@ void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas)
|
||||||
/* TODO Triangles at poles */
|
/* TODO Triangles at poles */
|
||||||
pushQuad(canvas, vertex1, vertex4, vertex3, vertex2);
|
pushQuad(canvas, vertex1, vertex4, vertex3, vertex2);
|
||||||
}
|
}
|
||||||
|
progress->add(res_i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,15 @@ namespace software {
|
||||||
class SOFTWARESHARED_EXPORT SkyRasterizer: public Rasterizer
|
class SOFTWARESHARED_EXPORT SkyRasterizer: public Rasterizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SkyRasterizer(SoftwareRenderer* renderer, int client_id);
|
SkyRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id);
|
||||||
|
|
||||||
|
virtual int prepareRasterization() override;
|
||||||
virtual void rasterizeToCanvas(CanvasPortion* canvas) override;
|
virtual void rasterizeToCanvas(CanvasPortion* canvas) override;
|
||||||
virtual Color shadeFragment(const CanvasFragment &fragment) const override;
|
virtual Color shadeFragment(const CanvasFragment &fragment) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int res_i;
|
||||||
|
int res_j;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "RenderConfig.h"
|
#include "RenderConfig.h"
|
||||||
#include "ColorProfile.h"
|
#include "ColorProfile.h"
|
||||||
#include "CanvasPreview.h"
|
#include "CanvasPreview.h"
|
||||||
|
#include "RenderProgress.h"
|
||||||
|
|
||||||
SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery):
|
SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery):
|
||||||
SoftwareRenderer(scenery)
|
SoftwareRenderer(scenery)
|
||||||
|
@ -21,12 +22,12 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery):
|
||||||
finished = false;
|
finished = false;
|
||||||
interrupted = false;
|
interrupted = false;
|
||||||
canvas = new Canvas();
|
canvas = new Canvas();
|
||||||
progress = 0.0;
|
progress = new RenderProgress();
|
||||||
samples = 1;
|
samples = 1;
|
||||||
|
|
||||||
rasterizers.push_back(new SkyRasterizer(this, 0));
|
rasterizers.push_back(new SkyRasterizer(this, progress, 0));
|
||||||
rasterizers.push_back(new WaterRasterizer(this, 1));
|
rasterizers.push_back(new WaterRasterizer(this, progress, 1));
|
||||||
rasterizers.push_back(new TerrainRasterizer(this, 2));
|
rasterizers.push_back(new TerrainRasterizer(this, progress, 2));
|
||||||
|
|
||||||
current_work = NULL;
|
current_work = NULL;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +35,7 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery):
|
||||||
SoftwareCanvasRenderer::~SoftwareCanvasRenderer()
|
SoftwareCanvasRenderer::~SoftwareCanvasRenderer()
|
||||||
{
|
{
|
||||||
delete canvas;
|
delete canvas;
|
||||||
|
delete progress;
|
||||||
|
|
||||||
for (auto &rasterizer: rasterizers)
|
for (auto &rasterizer: rasterizers)
|
||||||
{
|
{
|
||||||
|
@ -41,6 +43,11 @@ SoftwareCanvasRenderer::~SoftwareCanvasRenderer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double SoftwareCanvasRenderer::getProgress() const
|
||||||
|
{
|
||||||
|
return progress->get();
|
||||||
|
}
|
||||||
|
|
||||||
void SoftwareCanvasRenderer::setConfig(const RenderConfig &config)
|
void SoftwareCanvasRenderer::setConfig(const RenderConfig &config)
|
||||||
{
|
{
|
||||||
if (not started)
|
if (not started)
|
||||||
|
@ -62,7 +69,6 @@ void SoftwareCanvasRenderer::setSize(int width, int height, int samples)
|
||||||
void SoftwareCanvasRenderer::render()
|
void SoftwareCanvasRenderer::render()
|
||||||
{
|
{
|
||||||
started = true;
|
started = true;
|
||||||
progress = 0.0;
|
|
||||||
|
|
||||||
render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight());
|
render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight());
|
||||||
|
|
||||||
|
@ -71,32 +77,33 @@ void SoftwareCanvasRenderer::render()
|
||||||
// Iterate portions
|
// Iterate portions
|
||||||
int nx = canvas->getHorizontalPortionCount();
|
int nx = canvas->getHorizontalPortionCount();
|
||||||
int ny = canvas->getVerticalPortionCount();
|
int ny = canvas->getVerticalPortionCount();
|
||||||
int i = 0;
|
|
||||||
int n = nx * ny;
|
int n = nx * ny;
|
||||||
|
progress->enterSub(n);
|
||||||
for (int y = 0; y < ny; y++)
|
for (int y = 0; y < ny; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < nx; x++)
|
for (int x = 0; x < nx; x++)
|
||||||
{
|
{
|
||||||
CanvasPortion *portion = canvas->at(x, y);
|
CanvasPortion *portion = canvas->at(x, y);
|
||||||
|
|
||||||
|
progress->enterSub(2);
|
||||||
|
|
||||||
if (not interrupted)
|
if (not interrupted)
|
||||||
{
|
{
|
||||||
progress_segment = 0.2 / (double)n;
|
|
||||||
portion->preparePixels();
|
portion->preparePixels();
|
||||||
rasterize(portion);
|
rasterize(portion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not interrupted)
|
if (not interrupted)
|
||||||
{
|
{
|
||||||
progress_segment = 0.8 / (double)n;
|
|
||||||
applyPixelShader(portion);
|
applyPixelShader(portion);
|
||||||
}
|
}
|
||||||
|
|
||||||
portion->discardPixels();
|
portion->discardPixels();
|
||||||
i++;
|
|
||||||
progress = (double)i / (double)n;
|
progress->exitSub();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
progress->exitSub();
|
||||||
finished = true;
|
finished = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,11 +133,18 @@ bool SoftwareCanvasRenderer::saveToDisk(const std::string &filepath) const
|
||||||
|
|
||||||
void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion)
|
void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion)
|
||||||
{
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (auto &rasterizer:rasterizers)
|
||||||
|
{
|
||||||
|
count += rasterizer->prepareRasterization();
|
||||||
|
}
|
||||||
|
|
||||||
|
progress->enterSub(count);
|
||||||
for (auto &rasterizer:rasterizers)
|
for (auto &rasterizer:rasterizers)
|
||||||
{
|
{
|
||||||
rasterizer->rasterizeToCanvas(portion);
|
rasterizer->rasterizeToCanvas(portion);
|
||||||
progress += progress_segment / (double)rasterizers.size();
|
|
||||||
}
|
}
|
||||||
|
progress->exitSub();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion)
|
void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion)
|
||||||
|
@ -141,14 +155,8 @@ void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion)
|
||||||
int chunks_y = (portion->getHeight() - 1) / chunk_size + 1;
|
int chunks_y = (portion->getHeight() - 1) / chunk_size + 1;
|
||||||
int units = chunks_x * chunks_y;
|
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
|
// Render chunks in parallel
|
||||||
|
progress->enterSub(portion->getWidth() * portion->getHeight());
|
||||||
for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2)
|
for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2)
|
||||||
{
|
{
|
||||||
if (interrupted)
|
if (interrupted)
|
||||||
|
@ -156,12 +164,12 @@ void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CanvasPixelShader shader(*this, portion, chunk_size, sub_chunk_size, chunks_x, chunks_y);
|
CanvasPixelShader shader(*this, portion, progress, chunk_size, sub_chunk_size, chunks_x, chunks_y);
|
||||||
ParallelWork work(&shader, units);
|
ParallelWork work(&shader, units);
|
||||||
|
|
||||||
current_work = &work;
|
current_work = &work;
|
||||||
work.perform();
|
work.perform();
|
||||||
current_work = NULL;
|
current_work = NULL;
|
||||||
progress += progress_segment * (double)(chunk_size / sub_chunk_size) / (double)n;
|
|
||||||
}
|
}
|
||||||
|
progress->exitSub();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,13 @@ public:
|
||||||
virtual ~SoftwareCanvasRenderer();
|
virtual ~SoftwareCanvasRenderer();
|
||||||
|
|
||||||
inline const Canvas *getCanvas() const {return canvas;}
|
inline const Canvas *getCanvas() const {return canvas;}
|
||||||
inline double getProgress() const {return progress;}
|
|
||||||
inline bool isFinished() const {return finished;}
|
inline bool isFinished() const {return finished;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the global rendering progress (0.0-1.0).
|
||||||
|
*/
|
||||||
|
double getProgress() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the renderer configuration.
|
* Set the renderer configuration.
|
||||||
*/
|
*/
|
||||||
|
@ -72,8 +76,7 @@ protected:
|
||||||
void applyPixelShader(CanvasPortion *portion);
|
void applyPixelShader(CanvasPortion *portion);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double progress;
|
RenderProgress *progress;
|
||||||
double progress_segment;
|
|
||||||
|
|
||||||
Canvas *canvas;
|
Canvas *canvas;
|
||||||
int samples;
|
int samples;
|
||||||
|
|
|
@ -9,9 +9,10 @@
|
||||||
#include "Scenery.h"
|
#include "Scenery.h"
|
||||||
#include "CanvasPortion.h"
|
#include "CanvasPortion.h"
|
||||||
#include "CanvasFragment.h"
|
#include "CanvasFragment.h"
|
||||||
|
#include "RenderProgress.h"
|
||||||
|
|
||||||
TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id):
|
TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id):
|
||||||
Rasterizer(renderer, client_id, Color(1.0, 0.9, 0.9))
|
Rasterizer(renderer, progress, client_id, Color(1.0, 0.9, 0.9))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,11 +23,6 @@ static inline Vector3 _getPoint(SoftwareRenderer* renderer, double x, double z)
|
||||||
|
|
||||||
void TerrainRasterizer::tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail)
|
void TerrainRasterizer::tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail)
|
||||||
{
|
{
|
||||||
if (detail < 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double water_height = renderer->getWaterRenderer()->getHeightInfo().min_height;
|
double water_height = renderer->getWaterRenderer()->getHeightInfo().min_height;
|
||||||
|
|
||||||
double startx = chunk->point_nw.x;
|
double startx = chunk->point_nw.x;
|
||||||
|
@ -40,6 +36,7 @@ void TerrainRasterizer::tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo*
|
||||||
{
|
{
|
||||||
renderQuad(canvas, startx + (double)i * size, startz + (double)j * size, size, water_height);
|
renderQuad(canvas, startx + (double)i * size, startz + (double)j * size, size, water_height);
|
||||||
}
|
}
|
||||||
|
progress->add(detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,12 +122,11 @@ static void _getChunk(SoftwareRenderer* renderer, TerrainRasterizer::TerrainChun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, bool displaced)
|
int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced)
|
||||||
{
|
{
|
||||||
TerrainChunkInfo chunk;
|
TerrainChunkInfo chunk;
|
||||||
int chunk_factor, chunk_count, i;
|
int chunk_factor, chunk_count, i, result;
|
||||||
Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO);
|
Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO);
|
||||||
double progress;
|
|
||||||
double radius_int, radius_ext;
|
double radius_int, radius_ext;
|
||||||
double base_chunk_size, chunk_size;
|
double base_chunk_size, chunk_size;
|
||||||
|
|
||||||
|
@ -141,42 +137,69 @@ void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, bool displace
|
||||||
radius_int = 0.0;
|
radius_int = 0.0;
|
||||||
radius_ext = base_chunk_size;
|
radius_ext = base_chunk_size;
|
||||||
chunk_size = base_chunk_size;
|
chunk_size = base_chunk_size;
|
||||||
progress = 0.0;
|
result = 0;
|
||||||
|
|
||||||
double cx = cam.x - fmod(cam.x, base_chunk_size);
|
double cx = cam.x - fmod(cam.x, base_chunk_size);
|
||||||
double cz = cam.z - fmod(cam.x, base_chunk_size);
|
double cz = cam.z - fmod(cam.x, base_chunk_size);
|
||||||
|
|
||||||
while (radius_int < 20000.0)
|
while (radius_int < 20000.0)
|
||||||
{
|
{
|
||||||
progress = radius_int / 20000.0;
|
|
||||||
for (i = 0; i < chunk_count - 1; i++)
|
for (i = 0; i < chunk_count - 1; i++)
|
||||||
{
|
{
|
||||||
_getChunk(renderer, &chunk, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size, displaced);
|
_getChunk(renderer, &chunk, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size, displaced);
|
||||||
processChunk(canvas, &chunk, progress);
|
if (chunk.detail_hint > 0)
|
||||||
|
{
|
||||||
|
result += chunk.detail_hint * chunk.detail_hint;
|
||||||
|
if (canvas)
|
||||||
|
{
|
||||||
|
processChunk(canvas, &chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (interrupted)
|
if (interrupted)
|
||||||
{
|
{
|
||||||
return;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
_getChunk(renderer, &chunk, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size, displaced);
|
_getChunk(renderer, &chunk, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size, displaced);
|
||||||
processChunk(canvas, &chunk, progress);
|
if (chunk.detail_hint > 0)
|
||||||
|
{
|
||||||
|
result += chunk.detail_hint * chunk.detail_hint;
|
||||||
|
if (canvas)
|
||||||
|
{
|
||||||
|
processChunk(canvas, &chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (interrupted)
|
if (interrupted)
|
||||||
{
|
{
|
||||||
return;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
_getChunk(renderer, &chunk, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size, displaced);
|
_getChunk(renderer, &chunk, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size, displaced);
|
||||||
processChunk(canvas, &chunk, progress);
|
if (chunk.detail_hint > 0)
|
||||||
|
{
|
||||||
|
result += chunk.detail_hint * chunk.detail_hint;
|
||||||
|
if (canvas)
|
||||||
|
{
|
||||||
|
processChunk(canvas, &chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (interrupted)
|
if (interrupted)
|
||||||
{
|
{
|
||||||
return;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
_getChunk(renderer, &chunk, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size, displaced);
|
_getChunk(renderer, &chunk, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size, displaced);
|
||||||
processChunk(canvas, &chunk, progress);
|
if (chunk.detail_hint > 0)
|
||||||
|
{
|
||||||
|
result += chunk.detail_hint * chunk.detail_hint;
|
||||||
|
if (canvas)
|
||||||
|
{
|
||||||
|
processChunk(canvas, &chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (interrupted)
|
if (interrupted)
|
||||||
{
|
{
|
||||||
return;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,16 +213,24 @@ void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, bool displace
|
||||||
radius_int = radius_ext;
|
radius_int = radius_ext;
|
||||||
radius_ext += chunk_size;
|
radius_ext += chunk_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double)
|
void TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk)
|
||||||
{
|
{
|
||||||
tessellateChunk(canvas, chunk, chunk->detail_hint);
|
tessellateChunk(canvas, chunk, chunk->detail_hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TerrainRasterizer::prepareRasterization()
|
||||||
|
{
|
||||||
|
// TODO Chunks could be saved and reused in rasterizeToCanvas
|
||||||
|
return performTessellation(NULL, false);
|
||||||
|
}
|
||||||
|
|
||||||
void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas)
|
void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas)
|
||||||
{
|
{
|
||||||
getTessellationInfo(canvas, false);
|
performTessellation(canvas, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Color TerrainRasterizer::shadeFragment(const CanvasFragment &fragment) const
|
Color TerrainRasterizer::shadeFragment(const CanvasFragment &fragment) const
|
||||||
|
|
|
@ -22,19 +22,28 @@ public:
|
||||||
} TerrainChunkInfo;
|
} TerrainChunkInfo;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TerrainRasterizer(SoftwareRenderer* renderer, int client_id);
|
TerrainRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id);
|
||||||
|
|
||||||
|
virtual int prepareRasterization() override;
|
||||||
|
virtual void rasterizeToCanvas(CanvasPortion* canvas) override;
|
||||||
|
virtual Color shadeFragment(const CanvasFragment &fragment) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
/**
|
/**
|
||||||
* Method called for each chunk tessellated by getTessellationInfo.
|
* Method called for each chunk tessellated by performTessellation.
|
||||||
*/
|
*/
|
||||||
void processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double progress);
|
void processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tessellate the terrain, calling processChunk for each chunk.
|
* Tessellate the terrain, calling processChunk for each chunk.
|
||||||
*
|
*
|
||||||
* The terrain will be broken in chunks, most detailed near the camera.
|
* The terrain will be broken in chunks, most detailed near the camera.
|
||||||
|
*
|
||||||
|
* Return the number of quads that has been pushed.
|
||||||
|
*
|
||||||
|
* *canvas* may be NULL to only simulate the tessellation.
|
||||||
*/
|
*/
|
||||||
void getTessellationInfo(CanvasPortion* canvas, bool displaced);
|
int performTessellation(CanvasPortion* canvas, bool displaced);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tessellate a terrain chunk, pushing the quads in the render area.
|
* Tessellate a terrain chunk, pushing the quads in the render area.
|
||||||
|
@ -42,9 +51,6 @@ public:
|
||||||
void tessellateChunk(CanvasPortion* canvas, 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);
|
void renderQuad(CanvasPortion* canvas, double x, double z, double size, double water_height);
|
||||||
|
|
||||||
virtual void rasterizeToCanvas(CanvasPortion* canvas) override;
|
|
||||||
virtual Color shadeFragment(const CanvasFragment &fragment) const override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
#include "SoftwareRenderer.h"
|
#include "SoftwareRenderer.h"
|
||||||
#include "WaterRenderer.h"
|
#include "WaterRenderer.h"
|
||||||
#include "CanvasFragment.h"
|
#include "CanvasFragment.h"
|
||||||
|
#include "RenderProgress.h"
|
||||||
|
|
||||||
WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, int client_id):
|
WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id):
|
||||||
Rasterizer(renderer, client_id, Color(0.9, 0.95, 1.0))
|
Rasterizer(renderer, progress, client_id, Color(0.9, 0.95, 1.0))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,9 +33,25 @@ void WaterRasterizer::rasterizeQuad(CanvasPortion* canvas, double x, double z, d
|
||||||
pushQuad(canvas, v1, v2, v3, v4);
|
pushQuad(canvas, v1, v2, v3, v4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WaterRasterizer::prepareRasterization()
|
||||||
|
{
|
||||||
|
return performTessellation(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas)
|
void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas)
|
||||||
{
|
{
|
||||||
int chunk_factor, chunk_count, i;
|
performTessellation(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color WaterRasterizer::shadeFragment(const CanvasFragment &fragment) const
|
||||||
|
{
|
||||||
|
Vector3 location = fragment.getLocation();
|
||||||
|
return renderer->getWaterRenderer()->getResult(location.x, location.z).final;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WaterRasterizer::performTessellation(CanvasPortion *canvas)
|
||||||
|
{
|
||||||
|
int chunk_factor, chunk_count, i, result;
|
||||||
Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO);
|
Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO);
|
||||||
double radius_int, radius_ext, base_chunk_size, chunk_size;
|
double radius_int, radius_ext, base_chunk_size, chunk_size;
|
||||||
|
|
||||||
|
@ -44,6 +61,7 @@ void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas)
|
||||||
base_chunk_size *= 0.5;
|
base_chunk_size *= 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = 0;
|
||||||
chunk_factor = 1;
|
chunk_factor = 1;
|
||||||
chunk_count = 2;
|
chunk_count = 2;
|
||||||
radius_int = 0.0;
|
radius_int = 0.0;
|
||||||
|
@ -57,15 +75,23 @@ void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas)
|
||||||
{
|
{
|
||||||
if (interrupted)
|
if (interrupted)
|
||||||
{
|
{
|
||||||
return;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < chunk_count - 1; i++)
|
for (i = 0; i < chunk_count - 1; i++)
|
||||||
{
|
{
|
||||||
rasterizeQuad(canvas, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size);
|
result++;
|
||||||
rasterizeQuad(canvas, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size);
|
if (canvas)
|
||||||
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);
|
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 (canvas)
|
||||||
|
{
|
||||||
|
progress->add(chunk_count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (radius_int > 20.0 && chunk_count % 64 == 0 && (double)chunk_factor < radius_int / 20.0)
|
if (radius_int > 20.0 && chunk_count % 64 == 0 && (double)chunk_factor < radius_int / 20.0)
|
||||||
|
@ -78,10 +104,6 @@ void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas)
|
||||||
radius_int = radius_ext;
|
radius_int = radius_ext;
|
||||||
radius_ext += chunk_size;
|
radius_ext += chunk_size;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Color WaterRasterizer::shadeFragment(const CanvasFragment &fragment) const
|
return result;
|
||||||
{
|
|
||||||
Vector3 location = fragment.getLocation();
|
|
||||||
return renderer->getWaterRenderer()->getResult(location.x, location.z).final;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,16 @@ namespace software {
|
||||||
class WaterRasterizer: public Rasterizer
|
class WaterRasterizer: public Rasterizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WaterRasterizer(SoftwareRenderer* renderer, int client_id);
|
WaterRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id);
|
||||||
|
|
||||||
void rasterizeQuad(CanvasPortion* canvas, double x, double z, double size);
|
void rasterizeQuad(CanvasPortion* canvas, double x, double z, double size);
|
||||||
|
|
||||||
|
virtual int prepareRasterization() override;
|
||||||
virtual void rasterizeToCanvas(CanvasPortion* canvas) override;
|
virtual void rasterizeToCanvas(CanvasPortion* canvas) override;
|
||||||
virtual Color shadeFragment(const CanvasFragment &fragment) const override;
|
virtual Color shadeFragment(const CanvasFragment &fragment) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int performTessellation(CanvasPortion* canvas);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,8 @@ SOURCES += SoftwareRenderer.cpp \
|
||||||
CanvasPictureWriter.cpp \
|
CanvasPictureWriter.cpp \
|
||||||
clouds/CloudModelAltoCumulus.cpp \
|
clouds/CloudModelAltoCumulus.cpp \
|
||||||
clouds/CloudModelCirrus.cpp \
|
clouds/CloudModelCirrus.cpp \
|
||||||
clouds/CloudModelCumuloNimbus.cpp
|
clouds/CloudModelCumuloNimbus.cpp \
|
||||||
|
RenderProgress.cpp
|
||||||
|
|
||||||
HEADERS += SoftwareRenderer.h\
|
HEADERS += SoftwareRenderer.h\
|
||||||
software_global.h \
|
software_global.h \
|
||||||
|
@ -90,7 +91,8 @@ HEADERS += SoftwareRenderer.h\
|
||||||
CanvasPictureWriter.h \
|
CanvasPictureWriter.h \
|
||||||
clouds/CloudModelAltoCumulus.h \
|
clouds/CloudModelAltoCumulus.h \
|
||||||
clouds/CloudModelCirrus.h \
|
clouds/CloudModelCirrus.h \
|
||||||
clouds/CloudModelCumuloNimbus.h
|
clouds/CloudModelCumuloNimbus.h \
|
||||||
|
RenderProgress.h
|
||||||
|
|
||||||
unix:!symbian {
|
unix:!symbian {
|
||||||
maemo5 {
|
maemo5 {
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace software {
|
||||||
class SoftwareRenderer;
|
class SoftwareRenderer;
|
||||||
class SoftwareCanvasRenderer;
|
class SoftwareCanvasRenderer;
|
||||||
class RenderConfig;
|
class RenderConfig;
|
||||||
|
class RenderProgress;
|
||||||
|
|
||||||
class FluidMediumManager;
|
class FluidMediumManager;
|
||||||
class FluidMediumInterface;
|
class FluidMediumInterface;
|
||||||
|
|
33
src/tests/RenderProgress_Test.cpp
Normal file
33
src/tests/RenderProgress_Test.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "BaseTestCase.h"
|
||||||
|
|
||||||
|
#include "RenderProgress.h"
|
||||||
|
|
||||||
|
TEST(RenderProgress, RecursiveSections)
|
||||||
|
{
|
||||||
|
RenderProgress progress(2);
|
||||||
|
EXPECT_DOUBLE_EQ(0.0, progress.get());
|
||||||
|
|
||||||
|
progress.enterSub(5);
|
||||||
|
EXPECT_DOUBLE_EQ(0.0, progress.get());
|
||||||
|
|
||||||
|
progress.add();
|
||||||
|
EXPECT_DOUBLE_EQ(0.1, progress.get());
|
||||||
|
|
||||||
|
progress.add(2);
|
||||||
|
EXPECT_DOUBLE_EQ(0.3, progress.get());
|
||||||
|
|
||||||
|
progress.enterSub(4);
|
||||||
|
EXPECT_DOUBLE_EQ(0.3, progress.get());
|
||||||
|
|
||||||
|
progress.add(1);
|
||||||
|
EXPECT_DOUBLE_EQ(0.325, progress.get());
|
||||||
|
|
||||||
|
progress.exitSub();
|
||||||
|
EXPECT_DOUBLE_EQ(0.4, progress.get());
|
||||||
|
|
||||||
|
progress.exitSub();
|
||||||
|
EXPECT_DOUBLE_EQ(0.5, progress.get());
|
||||||
|
|
||||||
|
progress.add(1);
|
||||||
|
EXPECT_DOUBLE_EQ(1.0, progress.get());
|
||||||
|
}
|
|
@ -26,7 +26,8 @@ SOURCES += main.cpp \
|
||||||
DefinitionNode_Test.cpp \
|
DefinitionNode_Test.cpp \
|
||||||
FloatNode_Test.cpp \
|
FloatNode_Test.cpp \
|
||||||
DiffManager_Test.cpp \
|
DiffManager_Test.cpp \
|
||||||
ColorHSL_Test.cpp
|
ColorHSL_Test.cpp \
|
||||||
|
RenderProgress_Test.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
BaseTestCase.h
|
BaseTestCase.h
|
||||||
|
|
Loading…
Reference in a new issue