Only allocate canvas portion pixels when needed
This will allow for larger renders in constant memory footprint
This commit is contained in:
parent
c9fa33984b
commit
3a2ec1c75f
7 changed files with 66 additions and 17 deletions
|
@ -36,8 +36,8 @@ BaseForm(parent, true)
|
|||
|
||||
addInput(new InputCamera(this, tr("Camera"), _camera));
|
||||
addInputInt(tr("Quality"), &_params.quality, 1, 10, 1, 1);
|
||||
addInputInt(tr("Image width"), &_params.width, 100, 2000, 10, 100);
|
||||
addInputInt(tr("Image height"), &_params.height, 100, 1200, 10, 100);
|
||||
addInputInt(tr("Image width"), &_params.width, 100, 4000, 10, 100);
|
||||
addInputInt(tr("Image height"), &_params.height, 100, 3000, 10, 100);
|
||||
addInputInt(tr("Anti aliasing"), &_params.antialias, 1, 4, 1, 1);
|
||||
|
||||
button = addButton(tr("Start new render"));
|
||||
|
|
|
@ -67,8 +67,13 @@ void Canvas::setSize(int width, int height)
|
|||
this->width = width;
|
||||
this->height = height;
|
||||
|
||||
// TODO Smaller preview
|
||||
preview->setSize(width, height, width, height);
|
||||
// Smaller preview
|
||||
while (width > 800 and height > 800)
|
||||
{
|
||||
width = width / 2;
|
||||
height = height / 2;
|
||||
}
|
||||
preview->setSize(this->width, this->height, width, height);
|
||||
}
|
||||
|
||||
CanvasPortion *Canvas::at(int x, int y) const
|
||||
|
|
|
@ -8,20 +8,24 @@
|
|||
#define CHECK_COORDINATES() assert(x >= 0); \
|
||||
assert(x < width); \
|
||||
assert(y >= 0); \
|
||||
assert(y < height)
|
||||
assert(y < height); \
|
||||
assert(pixels != NULL)
|
||||
|
||||
CanvasPortion::CanvasPortion(CanvasPreview* preview):
|
||||
preview(preview)
|
||||
{
|
||||
width = 1;
|
||||
height = 1;
|
||||
pixels = new CanvasPixel[1];
|
||||
pixels = NULL;
|
||||
}
|
||||
|
||||
CanvasPortion::~CanvasPortion()
|
||||
{
|
||||
if (pixels)
|
||||
{
|
||||
delete[] pixels;
|
||||
}
|
||||
}
|
||||
|
||||
int CanvasPortion::getFragmentCount(int x, int y) const
|
||||
{
|
||||
|
@ -50,9 +54,16 @@ void CanvasPortion::setSize(int width, int height)
|
|||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
}
|
||||
|
||||
void CanvasPortion::preparePixels()
|
||||
{
|
||||
if (pixels)
|
||||
{
|
||||
delete[] pixels;
|
||||
}
|
||||
pixels = new CanvasPixel[width * height];
|
||||
clear();
|
||||
}
|
||||
|
||||
void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment)
|
||||
|
|
|
@ -10,6 +10,8 @@ namespace software {
|
|||
* Rectangular portion of a Canvas.
|
||||
*
|
||||
* Contains the pixels of a canvas region (CanvasPixel).
|
||||
*
|
||||
* Pixels are not allocated until preparePixels is called.
|
||||
*/
|
||||
class SOFTWARESHARED_EXPORT CanvasPortion
|
||||
{
|
||||
|
@ -25,6 +27,11 @@ public:
|
|||
void clear();
|
||||
void setSize(int width, int height);
|
||||
|
||||
/**
|
||||
* Prepare (allocate in memory) the pixels area.
|
||||
*/
|
||||
void preparePixels();
|
||||
|
||||
/**
|
||||
* Add a fragment to the pixel located at (x, y).
|
||||
*
|
||||
|
|
|
@ -18,6 +18,11 @@ CanvasPreview::CanvasPreview()
|
|||
dirty_down = 1;
|
||||
dirty_up = -1;
|
||||
|
||||
scaled = false;
|
||||
factor = 1.0;
|
||||
factor_x = 1.0;
|
||||
factor_y = 1.0;
|
||||
|
||||
lock = new Mutex();
|
||||
profile = new ColorProfile();
|
||||
}
|
||||
|
@ -44,6 +49,11 @@ void CanvasPreview::setSize(int real_width, int real_height, int preview_width,
|
|||
dirty_down = height;
|
||||
dirty_up = -1;
|
||||
|
||||
scaled = (real_width != preview_height or real_height != preview_height);
|
||||
factor_x = (double)real_width / (double)preview_width;
|
||||
factor_y = (double)real_height / (double)preview_height;
|
||||
factor = factor_x * factor_y;
|
||||
|
||||
lock->release();
|
||||
|
||||
reset();
|
||||
|
@ -94,17 +104,26 @@ void CanvasPreview::updateLive(CanvasLiveClient *client)
|
|||
|
||||
void CanvasPreview::pushPixel(int real_x, int real_y, const Color &old_color, const Color &new_color)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
lock->acquire();
|
||||
|
||||
// TODO Assert-check and transform coordinates
|
||||
int x = real_x;
|
||||
int y = real_y;
|
||||
double fact = 1.0;
|
||||
// TODO Assert-check
|
||||
if (scaled)
|
||||
{
|
||||
x = round(real_x / factor_x);
|
||||
y = round(real_y / factor_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = real_x;
|
||||
y = real_y;
|
||||
}
|
||||
|
||||
Color* pixel = pixels + (real_y * width + real_x);
|
||||
pixel->r = pixel->r - old_color.r * fact + new_color.r * fact;
|
||||
pixel->g = pixel->g - old_color.g * fact + new_color.g * fact;
|
||||
pixel->b = pixel->b - old_color.b * fact + new_color.b * fact;
|
||||
Color* pixel = pixels + (y * width + x);
|
||||
pixel->r = pixel->r - old_color.r / factor + new_color.r / factor;
|
||||
pixel->g = pixel->g - old_color.g / factor + new_color.g / factor;
|
||||
pixel->b = pixel->b - old_color.b / factor + new_color.b / factor;
|
||||
|
||||
// Set pixel dirty
|
||||
if (x < dirty_left)
|
||||
|
|
|
@ -42,6 +42,11 @@ private:
|
|||
int dirty_right;
|
||||
int dirty_down;
|
||||
int dirty_up;
|
||||
|
||||
bool scaled;
|
||||
double factor;
|
||||
double factor_x;
|
||||
double factor_y;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ void SoftwareCanvasRenderer::render()
|
|||
{
|
||||
// TEMP
|
||||
started = true;
|
||||
CanvasPortion *portion = canvas->at(0, 0);
|
||||
render_width = canvas->getWidth();
|
||||
render_height = canvas->getHeight();
|
||||
render_quality = 3;
|
||||
|
@ -52,6 +51,9 @@ void SoftwareCanvasRenderer::render()
|
|||
|
||||
prepare();
|
||||
|
||||
// TODO Iterate portions
|
||||
CanvasPortion *portion = canvas->at(0, 0);
|
||||
portion->preparePixels();
|
||||
rasterize(portion, true);
|
||||
postProcess(portion, true);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue