2014-06-05 15:12:49 +00:00
|
|
|
#include "SoftwareCanvasRenderer.h"
|
|
|
|
|
|
|
|
#include "Rasterizer.h"
|
|
|
|
#include "SoftwareRenderer.h"
|
|
|
|
#include "Canvas.h"
|
2014-06-12 15:45:59 +00:00
|
|
|
#include "TerrainRasterizer.h"
|
|
|
|
#include "WaterRasterizer.h"
|
|
|
|
#include "SkyRasterizer.h"
|
2015-10-18 15:26:19 +00:00
|
|
|
#include "VegetationRasterizer.h"
|
2014-06-12 15:45:59 +00:00
|
|
|
#include "CameraDefinition.h"
|
2014-08-18 10:17:16 +00:00
|
|
|
#include "ParallelWork.h"
|
|
|
|
#include "CanvasPortion.h"
|
|
|
|
#include "CanvasPixelShader.h"
|
2014-08-20 12:23:35 +00:00
|
|
|
#include "RenderConfig.h"
|
2014-08-21 10:36:28 +00:00
|
|
|
#include "ColorProfile.h"
|
|
|
|
#include "CanvasPreview.h"
|
2015-08-23 18:22:37 +00:00
|
|
|
#include "RenderProgress.h"
|
2014-06-05 15:12:49 +00:00
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery) : SoftwareRenderer(scenery) {
|
2014-06-05 15:12:49 +00:00
|
|
|
started = false;
|
2014-09-09 15:56:52 +00:00
|
|
|
finished = false;
|
2014-08-19 12:20:37 +00:00
|
|
|
interrupted = false;
|
2014-06-05 15:12:49 +00:00
|
|
|
canvas = new Canvas();
|
2015-08-23 18:22:37 +00:00
|
|
|
progress = new RenderProgress();
|
2014-08-21 10:36:28 +00:00
|
|
|
samples = 1;
|
2014-06-12 15:45:59 +00:00
|
|
|
|
2015-09-10 17:33:52 +00:00
|
|
|
postprocess_enabled = true;
|
|
|
|
|
2015-11-09 00:07:33 +00:00
|
|
|
rasterizers.push_back(rasterizer_sky = new SkyRasterizer(this, progress, RASTERIZER_CLIENT_SKY));
|
|
|
|
rasterizers.push_back(rasterizer_water = new WaterRasterizer(this, progress, RASTERIZER_CLIENT_WATER));
|
|
|
|
rasterizers.push_back(rasterizer_terrain = new TerrainRasterizer(this, progress, RASTERIZER_CLIENT_TERRAIN));
|
2015-11-09 21:38:00 +00:00
|
|
|
rasterizers.push_back(rasterizer_vegetation =
|
|
|
|
new VegetationRasterizer(this, progress, RASTERIZER_CLIENT_VEGETATION));
|
2014-08-19 07:18:55 +00:00
|
|
|
|
|
|
|
current_work = NULL;
|
2014-06-05 15:12:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
SoftwareCanvasRenderer::~SoftwareCanvasRenderer() {
|
2014-06-05 15:12:49 +00:00
|
|
|
delete canvas;
|
2015-08-23 18:22:37 +00:00
|
|
|
delete progress;
|
2014-06-12 15:45:59 +00:00
|
|
|
|
2015-11-09 00:07:33 +00:00
|
|
|
delete rasterizer_sky;
|
|
|
|
delete rasterizer_water;
|
|
|
|
delete rasterizer_terrain;
|
|
|
|
delete rasterizer_vegetation;
|
2014-06-05 15:12:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void SoftwareCanvasRenderer::setQuality(double factor) {
|
2015-09-10 17:33:52 +00:00
|
|
|
SoftwareRenderer::setQuality(factor);
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
for (auto &rasterizer : rasterizers) {
|
2015-09-10 17:33:52 +00:00
|
|
|
rasterizer->setQuality(factor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void SoftwareCanvasRenderer::setSoloRasterizer(Rasterizer *rasterizer) {
|
2015-09-13 16:58:11 +00:00
|
|
|
rasterizers.clear();
|
|
|
|
rasterizers.push_back(rasterizer);
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
double SoftwareCanvasRenderer::getProgress() const {
|
2015-08-23 18:22:37 +00:00
|
|
|
return progress->get();
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void SoftwareCanvasRenderer::setConfig(const RenderConfig &config) {
|
|
|
|
if (not started) {
|
2014-08-20 12:23:35 +00:00
|
|
|
setSize(config.width, config.height, config.antialias);
|
2015-12-17 00:13:20 +00:00
|
|
|
setQuality(to_double(config.quality - 1) / 9.0);
|
2014-08-20 12:23:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void SoftwareCanvasRenderer::enablePostprocess(bool enabled) {
|
2015-09-10 17:33:52 +00:00
|
|
|
this->postprocess_enabled = enabled;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void SoftwareCanvasRenderer::setSize(int width, int height, int samples) {
|
|
|
|
if (not started) {
|
2014-06-05 15:12:49 +00:00
|
|
|
canvas->setSize(width * samples, height * samples);
|
2014-08-21 10:36:28 +00:00
|
|
|
this->samples = samples;
|
2014-06-05 15:12:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void SoftwareCanvasRenderer::render() {
|
2014-06-05 15:12:49 +00:00
|
|
|
started = true;
|
2015-09-09 22:40:47 +00:00
|
|
|
progress->reset();
|
2014-06-05 15:12:49 +00:00
|
|
|
|
2014-06-18 18:10:05 +00:00
|
|
|
prepare();
|
2015-11-18 17:39:31 +00:00
|
|
|
render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight());
|
2014-06-18 18:10:05 +00:00
|
|
|
|
2014-08-18 15:33:15 +00:00
|
|
|
// Iterate portions
|
|
|
|
int nx = canvas->getHorizontalPortionCount();
|
|
|
|
int ny = canvas->getVerticalPortionCount();
|
2014-08-20 13:58:37 +00:00
|
|
|
int n = nx * ny;
|
2015-08-23 18:22:37 +00:00
|
|
|
progress->enterSub(n);
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int y = 0; y < ny; y++) {
|
|
|
|
for (int x = 0; x < nx; x++) {
|
2014-08-18 15:33:15 +00:00
|
|
|
CanvasPortion *portion = canvas->at(x, y);
|
2014-08-19 07:18:55 +00:00
|
|
|
|
2015-08-23 18:22:37 +00:00
|
|
|
progress->enterSub(2);
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (not interrupted) {
|
2014-08-19 07:18:55 +00:00
|
|
|
portion->preparePixels();
|
2014-08-20 13:58:37 +00:00
|
|
|
rasterize(portion);
|
2014-08-19 07:18:55 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (not interrupted and postprocess_enabled) {
|
2014-08-20 13:58:37 +00:00
|
|
|
applyPixelShader(portion);
|
2014-08-19 07:18:55 +00:00
|
|
|
}
|
|
|
|
|
2014-08-18 15:33:15 +00:00
|
|
|
portion->discardPixels();
|
2015-08-23 18:22:37 +00:00
|
|
|
|
|
|
|
progress->exitSub();
|
2014-08-18 15:33:15 +00:00
|
|
|
}
|
|
|
|
}
|
2015-08-23 18:22:37 +00:00
|
|
|
progress->exitSub();
|
2015-09-13 20:38:44 +00:00
|
|
|
progress->end();
|
2014-09-09 15:56:52 +00:00
|
|
|
finished = true;
|
2014-06-05 15:12:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void SoftwareCanvasRenderer::interrupt() {
|
2014-08-19 12:20:37 +00:00
|
|
|
interrupted = true;
|
2014-08-19 07:18:55 +00:00
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (current_work) {
|
2014-08-19 07:18:55 +00:00
|
|
|
current_work->interrupt();
|
|
|
|
}
|
2015-11-09 21:30:46 +00:00
|
|
|
for (auto &rasterizer : rasterizers) {
|
2014-08-19 09:44:54 +00:00
|
|
|
rasterizer->interrupt();
|
|
|
|
}
|
2014-08-19 07:18:55 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
const Rasterizer &SoftwareCanvasRenderer::getRasterizer(int client_id) const {
|
2014-08-20 13:58:37 +00:00
|
|
|
return *(rasterizers[client_id]);
|
2014-08-18 10:17:16 +00:00
|
|
|
}
|
|
|
|
|
2015-12-10 23:36:50 +00:00
|
|
|
bool SoftwareCanvasRenderer::saveToDisk(const string &filepath) const {
|
2014-08-21 10:36:28 +00:00
|
|
|
return getCanvas()->saveToDisk(filepath, *getCanvas()->getPreview()->getToneMapping(), samples);
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion) {
|
2015-08-23 18:22:37 +00:00
|
|
|
int count = 0;
|
2015-11-09 21:30:46 +00:00
|
|
|
for (auto &rasterizer : rasterizers) {
|
2015-08-23 18:22:37 +00:00
|
|
|
count += rasterizer->prepareRasterization();
|
|
|
|
}
|
|
|
|
|
|
|
|
progress->enterSub(count);
|
2015-11-09 21:30:46 +00:00
|
|
|
for (auto &rasterizer : rasterizers) {
|
2014-06-12 15:45:59 +00:00
|
|
|
rasterizer->rasterizeToCanvas(portion);
|
2014-06-05 15:12:49 +00:00
|
|
|
}
|
2015-08-23 18:22:37 +00:00
|
|
|
progress->exitSub();
|
2014-06-05 15:12:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion) {
|
2014-08-18 10:17:16 +00:00
|
|
|
// Subdivide in chunks
|
2014-08-18 14:04:46 +00:00
|
|
|
int chunk_size = 64;
|
2014-08-18 13:20:04 +00:00
|
|
|
int chunks_x = (portion->getWidth() - 1) / chunk_size + 1;
|
|
|
|
int chunks_y = (portion->getHeight() - 1) / chunk_size + 1;
|
2014-08-18 10:17:16 +00:00
|
|
|
int units = chunks_x * chunks_y;
|
|
|
|
|
|
|
|
// Render chunks in parallel
|
2015-08-23 18:22:37 +00:00
|
|
|
progress->enterSub(portion->getWidth() * portion->getHeight());
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2) {
|
|
|
|
if (interrupted) {
|
2014-08-19 07:18:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-23 18:22:37 +00:00
|
|
|
CanvasPixelShader shader(*this, portion, progress, chunk_size, sub_chunk_size, chunks_x, chunks_y);
|
2014-08-18 14:04:46 +00:00
|
|
|
ParallelWork work(&shader, units);
|
2014-08-19 07:18:55 +00:00
|
|
|
|
|
|
|
current_work = &work;
|
2014-08-18 14:04:46 +00:00
|
|
|
work.perform();
|
2014-08-19 07:18:55 +00:00
|
|
|
current_work = NULL;
|
2014-08-18 14:04:46 +00:00
|
|
|
}
|
2015-08-23 18:22:37 +00:00
|
|
|
progress->exitSub();
|
2014-06-05 15:12:49 +00:00
|
|
|
}
|