| #include "EdgeDemo.h" |
| #include "EdgeWalker_Test.h" |
| #include "ShapeOps.h" |
| #import "SkCanvas.h" |
| #import "SkPaint.h" |
| |
| extern void showPath(const SkPath& path, const char* str); |
| |
| static bool drawPaths(SkCanvas* canvas, const SkPath& path, bool useOld) |
| { |
| SkPath out; |
| #define SHOW_PATH 0 |
| #if SHOW_PATH |
| showPath(path, "original:"); |
| #endif |
| if (useOld) { |
| simplify(path, true, out); |
| } else { |
| simplifyx(path, out); |
| } |
| #if SHOW_PATH |
| showPath(out, "simplified:"); |
| #endif |
| SkPaint paint; |
| paint.setAntiAlias(true); |
| paint.setStyle(SkPaint::kStroke_Style); |
| // paint.setStrokeWidth(6); |
| // paint.setColor(0x1F003f7f); |
| // canvas->drawPath(path, paint); |
| paint.setColor(0xFF305F00); |
| paint.setStrokeWidth(1); |
| canvas->drawPath(out, paint); |
| return true; |
| } |
| |
| // Three circles bounce inside a rectangle. The circles describe three, four |
| // or five points which in turn describe a polygon. The polygon points |
| // bounce inside the circles. The circles rotate and scale over time. The |
| // polygons are combined into a single path, simplified, and stroked. |
| static bool drawCircles(SkCanvas* canvas, int step, bool useOld) |
| { |
| const int circles = 3; |
| int scales[circles]; |
| int angles[circles]; |
| int locs[circles * 2]; |
| int pts[circles * 2 * 4]; |
| int c, p; |
| for (c = 0; c < circles; ++c) { |
| scales[c] = abs(10 - (step + c * 4) % 21); |
| angles[c] = (step + c * 6) % 600; |
| locs[c * 2] = abs(130 - (step + c * 9) % 261); |
| locs[c * 2 + 1] = abs(170 - (step + c * 11) % 341); |
| for (p = 0; p < 4; ++p) { |
| pts[c * 8 + p * 2] = abs(90 - ((step + c * 121 + p * 13) % 190)); |
| pts[c * 8 + p * 2 + 1] = abs(110 - ((step + c * 223 + p * 17) % 230)); |
| } |
| } |
| SkPath path; |
| for (c = 0; c < circles; ++c) { |
| for (p = 0; p < 4; ++p) { |
| SkScalar x = pts[c * 8 + p * 2]; |
| SkScalar y = pts[c * 8 + p * 2 + 1]; |
| x *= 3 + scales[c] / 10.0f; |
| y *= 3 + scales[c] / 10.0f; |
| SkScalar angle = angles[c] * 3.1415f * 2 / 600; |
| SkScalar temp = (SkScalar) (x * cos(angle) - y * sin(angle)); |
| y = (SkScalar) (x * sin(angle) + y * cos(angle)); |
| x = temp; |
| x += locs[c * 2] * 200 / 130.0f; |
| y += locs[c * 2 + 1] * 200 / 170.0f; |
| x += 50; |
| // y += 200; |
| if (p == 0) { |
| path.moveTo(x, y); |
| } else { |
| path.lineTo(x, y); |
| } |
| } |
| path.close(); |
| } |
| return drawPaths(canvas, path, useOld); |
| } |
| |
| static void createStar(SkPath& path, SkScalar innerRadius, SkScalar outerRadius, |
| SkScalar startAngle, int points, SkPoint center) { |
| SkScalar angle = startAngle; |
| for (int index = 0; index < points * 2; ++index) { |
| SkScalar radius = index & 1 ? outerRadius : innerRadius; |
| SkScalar x = (SkScalar) (radius * cos(angle)); |
| SkScalar y = (SkScalar) (radius * sin(angle)); |
| x += center.fX; |
| y += center.fY; |
| if (index == 0) { |
| path.moveTo(x, y); |
| } else { |
| path.lineTo(x, y); |
| } |
| angle += 3.1415f / points; |
| } |
| path.close(); |
| } |
| |
| static bool drawStars(SkCanvas* canvas, int step, bool useOld) |
| { |
| SkPath path; |
| const int stars = 25; |
| int pts[stars]; |
| // static bool initialize = true; |
| int s; |
| for (s = 0; s < stars; ++s) { |
| pts[s] = 4 + (s % 7); |
| } |
| SkPoint locs[stars]; |
| SkScalar angles[stars]; |
| SkScalar innerRadius[stars]; |
| SkScalar outerRadius[stars]; |
| const int width = 640; |
| const int height = 480; |
| const int margin = 30; |
| const int minRadius = 120; |
| const int maxInner = 800; |
| const int maxOuter = 1153; |
| for (s = 0; s < stars; ++s) { |
| int starW = (int) (width - margin * 2 + (SkScalar) s * (stars - s) / stars); |
| locs[s].fX = (int) (step * (1.3f * (s + 1) / stars) + s * 121) % (starW * 2); |
| if (locs[s].fX > starW) { |
| locs[s].fX = starW * 2 - locs[s].fX; |
| } |
| locs[s].fX += margin; |
| int starH = (int) (height - margin * 2 + (SkScalar) s * s / stars); |
| locs[s].fY = (int) (step * (1.7f * (s + 1) / stars) + s * 183) % (starH * 2); |
| if (locs[s].fY > starH) { |
| locs[s].fY = starH * 2 - locs[s].fY; |
| } |
| locs[s].fY += margin; |
| angles[s] = ((step + s * 47) % (360 * 4)) * 3.1415f / 180 / 4; |
| innerRadius[s] = (step + s * 30) % (maxInner * 2); |
| if (innerRadius[s] > maxInner) { |
| innerRadius[s] = (maxInner * 2) - innerRadius[s]; |
| } |
| innerRadius[s] = innerRadius[s] / 4 + minRadius; |
| outerRadius[s] = (step + s * 70) % (maxOuter * 2); |
| if (outerRadius[s] > maxOuter) { |
| outerRadius[s] = (maxOuter * 2) - outerRadius[s]; |
| } |
| outerRadius[s] = outerRadius[s] / 4 + minRadius; |
| createStar(path, innerRadius[s] / 4.0f, outerRadius[s] / 4.0f, |
| angles[s], pts[s], locs[s]); |
| } |
| return drawPaths(canvas, path, useOld); |
| } |
| |
| static void tryRoncoOnce(const SkPath& path, const SkRect& target, bool show) { |
| // capture everything in a desired rectangle |
| SkPath tiny; |
| bool closed = true; |
| SkPath::Iter iter(path, false); |
| SkPoint pts[4]; |
| SkPath::Verb verb; |
| int count = 0; |
| SkPoint lastPt; |
| while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
| switch (verb) { |
| case SkPath::kMove_Verb: |
| count = 0; |
| break; |
| case SkPath::kLine_Verb: |
| count = 1; |
| break; |
| case SkPath::kQuad_Verb: |
| count = 2; |
| break; |
| case SkPath::kCubic_Verb: |
| count = 3; |
| break; |
| case SkPath::kClose_Verb: |
| if (!closed) { |
| tiny.close(); |
| closed = true; |
| } |
| count = 0; |
| break; |
| default: |
| SkDEBUGFAIL("bad verb"); |
| } |
| if (!count) { |
| continue; |
| } |
| SkRect bounds; |
| bounds.set(pts[0].fX, pts[0].fY, pts[0].fX, pts[0].fY); |
| for (int i = 1; i <= count; ++i) { |
| bounds.growToInclude(pts[i].fX + 0.1f, pts[i].fY + 0.1f); |
| } |
| if (!SkRect::Intersects(target, bounds)) { |
| continue; |
| } |
| if (closed) { |
| tiny.moveTo(pts[0].fX, pts[0].fY); |
| closed = false; |
| } else if (pts[0] != lastPt) { |
| tiny.lineTo(pts[0].fX, pts[0].fY); |
| } |
| switch (verb) { |
| case SkPath::kLine_Verb: |
| tiny.lineTo(pts[1].fX, pts[1].fY); |
| lastPt = pts[1]; |
| break; |
| case SkPath::kQuad_Verb: |
| tiny.quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); |
| lastPt = pts[2]; |
| break; |
| case SkPath::kCubic_Verb: |
| tiny.cubicTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3].fY); |
| lastPt = pts[3]; |
| break; |
| default: |
| SkDEBUGFAIL("bad verb"); |
| } |
| } |
| if (!closed) { |
| tiny.close(); |
| } |
| if (show) { |
| showPath(tiny, NULL); |
| SkDebugf("simplified:\n"); |
| } |
| testSimplifyx(tiny); |
| } |
| |
| static void tryRonco(const SkPath& path) { |
| const SkRect& overall = path.getBounds(); |
| const int divs = 64; |
| SkScalar cellWidth = overall.width() / divs * 2; |
| SkScalar cellHeight = overall.height() / divs * 2; |
| SkRect target; |
| if (true) { |
| int xDiv = 28; |
| int yDiv = 17; |
| target.setXYWH(overall.fLeft + (overall.width() - cellWidth) * xDiv / divs, |
| overall.fTop + (overall.height() - cellHeight) * yDiv / divs, |
| cellWidth, cellHeight); |
| tryRoncoOnce(path, target, true); |
| } else { |
| for (int xDiv = 0; xDiv < divs; ++xDiv) { |
| for (int yDiv = 0; yDiv < divs; ++yDiv) { |
| target.setXYWH(overall.fLeft + (overall.width() - cellWidth) * xDiv / divs, |
| overall.fTop + (overall.height() - cellHeight) * yDiv / divs, |
| cellWidth, cellHeight); |
| tryRoncoOnce(path, target, true); |
| } |
| } |
| } |
| } |
| |
| static bool drawLetters(SkCanvas* canvas, int step, bool useOld) |
| { |
| SkPath path; |
| const int width = 640; |
| const int height = 480; |
| const char testStr[] = "Merge"; |
| const int testStrLen = sizeof(testStr) - 1; |
| SkPoint textPos[testStrLen]; |
| SkScalar widths[testStrLen]; |
| SkPaint paint; |
| paint.setTextSize(40); |
| paint.setAntiAlias(true); |
| paint.getTextWidths(testStr, testStrLen, widths, NULL); |
| SkScalar running = 0; |
| for (int x = 0; x < testStrLen; ++x) { |
| SkScalar width = widths[x]; |
| widths[x] = running; |
| running += width; |
| } |
| SkScalar bias = (width - widths[testStrLen - 1]) / 2; |
| for (int x = 0; x < testStrLen; ++x) { |
| textPos[x].fX = bias + widths[x]; |
| textPos[x].fY = height / 2; |
| } |
| paint.setTextSize(40 + step / 100.0f); |
| #if 0 |
| for (int mask = 0; mask < 1 << testStrLen; ++mask) { |
| char maskStr[testStrLen]; |
| mask = 15; |
| for (int letter = 0; letter < testStrLen; ++letter) { |
| maskStr[letter] = mask & (1 << letter) ? testStr[letter] : ' '; |
| } |
| paint.getPosTextPath(maskStr, testStrLen, textPos, &path); |
| // showPath(path, NULL); |
| // SkDebugf("%d simplified:\n", mask); |
| tryRonco(path); |
| testSimplifyx(path); |
| } |
| #endif |
| paint.getPosTextPath(testStr, testStrLen, textPos, &path); |
| #if 0 |
| tryRonco(path); |
| #endif |
| #if 0 |
| showPath(path, NULL); |
| SkDebugf("simplified:\n"); |
| #endif |
| return drawPaths(canvas, path, false); |
| } |
| |
| static bool (*drawDemos[])(SkCanvas* , int , bool ) = { |
| drawStars, |
| drawCircles, |
| drawLetters, |
| }; |
| |
| static size_t drawDemosCount = sizeof(drawDemos) / sizeof(drawDemos[0]); |
| |
| static bool (*firstTest)(SkCanvas* , int , bool) = drawLetters; |
| |
| |
| bool DrawEdgeDemo(SkCanvas* canvas, int step, bool useOld) { |
| size_t index = 0; |
| if (firstTest) { |
| while (index < drawDemosCount && drawDemos[index] != firstTest) { |
| ++index; |
| } |
| } |
| return (*drawDemos[index])(canvas, step, useOld); |
| } |