1#include "EdgeDemo.h"
2#include "EdgeWalker_Test.h"
3#include "ShapeOps.h"
4#import "SkCanvas.h"
5#import "SkPaint.h"
6
7extern void showPath(const SkPath& path, const char* str);
8
9static bool drawPaths(SkCanvas* canvas, const SkPath& path, bool useOld)
10{
11    SkPath out;
12#define SHOW_PATH 0
13#if SHOW_PATH
14    showPath(path, "original:");
15#endif
16    if (useOld) {
17        simplify(path, true, out);
18    } else {
19        simplifyx(path, out);
20    }
21#if SHOW_PATH
22    showPath(out, "simplified:");
23#endif
24    SkPaint paint;
25    paint.setAntiAlias(true);
26    paint.setStyle(SkPaint::kStroke_Style);
27//   paint.setStrokeWidth(6);
28 //  paint.setColor(0x1F003f7f);
29 //  canvas->drawPath(path, paint);
30    paint.setColor(0xFF305F00);
31    paint.setStrokeWidth(1);
32    canvas->drawPath(out, paint);
33    return true;
34}
35
36// Three circles bounce inside a rectangle. The circles describe three, four
37// or five points which in turn describe a polygon. The polygon points
38// bounce inside the circles. The circles rotate and scale over time. The
39// polygons are combined into a single path, simplified, and stroked.
40static bool drawCircles(SkCanvas* canvas, int step, bool useOld)
41{
42    const int circles = 3;
43    int scales[circles];
44    int angles[circles];
45    int locs[circles * 2];
46    int pts[circles * 2 * 4];
47    int c, p;
48    for (c = 0; c < circles; ++c) {
49        scales[c] = abs(10 - (step + c * 4) % 21);
50        angles[c] = (step + c * 6) % 600;
51        locs[c * 2] = abs(130 - (step + c * 9) % 261);
52        locs[c * 2 + 1] = abs(170 - (step + c * 11) % 341);
53        for (p = 0; p < 4; ++p) {
54            pts[c * 8 + p * 2] = abs(90 - ((step + c * 121 + p * 13) % 190));
55            pts[c * 8 + p * 2 + 1] = abs(110 - ((step + c * 223 + p * 17) % 230));
56        }
57    }
58    SkPath path;
59    for (c = 0; c < circles; ++c) {
60        for (p = 0; p < 4; ++p) {
61            SkScalar x = pts[c * 8 + p * 2];
62            SkScalar y = pts[c * 8 + p * 2 + 1];
63            x *= 3 + scales[c] / 10.0f;
64            y *= 3 + scales[c] / 10.0f;
65            SkScalar angle = angles[c] * 3.1415f * 2 / 600;
66            SkScalar temp = (SkScalar) (x * cos(angle) - y * sin(angle));
67            y = (SkScalar) (x * sin(angle) + y * cos(angle));
68            x = temp;
69            x += locs[c * 2] * 200 / 130.0f;
70            y += locs[c * 2 + 1] * 200 / 170.0f;
71            x += 50;
72    //        y += 200;
73            if (p == 0) {
74                path.moveTo(x, y);
75            } else {
76                path.lineTo(x, y);
77            }
78        }
79        path.close();
80    }
81    return drawPaths(canvas, path, useOld);
82}
83
84static void createStar(SkPath& path, SkScalar innerRadius, SkScalar outerRadius,
85        SkScalar startAngle, int points, SkPoint center) {
86    SkScalar angle = startAngle;
87    for (int index = 0; index < points * 2; ++index) {
88        SkScalar radius = index & 1 ? outerRadius : innerRadius;
89        SkScalar x = (SkScalar) (radius * cos(angle));
90        SkScalar y = (SkScalar) (radius * sin(angle));
91        x += center.fX;
92        y += center.fY;
93        if (index == 0) {
94            path.moveTo(x, y);
95        } else {
96            path.lineTo(x, y);
97        }
98        angle += 3.1415f / points;
99    }
100    path.close();
101}
102
103static bool drawStars(SkCanvas* canvas, int step, bool useOld)
104{
105    SkPath path;
106    const int stars = 25;
107    int pts[stars];
108 //   static bool initialize = true;
109    int s;
110    for (s = 0; s < stars; ++s) {
111        pts[s] = 4 + (s % 7);
112    }
113    SkPoint locs[stars];
114    SkScalar angles[stars];
115    SkScalar innerRadius[stars];
116    SkScalar outerRadius[stars];
117    const int width = 640;
118    const int height = 480;
119    const int margin = 30;
120    const int minRadius = 120;
121    const int maxInner = 800;
122    const int maxOuter = 1153;
123    for (s = 0; s < stars; ++s) {
124        int starW = (int) (width - margin * 2 + (SkScalar) s * (stars - s) / stars);
125        locs[s].fX = (int) (step * (1.3f * (s + 1) / stars) + s * 121) % (starW * 2);
126        if (locs[s].fX > starW) {
127            locs[s].fX = starW * 2 - locs[s].fX;
128        }
129        locs[s].fX += margin;
130        int starH = (int) (height - margin * 2 + (SkScalar) s * s / stars);
131        locs[s].fY = (int) (step * (1.7f * (s + 1) / stars) + s * 183) % (starH * 2);
132        if (locs[s].fY > starH) {
133            locs[s].fY = starH * 2 - locs[s].fY;
134        }
135        locs[s].fY += margin;
136        angles[s] = ((step + s * 47) % (360 * 4)) * 3.1415f / 180 / 4;
137        innerRadius[s] = (step + s * 30) % (maxInner * 2);
138        if (innerRadius[s] > maxInner) {
139            innerRadius[s] = (maxInner * 2) - innerRadius[s];
140        }
141        innerRadius[s] = innerRadius[s] / 4 + minRadius;
142        outerRadius[s] = (step + s * 70) % (maxOuter * 2);
143        if (outerRadius[s] > maxOuter) {
144            outerRadius[s] = (maxOuter * 2) - outerRadius[s];
145        }
146        outerRadius[s] = outerRadius[s] / 4 + minRadius;
147        createStar(path, innerRadius[s] / 4.0f, outerRadius[s] / 4.0f,
148                angles[s], pts[s], locs[s]);
149    }
150    return drawPaths(canvas, path, useOld);
151}
152
153#if 0
154static void tryRoncoOnce(const SkPath& path, const SkRect& target, bool show) {
155    // capture everything in a desired rectangle
156    SkPath tiny;
157    bool closed = true;
158    SkPath::Iter iter(path, false);
159    SkPoint pts[4];
160    SkPath::Verb verb;
161    int count = 0;
162    SkPoint lastPt;
163    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
164        switch (verb) {
165            case SkPath::kMove_Verb:
166                count = 0;
167                break;
168            case SkPath::kLine_Verb:
169                count = 1;
170                break;
171            case SkPath::kQuad_Verb:
172                count = 2;
173                break;
174            case SkPath::kCubic_Verb:
175                count = 3;
176                break;
177            case SkPath::kClose_Verb:
178                if (!closed) {
179                    tiny.close();
180                    closed = true;
181                }
182                count = 0;
183                break;
184            default:
185                SkDEBUGFAIL("bad verb");
186        }
187        if (!count) {
188            continue;
189        }
190        SkRect bounds;
191        bounds.set(pts[0].fX, pts[0].fY, pts[0].fX, pts[0].fY);
192        for (int i = 1; i <= count; ++i) {
193            bounds.growToInclude(pts[i].fX + 0.1f, pts[i].fY + 0.1f);
194        }
195        if (!SkRect::Intersects(target, bounds)) {
196            continue;
197        }
198        if (closed) {
199            tiny.moveTo(pts[0].fX, pts[0].fY);
200            closed = false;
201        } else if (pts[0] != lastPt) {
202            tiny.lineTo(pts[0].fX, pts[0].fY);
203        }
204        switch (verb) {
205            case SkPath::kLine_Verb:
206                tiny.lineTo(pts[1].fX, pts[1].fY);
207                lastPt = pts[1];
208                break;
209            case SkPath::kQuad_Verb:
210                tiny.quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
211                lastPt = pts[2];
212                break;
213            case SkPath::kCubic_Verb:
214                tiny.cubicTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3].fY);
215                lastPt = pts[3];
216                break;
217            default:
218                SkDEBUGFAIL("bad verb");
219        }
220    }
221    if (!closed) {
222        tiny.close();
223    }
224    if (show) {
225        showPath(tiny, NULL);
226        SkDebugf("simplified:\n");
227    }
228    testSimplifyx(tiny);
229}
230#endif
231
232#if 0
233static void tryRonco(const SkPath& path) {
234    int divMax = 64;
235    int divMin = 1;
236    int xDivMin = 0;
237    int yDivMin = 0;
238    bool allYs = true;
239    bool allXs = true;
240    if (1) {
241        divMax = divMin = 64;
242        xDivMin = 11;
243        yDivMin = 0;
244        allXs = true;
245        allYs = true;
246    }
247    for (int divs = divMax; divs >= divMin; divs /= 2) {
248        SkDebugf("divs=%d\n",divs);
249        const SkRect& overall = path.getBounds();
250        SkScalar cellWidth = overall.width() / divs * 2;
251        SkScalar cellHeight = overall.height() / divs * 2;
252        SkRect target;
253        int xDivMax = divMax == divMin && !allXs ? xDivMin + 1 : divs;
254        int yDivMax = divMax == divMin && !allYs ? yDivMin + 1 : divs;
255        for (int xDiv = xDivMin; xDiv < xDivMax; ++xDiv) {
256            SkDebugf("xDiv=%d\n",xDiv);
257            for (int yDiv = yDivMin; yDiv < yDivMax; ++yDiv) {
258                SkDebugf("yDiv=%d\n",yDiv);
259                target.setXYWH(overall.fLeft + (overall.width() - cellWidth) * xDiv / divs,
260                        overall.fTop + (overall.height() - cellHeight) * yDiv / divs,
261                         cellWidth, cellHeight);
262                tryRoncoOnce(path, target, divMax == divMin);
263            }
264        }
265    }
266}
267#endif
268
269static bool drawLetters(SkCanvas* canvas, int step, bool useOld)
270{
271    SkPath path;
272    const int width = 640;
273    const int height = 480;
274    const char testStr[] = "Merge";
275    const int testStrLen = sizeof(testStr) - 1;
276    SkPoint textPos[testStrLen];
277    SkScalar widths[testStrLen];
278    SkPaint paint;
279    paint.setTextSize(40);
280    paint.setAntiAlias(true);
281    paint.getTextWidths(testStr, testStrLen, widths, NULL);
282    SkScalar running = 0;
283    for (int x = 0; x < testStrLen; ++x) {
284        SkScalar width = widths[x];
285        widths[x] = running;
286        running += width;
287    }
288    SkScalar bias = (width - widths[testStrLen - 1]) / 2;
289    for (int x = 0; x < testStrLen; ++x) {
290        textPos[x].fX = bias + widths[x];
291        textPos[x].fY = height / 2;
292    }
293    paint.setTextSize(40 + step / 100.0f);
294#if 0
295    bool oneShot = false;
296    for (int mask = 0; mask < 1 << testStrLen; ++mask) {
297        char maskStr[testStrLen];
298#if 1
299        mask = 12;
300        oneShot = true;
301#endif
302        SkDebugf("mask=%d\n", mask);
303        for (int letter = 0; letter < testStrLen; ++letter) {
304            maskStr[letter] = mask & (1 << letter) ? testStr[letter] : ' ';
305        }
306        paint.getPosTextPath(maskStr, testStrLen, textPos, &path);
307   //     showPath(path, NULL);
308   //     SkDebugf("%d simplified:\n", mask);
309        tryRonco(path);
310    //    testSimplifyx(path);
311        if (oneShot) {
312            break;
313        }
314    }
315#endif
316    paint.getPosTextPath(testStr, testStrLen, textPos, &path);
317#if 0
318    tryRonco(path);
319    SkDebugf("RoncoDone!\n");
320#endif
321#if 0
322    showPath(path, NULL);
323    SkDebugf("simplified:\n");
324#endif
325    return drawPaths(canvas, path, false);
326}
327
328static bool (*drawDemos[])(SkCanvas* , int , bool ) = {
329    drawStars,
330    drawCircles,
331    drawLetters,
332};
333
334static size_t drawDemosCount = sizeof(drawDemos) / sizeof(drawDemos[0]);
335
336static bool (*firstTest)(SkCanvas* , int , bool) = drawStars;
337
338
339bool DrawEdgeDemo(SkCanvas* canvas, int step, bool useOld) {
340    size_t index = 0;
341    if (firstTest) {
342        while (index < drawDemosCount && drawDemos[index] != firstTest) {
343            ++index;
344        }
345    }
346    return (*drawDemos[index])(canvas, step, useOld);
347}
348