C++程序  |  348行  |  10.62 KB

#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);
}

#if 0
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);
}
#endif

#if 0
static void tryRonco(const SkPath& path) {
    int divMax = 64;
    int divMin = 1;
    int xDivMin = 0;
    int yDivMin = 0;
    bool allYs = true;
    bool allXs = true;
    if (1) {
        divMax = divMin = 64;
        xDivMin = 11;
        yDivMin = 0;
        allXs = true;
        allYs = true;
    }
    for (int divs = divMax; divs >= divMin; divs /= 2) {
        SkDebugf("divs=%d\n",divs);
        const SkRect& overall = path.getBounds();
        SkScalar cellWidth = overall.width() / divs * 2;
        SkScalar cellHeight = overall.height() / divs * 2;
        SkRect target;
        int xDivMax = divMax == divMin && !allXs ? xDivMin + 1 : divs;
        int yDivMax = divMax == divMin && !allYs ? yDivMin + 1 : divs;
        for (int xDiv = xDivMin; xDiv < xDivMax; ++xDiv) {
            SkDebugf("xDiv=%d\n",xDiv);
            for (int yDiv = yDivMin; yDiv < yDivMax; ++yDiv) {
                SkDebugf("yDiv=%d\n",yDiv);
                target.setXYWH(overall.fLeft + (overall.width() - cellWidth) * xDiv / divs,
                        overall.fTop + (overall.height() - cellHeight) * yDiv / divs,
                         cellWidth, cellHeight);
                tryRoncoOnce(path, target, divMax == divMin);
            }
        }
    }
}
#endif

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
    bool oneShot = false;
    for (int mask = 0; mask < 1 << testStrLen; ++mask) {
        char maskStr[testStrLen];
#if 1
        mask = 12;
        oneShot = true;
#endif
        SkDebugf("mask=%d\n", mask);
        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);
        if (oneShot) {
            break;
        }
    }
#endif
    paint.getPosTextPath(testStr, testStrLen, textPos, &path);
#if 0
    tryRonco(path);
    SkDebugf("RoncoDone!\n");
#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) = drawStars;


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);
}