| /* | |
| * Copyright 2011 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "SampleCode.h" | |
| #include "SkView.h" | |
| #include "SkCanvas.h" | |
| #include "SkGradientShader.h" | |
| #include "SkPath.h" | |
| #include "SkRegion.h" | |
| #include "SkShader.h" | |
| #include "SkUtils.h" | |
| #include "SkImageDecoder.h" | |
| #include "SkBlurMaskFilter.h" | |
| #include "SkTableMaskFilter.h" | |
| #define kNearlyZero (SK_Scalar1 / 8092) | |
| static void test_bigblur(SkCanvas* canvas) { | |
| canvas->drawColor(SK_ColorBLACK); | |
| SkBitmap orig, mask; | |
| SkImageDecoder::DecodeFile("/skimages/app_icon.png", &orig); | |
| SkMaskFilter* mf = SkBlurMaskFilter::Create(8, SkBlurMaskFilter::kNormal_BlurStyle); | |
| SkPaint paint; | |
| paint.setMaskFilter(mf)->unref(); | |
| SkIPoint offset; | |
| orig.extractAlpha(&mask, &paint, &offset); | |
| paint.setColor(0xFFBB8800); | |
| paint.setColor(SK_ColorWHITE); | |
| int i; | |
| canvas->save(); | |
| float gamma = 0.8; | |
| for (i = 0; i < 5; i++) { | |
| paint.setMaskFilter(SkTableMaskFilter::CreateGamma(gamma))->unref(); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| paint.setMaskFilter(NULL); | |
| canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); | |
| gamma -= 0.1; | |
| canvas->translate(120, 0); | |
| } | |
| canvas->restore(); | |
| canvas->translate(0, 160); | |
| for (i = 0; i < 5; i++) { | |
| paint.setMaskFilter(SkTableMaskFilter::CreateClip(i*30, 255 - 20))->unref(); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| paint.setMaskFilter(NULL); | |
| canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); | |
| canvas->translate(120, 0); | |
| } | |
| #if 0 | |
| paint.setColor(0xFFFFFFFF); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| paint.setMaskFilter(NULL); | |
| canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); | |
| canvas->translate(120, 0); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); | |
| canvas->translate(120, 0); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); | |
| canvas->translate(120, 0); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); | |
| canvas->translate(120, 0); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(mask, 0, 0, &paint); | |
| canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint); | |
| #endif | |
| } | |
| #include "SkMeshUtils.h" | |
| static SkPoint SkMakePoint(SkScalar x, SkScalar y) { | |
| SkPoint pt; | |
| pt.set(x, y); | |
| return pt; | |
| } | |
| static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) { | |
| return SkMakePoint(SkScalarInterp(a.fX, b.fX, t), | |
| SkScalarInterp(a.fY, b.fY, t)); | |
| } | |
| #include "SkBoundaryPatch.h" | |
| static void set_cubic(SkPoint pts[4], SkScalar x0, SkScalar y0, | |
| SkScalar x3, SkScalar y3, SkScalar scale = 1) { | |
| SkPoint tmp, tmp2; | |
| pts[0].set(x0, y0); | |
| pts[3].set(x3, y3); | |
| tmp = SkPointInterp(pts[0], pts[3], SK_Scalar1/3); | |
| tmp2 = pts[0] - tmp; | |
| tmp2.rotateCW(); | |
| tmp2.scale(scale); | |
| pts[1] = tmp + tmp2; | |
| tmp = SkPointInterp(pts[0], pts[3], 2*SK_Scalar1/3); | |
| tmp2 = pts[3] - tmp; | |
| tmp2.rotateCW(); | |
| tmp2.scale(scale); | |
| pts[2] = tmp + tmp2; | |
| } | |
| static void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale) { | |
| SkCubicBoundary cubic; | |
| set_cubic(cubic.fPts + 0, 0, 0, 100, 0, scale); | |
| set_cubic(cubic.fPts + 3, 100, 0, 100, 100, scale); | |
| set_cubic(cubic.fPts + 6, 100, 100, 0, 100, -scale); | |
| set_cubic(cubic.fPts + 9, 0, 100, 0, 0, 0); | |
| SkBoundaryPatch patch; | |
| patch.setBoundary(&cubic); | |
| const int Rows = 16; | |
| const int Cols = 16; | |
| SkPoint pts[Rows * Cols]; | |
| patch.evalPatch(pts, Rows, Cols); | |
| SkPaint paint; | |
| paint.setAntiAlias(true); | |
| paint.setFilterBitmap(true); | |
| paint.setStrokeWidth(1); | |
| paint.setStrokeCap(SkPaint::kRound_Cap); | |
| canvas->translate(50, 50); | |
| canvas->scale(3, 3); | |
| SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint); | |
| } | |
| static void test_drag(SkCanvas* canvas, const SkBitmap& bm, | |
| const SkPoint& p0, const SkPoint& p1) { | |
| SkCubicBoundary cubic; | |
| set_cubic(cubic.fPts + 0, 0, 0, 100, 0, 0); | |
| set_cubic(cubic.fPts + 3, 100, 0, 100, 100, 0); | |
| set_cubic(cubic.fPts + 6, 100, 100, 0, 100, 0); | |
| set_cubic(cubic.fPts + 9, 0, 100, 0, 0, 0); | |
| #if 0 | |
| cubic.fPts[1] += p1 - p0; | |
| cubic.fPts[2] += p1 - p0; | |
| #else | |
| SkScalar dx = p1.fX - p0.fX; | |
| if (dx > 0) dx = 0; | |
| SkScalar dy = p1.fY - p0.fY; | |
| if (dy > 0) dy = 0; | |
| cubic.fPts[1].fY += dy; | |
| cubic.fPts[2].fY += dy; | |
| cubic.fPts[10].fX += dx; | |
| cubic.fPts[11].fX += dx; | |
| #endif | |
| SkBoundaryPatch patch; | |
| patch.setBoundary(&cubic); | |
| const int Rows = 16; | |
| const int Cols = 16; | |
| SkPoint pts[Rows * Cols]; | |
| patch.evalPatch(pts, Rows, Cols); | |
| SkPaint paint; | |
| paint.setAntiAlias(true); | |
| paint.setFilterBitmap(true); | |
| paint.setStrokeWidth(1); | |
| paint.setStrokeCap(SkPaint::kRound_Cap); | |
| canvas->translate(50, 50); | |
| canvas->scale(3, 3); | |
| SkAutoCanvasRestore acr(canvas, true); | |
| SkRect r = { 0, 0, 100, 100 }; | |
| canvas->clipRect(r); | |
| SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| class Mesh { | |
| public: | |
| Mesh(); | |
| ~Mesh(); | |
| Mesh& operator=(const Mesh& src); | |
| void init(const SkRect& bounds, int rows, int cols, | |
| const SkRect& texture); | |
| const SkRect& bounds() const { return fBounds; } | |
| int rows() const { return fRows; } | |
| int cols() const { return fCols; } | |
| SkPoint& pt(int row, int col) { | |
| return fPts[row * (fRows + 1) + col]; | |
| } | |
| void draw(SkCanvas*, const SkPaint&); | |
| void drawWireframe(SkCanvas* canvas, const SkPaint& paint); | |
| private: | |
| SkRect fBounds; | |
| int fRows, fCols; | |
| SkPoint* fPts; | |
| SkPoint* fTex; // just points into fPts, not separately allocated | |
| int fCount; | |
| uint16_t* fIndices; | |
| int fIndexCount; | |
| }; | |
| Mesh::Mesh() : fPts(NULL), fCount(0), fIndices(NULL), fIndexCount(0) {} | |
| Mesh::~Mesh() { | |
| delete[] fPts; | |
| delete[] fIndices; | |
| } | |
| Mesh& Mesh::operator=(const Mesh& src) { | |
| delete[] fPts; | |
| delete[] fIndices; | |
| fBounds = src.fBounds; | |
| fRows = src.fRows; | |
| fCols = src.fCols; | |
| fCount = src.fCount; | |
| fPts = new SkPoint[fCount * 2]; | |
| fTex = fPts + fCount; | |
| memcpy(fPts, src.fPts, fCount * 2 * sizeof(SkPoint)); | |
| delete[] fIndices; | |
| fIndexCount = src.fIndexCount; | |
| fIndices = new uint16_t[fIndexCount]; | |
| memcpy(fIndices, src.fIndices, fIndexCount * sizeof(uint16_t)); | |
| return *this; | |
| } | |
| void Mesh::init(const SkRect& bounds, int rows, int cols, | |
| const SkRect& texture) { | |
| SkASSERT(rows > 0 && cols > 0); | |
| fBounds = bounds; | |
| fRows = rows; | |
| fCols = cols; | |
| delete[] fPts; | |
| fCount = (rows + 1) * (cols + 1); | |
| fPts = new SkPoint[fCount * 2]; | |
| fTex = fPts + fCount; | |
| delete[] fIndices; | |
| fIndexCount = rows * cols * 6; | |
| fIndices = new uint16_t[fIndexCount]; | |
| SkPoint* pts = fPts; | |
| const SkScalar dx = bounds.width() / rows; | |
| const SkScalar dy = bounds.height() / cols; | |
| SkPoint* tex = fTex; | |
| const SkScalar dtx = texture.width() / rows; | |
| const SkScalar dty = texture.height() / cols; | |
| uint16_t* idx = fIndices; | |
| int index = 0; | |
| for (int y = 0; y <= cols; y++) { | |
| for (int x = 0; x <= rows; x++) { | |
| pts->set(bounds.fLeft + x*dx, bounds.fTop + y*dy); | |
| pts += 1; | |
| tex->set(texture.fLeft + x*dtx, texture.fTop + y*dty); | |
| tex += 1; | |
| if (y < cols && x < rows) { | |
| *idx++ = index; | |
| *idx++ = index + rows + 1; | |
| *idx++ = index + 1; | |
| *idx++ = index + 1; | |
| *idx++ = index + rows + 1; | |
| *idx++ = index + rows + 2; | |
| index += 1; | |
| } | |
| } | |
| index += 1; | |
| } | |
| } | |
| void Mesh::draw(SkCanvas* canvas, const SkPaint& paint) { | |
| canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount, | |
| fPts, fTex, NULL, NULL, fIndices, fIndexCount, | |
| paint); | |
| } | |
| void Mesh::drawWireframe(SkCanvas* canvas, const SkPaint& paint) { | |
| canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount, | |
| fPts, NULL, NULL, NULL, fIndices, fIndexCount, | |
| paint); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| class WarpView : public SkView { | |
| Mesh fMesh, fOrig; | |
| SkBitmap fBitmap; | |
| SkMatrix fMatrix, fInverse; | |
| public: | |
| WarpView() { | |
| SkBitmap bm; | |
| // SkImageDecoder::DecodeFile("/skimages/marker.png", &bm); | |
| SkImageDecoder::DecodeFile("/skimages/logo.gif", &bm); | |
| // SkImageDecoder::DecodeFile("/beach_shot.JPG", &bm); | |
| fBitmap = bm; | |
| SkRect bounds, texture; | |
| texture.set(0, 0, SkIntToScalar(fBitmap.width()), | |
| SkIntToScalar(fBitmap.height())); | |
| bounds = texture; | |
| // fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture); | |
| fMesh.init(bounds, fBitmap.width()/16, fBitmap.height()/16, texture); | |
| fOrig = fMesh; | |
| fP0.set(0, 0); | |
| fP1 = fP0; | |
| fMatrix.setScale(2, 2); | |
| fMatrix.invert(&fInverse); | |
| } | |
| protected: | |
| // overrides from SkEventSink | |
| virtual bool onQuery(SkEvent* evt) { | |
| if (SampleCode::TitleQ(*evt)) { | |
| SampleCode::TitleR(evt, "Warp"); | |
| return true; | |
| } | |
| return this->INHERITED::onQuery(evt); | |
| } | |
| static SkPoint apply_warp(const SkVector& drag, SkScalar dragLength, | |
| const SkPoint& dragStart, const SkPoint& dragCurr, | |
| const SkPoint& orig) { | |
| SkVector delta = orig - dragCurr; | |
| SkScalar length = SkPoint::Normalize(&delta); | |
| if (length <= kNearlyZero) { | |
| return orig; | |
| } | |
| const SkScalar period = 20; | |
| const SkScalar mag = dragLength / 3; | |
| SkScalar d = length / (period); | |
| d = mag * SkScalarSin(d) / d; | |
| SkScalar dx = delta.fX * d; | |
| SkScalar dy = delta.fY * d; | |
| SkScalar px = orig.fX + dx; | |
| SkScalar py = orig.fY + dy; | |
| return SkPoint::Make(px, py); | |
| } | |
| static SkPoint apply_warp2(const SkVector& drag, SkScalar dragLength, | |
| const SkPoint& dragStart, const SkPoint& dragCurr, | |
| const SkPoint& orig) { | |
| SkVector delta = orig - dragCurr; | |
| SkScalar length = SkPoint::Normalize(&delta); | |
| if (length <= kNearlyZero) { | |
| return orig; | |
| } | |
| const SkScalar period = 10 + dragLength/4; | |
| const SkScalar mag = dragLength / 3; | |
| SkScalar d = length / (period); | |
| if (d > SK_ScalarPI) { | |
| d = SK_ScalarPI; | |
| } | |
| d = -mag * SkScalarSin(d); | |
| SkScalar dx = delta.fX * d; | |
| SkScalar dy = delta.fY * d; | |
| SkScalar px = orig.fX + dx; | |
| SkScalar py = orig.fY + dy; | |
| return SkPoint::Make(px, py); | |
| } | |
| typedef SkPoint (*WarpProc)(const SkVector& drag, SkScalar dragLength, | |
| const SkPoint& dragStart, const SkPoint& dragCurr, | |
| const SkPoint& orig); | |
| void warp(const SkPoint& p0, const SkPoint& p1) { | |
| WarpProc proc = apply_warp2; | |
| SkPoint delta = p1 - p0; | |
| SkScalar length = SkPoint::Normalize(&delta); | |
| for (int y = 0; y < fMesh.rows(); y++) { | |
| for (int x = 0; x < fMesh.cols(); x++) { | |
| fMesh.pt(x, y) = proc(delta, length, p0, p1, fOrig.pt(x, y)); | |
| } | |
| } | |
| fP0 = p0; | |
| fP1 = p1; | |
| } | |
| virtual void onDraw(SkCanvas* canvas) { | |
| canvas->drawColor(SK_ColorLTGRAY); | |
| // test_bigblur(canvas); return; | |
| canvas->concat(fMatrix); | |
| SkPaint paint; | |
| paint.setFilterBitmap(true); | |
| paint.setShader(SkShader::CreateBitmapShader(fBitmap, | |
| SkShader::kClamp_TileMode, | |
| SkShader::kClamp_TileMode))->unref(); | |
| fMesh.draw(canvas, paint); //return; | |
| paint.setShader(NULL); | |
| paint.setColor(SK_ColorRED); | |
| fMesh.draw(canvas, paint); | |
| // test_drag(canvas, fBitmap, fP0, fP1); | |
| } | |
| virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) { | |
| return new Click(this); | |
| } | |
| virtual bool onClick(Click* click) { | |
| SkPoint pts[2] = { click->fOrig, click->fCurr }; | |
| fInverse.mapPoints(pts, 2); | |
| this->warp(pts[0], pts[1]); | |
| this->inval(NULL); | |
| return true; | |
| } | |
| private: | |
| SkIRect fBase, fRect; | |
| SkPoint fP0, fP1; | |
| typedef SkView INHERITED; | |
| }; | |
| ////////////////////////////////////////////////////////////////////////////// | |
| static SkView* MyFactory() { return new WarpView; } | |
| static SkViewRegister reg(MyFactory); |