From 05383532b7da1a2ed669d03ee9ca8aa9e6bdcdf1 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Wed, 29 Jun 2016 19:25:57 +0600 Subject: GUI: Add drawLineClip() --- graphics/VectorRenderer.h | 5 +- graphics/VectorRendererSpec.cpp | 124 ++++++++++++++++++++++++++++++++++++++++ graphics/VectorRendererSpec.h | 6 +- 3 files changed, 132 insertions(+), 3 deletions(-) diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h index 38185f1a7b..d180d87217 100644 --- a/graphics/VectorRenderer.h +++ b/graphics/VectorRenderer.h @@ -142,6 +142,7 @@ public: * @param y2 Vertical (Y) coordinate for the line end */ virtual void drawLine(int x1, int y1, int x2, int y2) = 0; + virtual void drawLineClip(int x1, int y1, int x2, int y2, Common::Rect clipping) = 0; /** * Draws a circle centered at (x,y) with radius r. @@ -374,10 +375,10 @@ public: drawSquareClip(x, y, w, h, clip); } - void drawCallback_LINE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) { //TODO + void drawCallback_LINE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) { uint16 x, y, w, h; stepGetPositions(step, area, x, y, w, h); - drawLine(x, y, x + w, y + w); + drawLineClip(x, y, x + w, y + w, clip); } void drawCallback_ROUNDSQ(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) { //TODO diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index cbabdc7caf..3011601168 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -1030,6 +1030,77 @@ drawLine(int x1, int y1, int x2, int y2) { } } +template +void VectorRendererSpec:: +drawLineClip(int x1, int y1, int x2, int y2, Common::Rect clipping) { + x1 = CLIP(x1, 0, (int)Base::_activeSurface->w); + x2 = CLIP(x2, 0, (int)Base::_activeSurface->w); + y1 = CLIP(y1, 0, (int)Base::_activeSurface->h); + y2 = CLIP(y2, 0, (int)Base::_activeSurface->h); + + // we draw from top to bottom + if (y2 < y1) { + SWAP(x1, x2); + SWAP(y1, y2); + } + + uint dx = ABS(x2 - x1); + uint dy = ABS(y2 - y1); + + // this is a point, not a line. stoopid. + if (dy == 0 && dx == 0) + return; + + if (Base::_strokeWidth == 0) + return; + + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1); + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int st = Base::_strokeWidth >> 1; + + Common::Rect backup = _clippingArea; + _clippingArea = clipping; + bool needsClipping = !_clippingArea.isEmpty() && (!_clippingArea.contains(x1, y1) || !_clippingArea.contains(x2, y2)); + if (!needsClipping) { + drawLine(x1, y1, x2, y2); + _clippingArea = backup; + return; + } + + int ptr_x = x1, ptr_y = y1; + + if (dy == 0) { // horizontal lines + colorFillClip(ptr, ptr + dx + 1, (PixelType)_fgColor, x1, y1, _clippingArea); + + for (int i = 0, p = pitch; i < st; ++i, p += pitch) { + colorFillClip(ptr + p, ptr + dx + 1 + p, (PixelType)_fgColor, x1, y1 + p/pitch, _clippingArea); + colorFillClip(ptr - p, ptr + dx + 1 - p, (PixelType)_fgColor, x1, y1 - p/pitch, _clippingArea); + } + + } else if (dx == 0) { // vertical lines + // these ones use a static pitch increase. + while (y1++ <= y2) { + colorFillClip(ptr - st, ptr + st, (PixelType)_fgColor, x1 - st, ptr_y, _clippingArea); + ptr += pitch; + ++ptr_y; + } + + } else if (dx == dy) { // diagonal lines + // these ones also use a fixed pitch increase + pitch += (x2 > x1) ? 1 : -1; + + while (dy--) { + colorFillClip(ptr - st, ptr + st, (PixelType)_fgColor, ptr_x - st, ptr_y, _clippingArea); + ptr += pitch; + ++ptr_y; + if (x2 > x1) ++ptr_x; else --ptr_x; + } + + } else { // generic lines, use the standard algorithm... + drawLineAlgClip(x1, y1, x2, y2, dx, dy, (PixelType)_fgColor); + } +} + /** CIRCLES **/ template void VectorRendererSpec:: @@ -1872,6 +1943,59 @@ drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) { *ptr = (PixelType)color; } +template +void VectorRendererSpec:: +drawLineAlgClip(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) { + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1); + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int xdir = (x2 > x1) ? 1 : -1; + int ptr_x = x1, ptr_y = y1; + + if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color; + + if (dx > dy) { + int ddy = dy * 2; + int dysub = ddy - (dx * 2); + int error_term = ddy - dx; + + while (dx--) { + if (error_term >= 0) { + ptr += pitch; + ++ptr_y; + error_term += dysub; + } else { + error_term += ddy; + } + + ptr += xdir; + ptr_x += xdir; + if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color; + } + } else { + int ddx = dx * 2; + int dxsub = ddx - (dy * 2); + int error_term = ddx - dy; + + while (dy--) { + if (error_term >= 0) { + ptr += xdir; + ptr_x += xdir; + error_term += dxsub; + } else { + error_term += ddx; + } + + ptr += pitch; + ++ptr_y; + if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color; + } + } + + ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2); + ptr_x = x2; ptr_y = y2; + if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color; +} + /** VERTICAL TRIANGLE DRAWING ALGORITHM **/ /** FIXED POINT ARITHMETIC diff --git a/graphics/VectorRendererSpec.h b/graphics/VectorRendererSpec.h index 01910004d2..dcef88e082 100644 --- a/graphics/VectorRendererSpec.h +++ b/graphics/VectorRendererSpec.h @@ -50,7 +50,8 @@ class VectorRendererSpec : public VectorRenderer { public: VectorRendererSpec(PixelFormat format); - void drawLine(int x1, int y1, int x2, int y2); //TODO + void drawLine(int x1, int y1, int x2, int y2); + void drawLineClip(int x1, int y1, int x2, int y2, Common::Rect clipping); void drawCircle(int x, int y, int r); void drawCircleClip(int x, int y, int r, Common::Rect clipping); void drawSquare(int x, int y, int w, int h); @@ -159,6 +160,9 @@ protected: virtual void drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color); + virtual void drawLineAlgClip(int x1, int y1, int x2, int y2, + uint dx, uint dy, PixelType color); + virtual void drawCircleAlg(int x, int y, int r, PixelType color, FillMode fill_m); -- cgit v1.2.3