From: Sam Moore Date: Tue, 17 Jun 2014 03:45:11 +0000 (+0800) Subject: Bugfixes for CPU rendering X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=6a1c4e752af0bd26803bc2285cff004ef7b9f53d;p=ipdf%2Fcode.git Bugfixes for CPU rendering Fix segfault caused by RectOutlineRenderer not properly checking bounds on pixel array. Fix positioning of RectOutline sides in other locations when they were off the screen. When you zoom in too far, an integer overflow will occur and the CPU rendered objects disappear. This occured at widths of about 1e-7 (for our test pattern). Improved for now by int -> int64_t Later need to replace everything except the actual array access with Real's I think. Then make Real's arbitrary precision. Done. There is a slight size difference between CPU rendered and GPU rendered objects; not sure what the source of this is. Blame rounding. GPU sometimes leaves off the corner pixels of the rectangles by the way. --- diff --git a/src/main.cpp b/src/main.cpp index 94d1cd5..91ce90b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,7 +90,7 @@ int main(int argc, char ** argv) } } - //doc.Add(IPDF::CIRCLE_FILLED, Rect(0.2,0.2,0.6,0.6)); + //doc.Add(IPDF::RECT_OUTLINE, Rect(0.4,0.4,0.6,0.6)); } Rect bounds(b[0],b[1],b[2],b[3]); diff --git a/src/objectrenderer.cpp b/src/objectrenderer.cpp index 1757ae0..e55dbbb 100644 --- a/src/objectrenderer.cpp +++ b/src/objectrenderer.cpp @@ -43,10 +43,11 @@ void ObjectRenderer::RenderUsingGPU() ObjectRenderer::CPURenderBounds::CPURenderBounds(const Rect & bounds, const View & view, const CPURenderTarget & target) { Rect view_bounds = view.TransformToViewCoords(bounds); - x = view_bounds.x * target.w; - y = view_bounds.y * target.h; - w = view_bounds.w * target.w; - h = view_bounds.h * target.h; + x = view_bounds.x * Real(target.w); + y = view_bounds.y * Real(target.h); + w = view_bounds.w * Real(target.w); + h = view_bounds.h * Real(target.h); + Debug("CPURenderBounds %s -> %s -> {%li,%li,%li,%li}", bounds.Str().c_str(), view_bounds.Str().c_str(), x, y, w, h); } /** @@ -120,9 +121,9 @@ void RectFilledRenderer::RenderUsingCPU(const Objects & objects, const View & vi for (unsigned i = 0; i < m_indexes.size(); ++i) { CPURenderBounds bounds(objects.bounds[m_indexes[i]], view, target); - for (int x = max(0, bounds.x); x < min(bounds.x+bounds.w, target.w); ++x) + for (int64_t x = max(0L, bounds.x); x <= min(bounds.x+bounds.w, target.w-1); ++x) { - for (int y = max(0, bounds.y); y < min(bounds.y+bounds.h, target.h); ++y) + for (int64_t y = max(0L, bounds.y); y <= min(bounds.y+bounds.h, target.h-1); ++y) { int index = (x+target.w*y)*4; target.pixels[index+0] = 0; @@ -142,31 +143,41 @@ void RectOutlineRenderer::RenderUsingCPU(const Objects & objects, const View & v for (unsigned i = 0; i < m_indexes.size(); ++i) { CPURenderBounds bounds(objects.bounds[m_indexes[i]], view, target); - for (int x = max(0, bounds.x); x < min(bounds.x+bounds.w, target.w); ++x) + for (int64_t x = max(0L, bounds.x); x <= min(bounds.x+bounds.w, target.w-1); ++x) { - int top = (x+target.w*max(0, bounds.y))*4; - int bottom = (x+target.w*min(bounds.y+bounds.h, target.h))*4; - for (int j = 0; j < 3; ++j) + int64_t top = (x+target.w*bounds.y)*4; + int64_t bottom = (x+target.w*(bounds.y+bounds.h))*4; + + if (top >= 0L && top <4*target.w*target.h) + { + for (int j = 0; j < 3; ++j) + target.pixels[top+j] = 0; + target.pixels[top+3] = 255; + } + if (bottom >= 0L && bottom <4*target.w*target.h) { - target.pixels[top+j] = 0; - target.pixels[bottom+j] = 0; + for (int j = 0; j < 3; ++j) + target.pixels[bottom+j] = 0; + target.pixels[bottom+3] = 255; } - target.pixels[top+3] = 255; - target.pixels[bottom+3] = 255; } - for (int y = max(0, bounds.y); y < min(bounds.y+bounds.h, target.h); ++y) + for (int64_t y = max(0L, bounds.y); y <= min(bounds.y+bounds.h, target.h-1); ++y) { - int left = (max(0, bounds.x)+target.w*y)*4; - int right = (min(bounds.x+bounds.w, target.w)+target.w*y)*4; - for (int j = 0; j < 3; ++j) + int64_t left = (bounds.x >= 0L && bounds.x < target.w) ? (bounds.x + target.w*y)*4 : -1L; + int64_t right = (bounds.x+bounds.w >= 0L && bounds.x+bounds.w < target.w) ? (bounds.x+bounds.w + target.w*y)*4 : -1L; + if (left >= 0L && left <4*target.w*target.h) { - target.pixels[left+j] = 0; - target.pixels[right+j] = 0; + for (int j = 0; j < 3; ++j) + target.pixels[left+j] = 0; + target.pixels[left+3] = 255; + } + if (right >= 0L && right <4*target.w*target.h) + { + for (int j = 0; j < 3; ++j) + target.pixels[right+j] = 0; + target.pixels[right+3] = 255; } - target.pixels[left+3] = 255; - target.pixels[right+3] = 255; - } } } @@ -179,19 +190,19 @@ void CircleFilledRenderer::RenderUsingCPU(const Objects & objects, const View & for (unsigned i = 0; i < m_indexes.size(); ++i) { CPURenderBounds bounds(objects.bounds[m_indexes[i]], view, target); - int centre_x = bounds.x + bounds.w / 2; - int centre_y = bounds.y + bounds.h / 2; + int64_t centre_x = bounds.x + bounds.w / 2; + int64_t centre_y = bounds.y + bounds.h / 2; Debug("Centre is %d, %d", centre_x, centre_y); Debug("Bounds are %d,%d,%d,%d", bounds.x, bounds.y, bounds.w, bounds.h); Debug("Windos is %d,%d", target.w, target.h); - for (int x = max(0, bounds.x); x < min(bounds.x+bounds.w, target.w); ++x) + for (int64_t x = max(0L, bounds.x); x <= min(bounds.x+bounds.w, target.w-1); ++x) { - for (int y = max(0, bounds.y); y < min(bounds.y + bounds.h, target.h); ++y) + for (int64_t y = max(0L, bounds.y); y <= min(bounds.y + bounds.h, target.h-1); ++y) { double dx = 2.0*(double)(x - centre_x)/(double)(bounds.w); double dy = 2.0*(double)(y - centre_y)/(double)(bounds.h); - int index = (x+target.w*y)*4; + int64_t index = (x+target.w*y)*4; if (dx*dx + dy*dy <= 1.0) { diff --git a/src/objectrenderer.h b/src/objectrenderer.h index 0790d85..6dd97ae 100644 --- a/src/objectrenderer.h +++ b/src/objectrenderer.h @@ -44,12 +44,12 @@ namespace IPDF struct CPURenderTarget { uint8_t * pixels; - int w; - int h; + int64_t w; + int64_t h; }; struct CPURenderBounds { - int x; int y; int w; int h; + int64_t x; int64_t y; int64_t w; int64_t h; CPURenderBounds(const Rect & bounds, const View & view, const CPURenderTarget & target); };