diff options
author | Eugene Sandulenko | 2016-02-07 19:02:53 +0100 |
---|---|---|
committer | Eugene Sandulenko | 2016-02-14 17:13:03 +0100 |
commit | 5e002c4fe2e1019e2d4f33b335d41eabb41ed63f (patch) | |
tree | 0ad2ebc36ccf5033b17eb1da2ed78357f68f2a03 | |
parent | 1d5220ef3fb5ed1a869d88ee67b28cb0433f8578 (diff) | |
download | scummvm-rg350-5e002c4fe2e1019e2d4f33b335d41eabb41ed63f.tar.gz scummvm-rg350-5e002c4fe2e1019e2d4f33b335d41eabb41ed63f.tar.bz2 scummvm-rg350-5e002c4fe2e1019e2d4f33b335d41eabb41ed63f.zip |
GRAPHICS: Move generic primitives from WAGE engine
-rw-r--r-- | engines/wage/design.cpp | 378 | ||||
-rw-r--r-- | engines/wage/design.h | 10 | ||||
-rw-r--r-- | graphics/primitives.cpp | 357 | ||||
-rw-r--r-- | graphics/primitives.h | 11 |
4 files changed, 378 insertions, 378 deletions
diff --git a/engines/wage/design.cpp b/engines/wage/design.cpp index 8e5c753321..2acd872812 100644 --- a/engines/wage/design.cpp +++ b/engines/wage/design.cpp @@ -226,7 +226,7 @@ void Design::drawRect(Graphics::Surface *surface, Common::ReadStream &in, plotData pd(surface, &patterns, fillType, 1); if (fillType <= patterns.size()) - drawFilledRect(r, kColorBlack, drawPixel, &pd); + Graphics::drawFilledRect(r, kColorBlack, drawPixel, &pd); pd.fillType = borderFillType; pd.thickness = borderThickness; @@ -256,13 +256,13 @@ void Design::drawRoundRect(Graphics::Surface *surface, Common::ReadStream &in, plotData pd(surface, &patterns, fillType, 1); if (fillType <= patterns.size()) - drawRoundRect(r, arc/2, kColorBlack, true, drawPixel, &pd); + Graphics::drawRoundRect(r, arc/2, kColorBlack, true, drawPixel, &pd); pd.fillType = borderFillType; pd.thickness = borderThickness; if (borderThickness > 0 && borderFillType <= patterns.size()) - drawRoundRect(r, arc/2, kColorBlack, false, drawPixel, &pd); + Graphics::drawRoundRect(r, arc/2, kColorBlack, false, drawPixel, &pd); } void Design::drawPolygon(Graphics::Surface *surface, Common::ReadStream &in, @@ -326,7 +326,7 @@ void Design::drawPolygon(Graphics::Surface *surface, Common::ReadStream &in, plotData pd(surface, &patterns, fillType, 1); if (fillType <= patterns.size()) { - drawPolygonScan(xpoints, ypoints, npoints, bbox, kColorBlack, drawPixel, &pd); + Graphics::drawPolygonScan(xpoints, ypoints, npoints, bbox, kColorBlack, drawPixel, &pd); } pd.fillType = borderFillType; @@ -349,13 +349,13 @@ void Design::drawOval(Graphics::Surface *surface, Common::ReadStream &in, plotData pd(surface, &patterns, fillType, 1); if (fillType <= patterns.size()) - drawEllipse(x1, y1, x2-1, y2-1, true, drawPixel, &pd); + Graphics::drawEllipse(x1, y1, x2-1, y2-1, kColorBlack, true, drawPixel, &pd); pd.fillType = borderFillType; pd.thickness = borderThickness; if (borderThickness > 0 && borderFillType <= patterns.size()) - drawEllipse(x1, y1, x2-1, y2-1, false, drawPixel, &pd); + Graphics::drawEllipse(x1, y1, x2-1, y2-1, kColorBlack, false, drawPixel, &pd); } void Design::drawBitmap(Graphics::Surface *surface, Common::ReadStream &in) { @@ -460,383 +460,25 @@ void Design::drawFilledRect(Graphics::Surface *surface, Common::Rect &rect, int plotData pd(surface, &patterns, fillType, 1); for (int y = rect.top; y <= rect.bottom; y++) - drawHLine(rect.left, rect.right, y, color, drawPixel, &pd); -} - -void Design::drawFilledRect(Common::Rect &rect, int color, void (*plotProc)(int, int, int, void *), void *data) { - for (int y = rect.top; y <= rect.bottom; y++) - drawHLine(rect.left, rect.right, y, color, plotProc, data); + Graphics::drawHLine(rect.left, rect.right, y, color, drawPixel, &pd); } void Design::drawFilledRoundRect(Graphics::Surface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType) { plotData pd(surface, &patterns, fillType, 1); - drawRoundRect(rect, arc, color, true, drawPixel, &pd); -} - -// http://members.chello.at/easyfilter/bresenham.html -void Design::drawRoundRect(Common::Rect &rect, int arc, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data) { - if (rect.height() < rect.width()) { - int x = -arc, y = 0, err = 2-2*arc; /* II. Quadrant */ - int dy = rect.height() - arc * 2; - int r = arc; - int stop = 0; - int lastx, lasty; - if (dy < 0) - stop = -dy / 2; - - do { - if (filled) { - drawHLine(rect.left+x+r, rect.right-x-r, rect.top-y+r-stop, color, plotProc, data); - drawHLine(rect.left+x+r, rect.right-x-r, rect.bottom+y-r+stop, color, plotProc, data); - } else { - (*plotProc)(rect.left+x+r, rect.top-y+r-stop, color, data); - (*plotProc)(rect.right-x-r, rect.top-y+r-stop, color, data); - (*plotProc)(rect.left+x+r, rect.bottom+y-r+stop, color, data); - (*plotProc)(rect.right-x-r, rect.bottom+y-r+stop, color, data); - - lastx = x; - lasty = y; - } - arc = err; - if (arc <= y) err += ++y*2+1; /* e_xy+e_y < 0 */ - if (arc > x || err > y) err += ++x*2+1; /* e_xy+e_x > 0 or no 2nd y-step */ - if (stop && y > stop) - break; - } while (x < 0); - - if (!filled) { - x = lastx; - y = lasty; - - drawHLine(rect.left+x+r, rect.right-x-r, rect.top-y+r-stop, color, plotProc, data); - drawHLine(rect.left+x+r, rect.right-x-r, rect.bottom+y-r+stop, color, plotProc, data); - } - - for (int i = 0; i < dy; i++) { - if (filled) { - drawHLine(rect.left, rect.right, rect.top + r + i, color, plotProc, data); - } else { - (*plotProc)(rect.left, rect.top + r + i, color, data); - (*plotProc)(rect.right, rect.top + r + i, color, data); - } - } - } else { - int y = -arc, x = 0, err = 2-2*arc; /* II. Quadrant */ - int dx = rect.width() - arc * 2; - int r = arc; - int stop = 0; - int lastx, lasty; - if (dx < 0) - stop = -dx / 2; - - do { - if (filled) { - drawVLine(rect.left-x+r-stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); - drawVLine(rect.right+x-r+stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); - } else { - (*plotProc)(rect.left-x+r-stop, rect.top+y+r, color, data); - (*plotProc)(rect.left-x+r-stop, rect.bottom-y-r, color, data); - (*plotProc)(rect.right+x-r+stop, rect.top+y+r, color, data); - (*plotProc)(rect.right+x-r+stop, rect.bottom-y-r, color, data); - - lastx = x; - lasty = y; - } - - arc = err; - if (arc <= x) err += ++x*2+1; /* e_xy+e_y < 0 */ - if (arc > y || err > x) err += ++y*2+1; /* e_xy+e_x > 0 or no 2nd y-step */ - if (stop && x > stop) - break; - } while (y < 0); - - if (!filled) { - x = lastx; - y = lasty; - drawVLine(rect.left-x+r-stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); - drawVLine(rect.right+x-r+stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); - } - - for (int i = 0; i < dx; i++) { - if (filled) { - drawVLine(rect.left + r + i, rect.top, rect.bottom, color, plotProc, data); - } else { - (*plotProc)(rect.left + r + i, rect.top, color, data); - (*plotProc)(rect.left + r + i, rect.bottom, color, data); - } - } - } -} - -// Based on public-domain code by Darel Rex Finley, 2007 -// http://alienryderflex.com/polygon_fill/ -void Design::drawPolygonScan(int *polyX, int *polyY, int npoints, Common::Rect &bbox, int color, - void (*plotProc)(int, int, int, void *), void *data) { - int *nodeX = (int *)calloc(npoints, sizeof(int)); - int i, j; - - // Loop through the rows of the image. - for (int pixelY = bbox.top; pixelY < bbox.bottom; pixelY++) { - // Build a list of nodes. - int nodes = 0; - j = npoints - 1; - - for (i = 0; i < npoints; i++) { - if ((polyY[i] < pixelY && polyY[j] >= pixelY) || (polyY[j] < pixelY && polyY[i] >= pixelY)) { - nodeX[nodes++] = (int)(polyX[i] + (double)(pixelY - polyY[i]) / (double)(polyY[j]-polyY[i]) * - (double)(polyX[j] - polyX[i]) + 0.5); - } - j = i; - } - - // Sort the nodes, via a simple “Bubble” sort. - i = 0; - while (i < nodes - 1) { - if (nodeX[i] > nodeX[i + 1]) { - SWAP(nodeX[i], nodeX[i + 1]); - if (i) - i--; - } else { - i++; - } - } - - // Fill the pixels between node pairs. - for (i = 0; i < nodes; i += 2) { - if (nodeX[i ] >= bbox.right) - break; - if (nodeX[i + 1] > bbox.left) { - nodeX[i] = MAX<int16>(nodeX[i], bbox.left); - nodeX[i + 1] = MIN<int16>(nodeX[i + 1], bbox.right); - - drawHLine(nodeX[i], nodeX[i + 1], pixelY, color, plotProc, data); - } - } - } - - free(nodeX); -} - -// http://members.chello.at/easyfilter/bresenham.html -void Design::drawEllipse(int x0, int y0, int x1, int y1, bool filled, void (*plotProc)(int, int, int, void *), void *data) { - int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; /* values of diameter */ - long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */ - long err = dx+dy+b1*a*a, e2; /* error of 1.step */ - - if (x0 > x1) { x0 = x1; x1 += a; } /* if called with swapped points */ - if (y0 > y1) y0 = y1; /* .. exchange them */ - y0 += (b+1)/2; y1 = y0-b1; /* starting pixel */ - a *= 8*a; b1 = 8*b*b; - - do { - if (filled) { - drawHLine(x0, x1, y0, kColorBlack, plotProc, data); - drawHLine(x0, x1, y1, kColorBlack, plotProc, data); - } else { - (*plotProc)(x1, y0, kColorBlack, data); /* I. Quadrant */ - (*plotProc)(x0, y0, kColorBlack, data); /* II. Quadrant */ - (*plotProc)(x0, y1, kColorBlack, data); /* III. Quadrant */ - (*plotProc)(x1, y1, kColorBlack, data); /* IV. Quadrant */ - } - e2 = 2*err; - if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */ - if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } /* x step */ - } while (x0 <= x1); - - while (y0-y1 < b) { /* too early stop of flat ellipses a=1 */ - if (filled) { - drawHLine(x0-1, x0-1, y0, kColorBlack, plotProc, data); /* -> finish tip of ellipse */ - drawHLine(x1+1, x1+1, y0, kColorBlack, plotProc, data); - drawHLine(x0-1, x0-1, y1, kColorBlack, plotProc, data); - drawHLine(x1+1, x1+1, y1, kColorBlack, plotProc, data); - } else { - (*plotProc)(x0-1, y0, kColorBlack, data); /* -> finish tip of ellipse */ - (*plotProc)(x1+1, y0, kColorBlack, data); - (*plotProc)(x0-1, y1, kColorBlack, data); - (*plotProc)(x1+1, y1, kColorBlack, data); - } - y0++; - y1--; - } + Graphics::drawRoundRect(rect, arc, color, true, drawPixel, &pd); } void Design::drawHLine(Graphics::Surface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType) { plotData pd(surface, &patterns, fillType, thickness); - drawHLine(x1, x2, y, color, drawPixel, &pd); -} - -void Design::drawHLine(int x1, int x2, int y, int color, void (*plotProc)(int, int, int, void *), void *data) { - if (x1 > x2) - SWAP(x1, x2); - - for (int x = x1; x <= x2; x++) - (*plotProc)(x, y, color, data); + Graphics::drawHLine(x1, x2, y, color, drawPixel, &pd); } void Design::drawVLine(Graphics::Surface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType) { plotData pd(surface, &patterns, fillType, thickness); - drawVLine(x, y1, y2, color, drawPixel, &pd); -} - -void Design::drawVLine(int x, int y1, int y2, int color, void (*plotProc)(int, int, int, void *), void *data) { - if (y1 > y2) - SWAP(y1, y2); - - for (int y = y1; y <= y2; y++) - (*plotProc)(x, y, color, data); -} - -/* Bresenham as presented in Foley & Van Dam */ -/* Code is based on GD lib http://libgd.github.io/ */ -void Design::drawThickLine (int x1, int y1, int x2, int y2, int thick, int color, - void (*plotProc)(int, int, int, void *), void *data) { - int incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; - int wid; - int w, wstart; - - int dx = abs(x2 - x1); - int dy = abs(y2 - y1); - - if (dx == 0) { - if (y1 > y2) - SWAP(y1, y2); - Common::Rect r(x1, y1, x1 + thick - 1, y2); - drawFilledRect(r, color, plotProc, data); - return; - } else if (dy == 0) { - if (x1 > x2) - SWAP(x1, x2); - Common::Rect r(x1, y1, x2, y1 + thick - 1); - drawFilledRect(r, color, plotProc, data); - return; - } - - if (dy <= dx) { - /* More-or-less horizontal. use wid for vertical stroke */ - /* Doug Claar: watch out for NaN in atan2 (2.0.5) */ - - /* 2.0.12: Michael Schwartz: divide rather than multiply; - TBB: but watch out for /0! */ - double ac = cos(atan2 (dy, dx)); - if (ac != 0) { - wid = thick / ac; - } else { - wid = 1; - } - if (wid == 0) { - wid = 1; - } - d = 2 * dy - dx; - incr1 = 2 * dy; - incr2 = 2 * (dy - dx); - if (x1 > x2) { - x = x2; - y = y2; - ydirflag = (-1); - xend = x1; - } else { - x = x1; - y = y1; - ydirflag = 1; - xend = x2; - } - - /* Set up line thickness */ - wstart = y - wid / 2; - for (w = wstart; w < wstart + wid; w++) - (*plotProc)(x, y, color, data); - - if (((y2 - y1) * ydirflag) > 0) { - while (x < xend) { - x++; - if (d < 0) { - d += incr1; - } else { - y++; - d += incr2; - } - wstart = y - wid / 2; - for (w = wstart; w < wstart + wid; w++) - (*plotProc)(x, w, color, data); - } - } else { - while (x < xend) { - x++; - if (d < 0) { - d += incr1; - } else { - y--; - d += incr2; - } - wstart = y - wid / 2; - for (w = wstart; w < wstart + wid; w++) - (*plotProc)(x, w, color, data); - } - } - } else { - /* More-or-less vertical. use wid for horizontal stroke */ - /* 2.0.12: Michael Schwartz: divide rather than multiply; - TBB: but watch out for /0! */ - double as = sin(atan2(dy, dx)); - if (as != 0) { - wid = thick / as; - } else { - wid = 1; - } - if (wid == 0) - wid = 1; - - d = 2 * dx - dy; - incr1 = 2 * dx; - incr2 = 2 * (dx - dy); - if (y1 > y2) { - y = y2; - x = x2; - yend = y1; - xdirflag = (-1); - } else { - y = y1; - x = x1; - yend = y2; - xdirflag = 1; - } - - /* Set up line thickness */ - wstart = x - wid / 2; - for (w = wstart; w < wstart + wid; w++) - (*plotProc)(w, y, color, data); - - if (((x2 - x1) * xdirflag) > 0) { - while (y < yend) { - y++; - if (d < 0) { - d += incr1; - } else { - x++; - d += incr2; - } - wstart = x - wid / 2; - for (w = wstart; w < wstart + wid; w++) - (*plotProc)(w, y, color, data); - } - } else { - while (y < yend) { - y++; - if (d < 0) { - d += incr1; - } else { - x--; - d += incr2; - } - wstart = x - wid / 2; - for (w = wstart; w < wstart + wid; w++) - (*plotProc)(w, y, color, data); - } - } - } + Graphics::drawVLine(x, y1, y2, color, drawPixel, &pd); } FloodFill::FloodFill(Graphics::Surface *surface, byte color1, byte color2) { diff --git a/engines/wage/design.h b/engines/wage/design.h index d98d30ce93..43f9ce1ce5 100644 --- a/engines/wage/design.h +++ b/engines/wage/design.h @@ -93,16 +93,6 @@ private: void drawOval(Graphics::Surface *surface, Common::ReadStream &in, Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType); void drawBitmap(Graphics::Surface *surface, Common::ReadStream &in); - - void drawFilledRect(Common::Rect &rect, int color, void (*plotProc)(int, int, int, void *), void *data); - static void drawRoundRect(Common::Rect &rect, int arc, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data); - void drawPolygonScan(int *polyX, int *polyY, int npoints, Common::Rect &bbox, int color, - void (*plotProc)(int, int, int, void *), void *data); - void drawEllipse(int x0, int y0, int x1, int y1, bool filled, void (*plotProc)(int, int, int, void *), void *data); - static void drawHLine(int x1, int x2, int y, int color, void (*plotProc)(int, int, int, void *), void *data); - static void drawVLine(int x, int y1, int y2, int color, void (*plotProc)(int, int, int, void *), void *data); - void drawThickLine (int x1, int y1, int x2, int y2, int thick, int color, - void (*plotProc)(int, int, int, void *), void *data); }; class FloodFill { diff --git a/graphics/primitives.cpp b/graphics/primitives.cpp index 564bdb9673..0e970655d4 100644 --- a/graphics/primitives.cpp +++ b/graphics/primitives.cpp @@ -21,6 +21,7 @@ */ #include "common/util.h" +#include "graphics/primitives.h" namespace Graphics { @@ -62,6 +63,22 @@ void drawLine(int x0, int y0, int x1, int y1, int color, void (*plotProc)(int, i } } +void drawHLine(int x1, int x2, int y, int color, void (*plotProc)(int, int, int, void *), void *data) { + if (x1 > x2) + SWAP(x1, x2); + + for (int x = x1; x <= x2; x++) + (*plotProc)(x, y, color, data); +} + +void drawVLine(int x, int y1, int y2, int color, void (*plotProc)(int, int, int, void *), void *data) { + if (y1 > y2) + SWAP(y1, y2); + + for (int y = y1; y <= y2; y++) + (*plotProc)(x, y, color, data); +} + void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color, void (*plotProc)(int, int, int, void *), void *data) { assert(penX > 0 && penY > 0); @@ -79,4 +96,344 @@ void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color drawLine(x0 + x, y0 + y, x1 + x, y1 + y, color, plotProc, data); } +/* Bresenham as presented in Foley & Van Dam */ +/* Code is based on GD lib http://libgd.github.io/ */ +void drawThickLine2(int x1, int y1, int x2, int y2, int thick, int color, void (*plotProc)(int, int, int, void *), void *data) { + int incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; + int wid; + int w, wstart; + + int dx = abs(x2 - x1); + int dy = abs(y2 - y1); + + if (dx == 0) { + if (y1 > y2) + SWAP(y1, y2); + Common::Rect r(x1, y1, x1 + thick - 1, y2); + drawFilledRect(r, color, plotProc, data); + return; + } else if (dy == 0) { + if (x1 > x2) + SWAP(x1, x2); + Common::Rect r(x1, y1, x2, y1 + thick - 1); + drawFilledRect(r, color, plotProc, data); + return; + } + + if (dy <= dx) { + /* More-or-less horizontal. use wid for vertical stroke */ + /* Doug Claar: watch out for NaN in atan2 (2.0.5) */ + + /* 2.0.12: Michael Schwartz: divide rather than multiply; + TBB: but watch out for /0! */ + double ac = cos(atan2 (dy, dx)); + if (ac != 0) { + wid = thick / ac; + } else { + wid = 1; + } + if (wid == 0) { + wid = 1; + } + d = 2 * dy - dx; + incr1 = 2 * dy; + incr2 = 2 * (dy - dx); + if (x1 > x2) { + x = x2; + y = y2; + ydirflag = (-1); + xend = x1; + } else { + x = x1; + y = y1; + ydirflag = 1; + xend = x2; + } + + /* Set up line thickness */ + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(x, y, color, data); + + if (((y2 - y1) * ydirflag) > 0) { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y++; + d += incr2; + } + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(x, w, color, data); + } + } else { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y--; + d += incr2; + } + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(x, w, color, data); + } + } + } else { + /* More-or-less vertical. use wid for horizontal stroke */ + /* 2.0.12: Michael Schwartz: divide rather than multiply; + TBB: but watch out for /0! */ + double as = sin(atan2(dy, dx)); + if (as != 0) { + wid = thick / as; + } else { + wid = 1; + } + if (wid == 0) + wid = 1; + + d = 2 * dx - dy; + incr1 = 2 * dx; + incr2 = 2 * (dx - dy); + if (y1 > y2) { + y = y2; + x = x2; + yend = y1; + xdirflag = (-1); + } else { + y = y1; + x = x1; + yend = y2; + xdirflag = 1; + } + + /* Set up line thickness */ + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(w, y, color, data); + + if (((x2 - x1) * xdirflag) > 0) { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x++; + d += incr2; + } + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(w, y, color, data); + } + } else { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x--; + d += incr2; + } + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) + (*plotProc)(w, y, color, data); + } + } + } +} + +void drawFilledRect(Common::Rect &rect, int color, void (*plotProc)(int, int, int, void *), void *data) { + for (int y = rect.top; y <= rect.bottom; y++) + drawHLine(rect.left, rect.right, y, color, plotProc, data); +} + +// http://members.chello.at/easyfilter/bresenham.html +void drawRoundRect(Common::Rect &rect, int arc, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data) { + if (rect.height() < rect.width()) { + int x = -arc, y = 0, err = 2-2*arc; /* II. Quadrant */ + int dy = rect.height() - arc * 2; + int r = arc; + int stop = 0; + int lastx, lasty; + if (dy < 0) + stop = -dy / 2; + + do { + if (filled) { + drawHLine(rect.left+x+r, rect.right-x-r, rect.top-y+r-stop, color, plotProc, data); + drawHLine(rect.left+x+r, rect.right-x-r, rect.bottom+y-r+stop, color, plotProc, data); + } else { + (*plotProc)(rect.left+x+r, rect.top-y+r-stop, color, data); + (*plotProc)(rect.right-x-r, rect.top-y+r-stop, color, data); + (*plotProc)(rect.left+x+r, rect.bottom+y-r+stop, color, data); + (*plotProc)(rect.right-x-r, rect.bottom+y-r+stop, color, data); + + lastx = x; + lasty = y; + } + arc = err; + if (arc <= y) err += ++y*2+1; /* e_xy+e_y < 0 */ + if (arc > x || err > y) err += ++x*2+1; /* e_xy+e_x > 0 or no 2nd y-step */ + if (stop && y > stop) + break; + } while (x < 0); + + if (!filled) { + x = lastx; + y = lasty; + + drawHLine(rect.left+x+r, rect.right-x-r, rect.top-y+r-stop, color, plotProc, data); + drawHLine(rect.left+x+r, rect.right-x-r, rect.bottom+y-r+stop, color, plotProc, data); + } + + for (int i = 0; i < dy; i++) { + if (filled) { + drawHLine(rect.left, rect.right, rect.top + r + i, color, plotProc, data); + } else { + (*plotProc)(rect.left, rect.top + r + i, color, data); + (*plotProc)(rect.right, rect.top + r + i, color, data); + } + } + } else { + int y = -arc, x = 0, err = 2-2*arc; /* II. Quadrant */ + int dx = rect.width() - arc * 2; + int r = arc; + int stop = 0; + int lastx, lasty; + if (dx < 0) + stop = -dx / 2; + + do { + if (filled) { + drawVLine(rect.left-x+r-stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); + drawVLine(rect.right+x-r+stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); + } else { + (*plotProc)(rect.left-x+r-stop, rect.top+y+r, color, data); + (*plotProc)(rect.left-x+r-stop, rect.bottom-y-r, color, data); + (*plotProc)(rect.right+x-r+stop, rect.top+y+r, color, data); + (*plotProc)(rect.right+x-r+stop, rect.bottom-y-r, color, data); + + lastx = x; + lasty = y; + } + + arc = err; + if (arc <= x) err += ++x*2+1; /* e_xy+e_y < 0 */ + if (arc > y || err > x) err += ++y*2+1; /* e_xy+e_x > 0 or no 2nd y-step */ + if (stop && x > stop) + break; + } while (y < 0); + + if (!filled) { + x = lastx; + y = lasty; + drawVLine(rect.left-x+r-stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); + drawVLine(rect.right+x-r+stop, rect.top+y+r, rect.bottom-y-r, color, plotProc, data); + } + + for (int i = 0; i < dx; i++) { + if (filled) { + drawVLine(rect.left + r + i, rect.top, rect.bottom, color, plotProc, data); + } else { + (*plotProc)(rect.left + r + i, rect.top, color, data); + (*plotProc)(rect.left + r + i, rect.bottom, color, data); + } + } + } +} + +// Based on public-domain code by Darel Rex Finley, 2007 +// http://alienryderflex.com/polygon_fill/ +void drawPolygonScan(int *polyX, int *polyY, int npoints, Common::Rect &bbox, int color, void (*plotProc)(int, int, int, void *), void *data) { + int *nodeX = (int *)calloc(npoints, sizeof(int)); + int i, j; + + // Loop through the rows of the image. + for (int pixelY = bbox.top; pixelY < bbox.bottom; pixelY++) { + // Build a list of nodes. + int nodes = 0; + j = npoints - 1; + + for (i = 0; i < npoints; i++) { + if ((polyY[i] < pixelY && polyY[j] >= pixelY) || (polyY[j] < pixelY && polyY[i] >= pixelY)) { + nodeX[nodes++] = (int)(polyX[i] + (double)(pixelY - polyY[i]) / (double)(polyY[j]-polyY[i]) * + (double)(polyX[j] - polyX[i]) + 0.5); + } + j = i; + } + + // Sort the nodes, via a simple “Bubble” sort. + i = 0; + while (i < nodes - 1) { + if (nodeX[i] > nodeX[i + 1]) { + SWAP(nodeX[i], nodeX[i + 1]); + if (i) + i--; + } else { + i++; + } + } + + // Fill the pixels between node pairs. + for (i = 0; i < nodes; i += 2) { + if (nodeX[i ] >= bbox.right) + break; + if (nodeX[i + 1] > bbox.left) { + nodeX[i] = MAX<int16>(nodeX[i], bbox.left); + nodeX[i + 1] = MIN<int16>(nodeX[i + 1], bbox.right); + + drawHLine(nodeX[i], nodeX[i + 1], pixelY, color, plotProc, data); + } + } + } + + free(nodeX); +} + +// http://members.chello.at/easyfilter/bresenham.html +void drawEllipse(int x0, int y0, int x1, int y1, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data) { + int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; /* values of diameter */ + long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */ + long err = dx+dy+b1*a*a, e2; /* error of 1.step */ + + if (x0 > x1) { x0 = x1; x1 += a; } /* if called with swapped points */ + if (y0 > y1) y0 = y1; /* .. exchange them */ + y0 += (b+1)/2; y1 = y0-b1; /* starting pixel */ + a *= 8*a; b1 = 8*b*b; + + do { + if (filled) { + drawHLine(x0, x1, y0, color, plotProc, data); + drawHLine(x0, x1, y1, color, plotProc, data); + } else { + (*plotProc)(x1, y0, color, data); /* I. Quadrant */ + (*plotProc)(x0, y0, color, data); /* II. Quadrant */ + (*plotProc)(x0, y1, color, data); /* III. Quadrant */ + (*plotProc)(x1, y1, color, data); /* IV. Quadrant */ + } + e2 = 2*err; + if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */ + if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } /* x step */ + } while (x0 <= x1); + + while (y0-y1 < b) { /* too early stop of flat ellipses a=1 */ + if (filled) { + drawHLine(x0-1, x0-1, y0, color, plotProc, data); /* -> finish tip of ellipse */ + drawHLine(x1+1, x1+1, y0, color, plotProc, data); + drawHLine(x0-1, x0-1, y1, color, plotProc, data); + drawHLine(x1+1, x1+1, y1, color, plotProc, data); + } else { + (*plotProc)(x0-1, y0, color, data); /* -> finish tip of ellipse */ + (*plotProc)(x1+1, y0, color, data); + (*plotProc)(x0-1, y1, color, data); + (*plotProc)(x1+1, y1, color, data); + } + y0++; + y1--; + } +} + } // End of namespace Graphics diff --git a/graphics/primitives.h b/graphics/primitives.h index a3e8ab1565..62dc10bfdf 100644 --- a/graphics/primitives.h +++ b/graphics/primitives.h @@ -23,10 +23,21 @@ #ifndef GRAPHICS_PRIMITIVES_H #define GRAPHICS_PRIMITIVES_H +#include "common/rect.h" + namespace Graphics { void drawLine(int x0, int y0, int x1, int y1, int color, void (*plotProc)(int, int, int, void *), void *data); +void drawHLine(int x1, int x2, int y, int color, void (*plotProc)(int, int, int, void *), void *data); +void drawVLine(int x, int y1, int y2, int color, void (*plotProc)(int, int, int, void *), void *data); void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color, void (*plotProc)(int, int, int, void *), void *data); +void drawThickLine2(int x1, int y1, int x2, int y2, int thick, int color, + void (*plotProc)(int, int, int, void *), void *data); +void drawFilledRect(Common::Rect &rect, int color, void (*plotProc)(int, int, int, void *), void *data); +void drawRoundRect(Common::Rect &rect, int arc, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data); +void drawPolygonScan(int *polyX, int *polyY, int npoints, Common::Rect &bbox, int color, + void (*plotProc)(int, int, int, void *), void *data); +void drawEllipse(int x0, int y0, int x1, int y1, int color, bool filled, void (*plotProc)(int, int, int, void *), void *data); } // End of namespace Graphics |