From 2ee7c640150a863f2859eb0aaf4dfe7ad7836f34 Mon Sep 17 00:00:00 2001 From: "reed@android.com" Date: Wed, 28 Oct 2009 14:25:34 +0000 Subject: [PATCH] update on boundary patches git-svn-id: http://skia.googlecode.com/svn/trunk@409 2bbb7eff-a529-9590-31e7-b0007b416f81 --- experimental/SkBoundaryPatch.cpp | 61 ++++++++---- experimental/SkBoundaryPatch.h | 41 ++++---- include/utils/SkMeshUtils.h | 43 +++++++++ samplecode/SampleAnimator.cpp | 45 +++++++++ samplecode/SampleWarp.cpp | 200 ++++++++++++++------------------------- src/utils/SkMeshUtils.cpp | 96 +++++++++++++++++++ 6 files changed, 319 insertions(+), 167 deletions(-) create mode 100644 include/utils/SkMeshUtils.h create mode 100644 src/utils/SkMeshUtils.cpp diff --git a/experimental/SkBoundaryPatch.cpp b/experimental/SkBoundaryPatch.cpp index 1644f72..cdbc877 100644 --- a/experimental/SkBoundaryPatch.cpp +++ b/experimental/SkBoundaryPatch.cpp @@ -1,20 +1,14 @@ #include "SkBoundaryPatch.h" -SkBoundaryPatch::SkBoundaryPatch() { - sk_bzero(fCurve, sizeof(fCurve)); -}; +SkBoundaryPatch::SkBoundaryPatch() : fBoundary(NULL) {} SkBoundaryPatch::~SkBoundaryPatch() { - for (int i = 0; i < 4; i++) { - SkSafeUnref(fCurve[i]); - } + SkSafeUnref(fBoundary); } -SkBoundaryCurve* SkBoundaryPatch::setCurve(Edge e, SkBoundaryCurve* curve) { - SkASSERT((unsigned)e < 4); - - SkRefCnt_SafeAssign(fCurve[e], curve); - return curve; +SkBoundary* SkBoundaryPatch::setBoundary(SkBoundary* b) { + SkRefCnt_SafeAssign(fBoundary, b); + return b; } static SkPoint SkMakePoint(SkScalar x, SkScalar y) { @@ -28,27 +22,52 @@ static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) { SkScalarInterp(a.fY, b.fY, t)); } -SkPoint SkBoundaryPatch::evaluate(SkScalar unitU, SkScalar unitV) { - SkPoint u = SkPointInterp(fCurve[kLeft]->evaluate(unitV), - fCurve[kRight]->evaluate(unitV), unitU); - SkPoint v = SkPointInterp(fCurve[kTop]->evaluate(unitU), - fCurve[kBottom]->evaluate(unitU), unitV); +SkPoint SkBoundaryPatch::eval(SkScalar unitU, SkScalar unitV) { + SkBoundary* b = fBoundary; + SkPoint u = SkPointInterp(b->eval(SkBoundary::kLeft, SK_Scalar1 - unitV), + b->eval(SkBoundary::kRight, unitV), + unitU); + SkPoint v = SkPointInterp(b->eval(SkBoundary::kTop, unitU), + b->eval(SkBoundary::kBottom, SK_Scalar1 - unitU), + unitV); return SkMakePoint(SkScalarAve(u.fX, v.fX), SkScalarAve(u.fY, v.fY)); } +bool SkBoundaryPatch::evalPatch(SkPoint verts[], int rows, int cols) { + if (rows < 2 || cols < 2) { + return false; + } + + const SkScalar invR = SkScalarInvert(SkIntToScalar(rows - 1)); + const SkScalar invC = SkScalarInvert(SkIntToScalar(cols - 1)); + + for (int y = 0; y < cols; y++) { + SkScalar yy = y * invC; + for (int x = 0; x < rows; x++) { + *verts++ = this->eval(x * invR, yy); + } + } + return true; +} + //////////////////////////////////////////////////////////////////////// #include "SkGeometry.h" -SkPoint SkLineBoundaryCurve::evaluate(SkScalar t) { - return SkPointInterp(fPts[0], fPts[1], t); +SkPoint SkLineBoundary::eval(Edge e, SkScalar t) { + SkASSERT((unsigned)e < 4); + return SkPointInterp(fPts[e], fPts[(e + 1) & 3], t); } -SkPoint SkCubicBoundaryCurve::evaluate(SkScalar t) { +SkPoint SkCubicBoundary::eval(Edge e, SkScalar t) { + SkASSERT((unsigned)e < 4); + + // ensure our 4th cubic wraps to the start of the first + fPts[12] = fPts[0]; + SkPoint loc; - SkEvalCubicAt(fPts, t, &loc, NULL, NULL); + SkEvalCubicAt(&fPts[e * 3], t, &loc, NULL, NULL); return loc; } - diff --git a/experimental/SkBoundaryPatch.h b/experimental/SkBoundaryPatch.h index 264ee29..835fc3e 100644 --- a/experimental/SkBoundaryPatch.h +++ b/experimental/SkBoundaryPatch.h @@ -4,9 +4,17 @@ #include "SkPoint.h" #include "SkRefCnt.h" -class SkBoundaryCurve : public SkRefCnt { +class SkBoundary : public SkRefCnt { public: - virtual SkPoint evaluate(SkScalar unitInterval) = 0; + // These must be 0, 1, 2, 3 for efficiency in the subclass implementations + enum Edge { + kTop = 0, + kRight = 1, + kBottom = 2, + kLeft = 3 + }; + // Edge index goes clockwise around the boundary, beginning at the "top" + virtual SkPoint eval(Edge, SkScalar unitInterval) = 0; }; class SkBoundaryPatch { @@ -14,38 +22,33 @@ public: SkBoundaryPatch(); ~SkBoundaryPatch(); - enum Edge { - kLeft, - kTop, - kRight, - kBottom - }; - - SkBoundaryCurve* getCurve(Edge e) const { return fCurve[e]; } - SkBoundaryCurve* setCurve(Edge e, SkBoundaryCurve*); + SkBoundary* getBoundary() const { return fBoundary; } + SkBoundary* setBoundary(SkBoundary*); - SkPoint evaluate(SkScalar unitU, SkScalar unitV); + SkPoint eval(SkScalar unitU, SkScalar unitV); + bool evalPatch(SkPoint verts[], int rows, int cols); private: - SkBoundaryCurve* fCurve[4]; + SkBoundary* fBoundary; }; //////////////////////////////////////////////////////////////////////// -class SkLineBoundaryCurve : public SkBoundaryCurve { +class SkLineBoundary : public SkBoundary { public: - SkPoint fPts[2]; + SkPoint fPts[4]; // override - virtual SkPoint evaluate(SkScalar); + virtual SkPoint eval(Edge, SkScalar); }; -class SkCubicBoundaryCurve : public SkBoundaryCurve { +class SkCubicBoundary : public SkBoundary { public: - SkPoint fPts[4]; + // the caller sets the first 12 entries. The 13th is used by the impl. + SkPoint fPts[13]; // override - virtual SkPoint evaluate(SkScalar); + virtual SkPoint eval(Edge, SkScalar); }; #endif diff --git a/include/utils/SkMeshUtils.h b/include/utils/SkMeshUtils.h new file mode 100644 index 0000000..1235485 --- /dev/null +++ b/include/utils/SkMeshUtils.h @@ -0,0 +1,43 @@ +#ifndef SkMeshUtils_DEFINED +#define SkMeshUtils_DEFINED + +#include "SkPoint.h" +#include "SkColor.h" + +class SkBitmap; +class SkCanvas; +class SkPaint; + +class SkMeshIndices { +public: + SkMeshIndices(); + ~SkMeshIndices(); + + bool init(int texW, int texH, int rows, int cols) { + return this->init(NULL, NULL, texW, texH, rows, cols); + } + + bool init(SkPoint tex[], uint16_t indices[], + int texW, int texH, int rows, int cols); + + size_t indexCount() const { return fIndexCount; } + const uint16_t* indices() const { return fIndices; } + + size_t texCount() const { return fTexCount; } + const SkPoint* tex() const { return fTex; } + +private: + size_t fIndexCount, fTexCount; + SkPoint* fTex; + uint16_t* fIndices; + void* fStorage; // may be null +}; + +class SkMeshUtils { +public: + static void Draw(SkCanvas*, const SkBitmap&, int rows, int cols, + const SkPoint verts[], const SkColor colors[], + const SkPaint& paint); +}; + +#endif diff --git a/samplecode/SampleAnimator.cpp b/samplecode/SampleAnimator.cpp index 2909ebc..4ba8872 100644 --- a/samplecode/SampleAnimator.cpp +++ b/samplecode/SampleAnimator.cpp @@ -5,6 +5,50 @@ #include "SkAnimator.h" #include "SkStream.h" +#include "SkColorPriv.h" +static inline void Filter_32_opaque_portable(unsigned x, unsigned y, + SkPMColor a00, SkPMColor a01, + SkPMColor a10, SkPMColor a11, + SkPMColor* dstColor) { + SkASSERT((unsigned)x <= 0xF); + SkASSERT((unsigned)y <= 0xF); + + int xy = x * y; + uint32_t mask = gMask_00FF00FF; //0xFF00FF; + + int scale = 256 - 16*y - 16*x + xy; + uint32_t lo = (a00 & mask) * scale; + uint32_t hi = ((a00 >> 8) & mask) * scale; + + scale = 16*x - xy; + lo += (a01 & mask) * scale; + hi += ((a01 >> 8) & mask) * scale; + + scale = 16*y - xy; + lo += (a10 & mask) * scale; + hi += ((a10 >> 8) & mask) * scale; + + lo += (a11 & mask) * xy; + hi += ((a11 >> 8) & mask) * xy; + + *dstColor = ((lo >> 8) & mask) | (hi & ~mask); +} + +static void test_filter() { + for (int r = 0; r <= 0xFF; r++) { + SkPMColor c = SkPackARGB32(0xFF, r, r, r); + for (int y = 0; y <= 0xF; y++) { + for (int x = 0; x <= 0xF; x++) { + SkPMColor dst; + Filter_32_opaque_portable(x, y, c, c, c, c, &dst); + SkASSERT(SkGetPackedA32(dst) == 255); + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + class SkAnimatorView : public SkView { public: SkAnimatorView(); @@ -30,6 +74,7 @@ private: }; SkAnimatorView::SkAnimatorView() : fAnimator(NULL) { + test_filter(); } SkAnimatorView::~SkAnimatorView() { diff --git a/samplecode/SampleWarp.cpp b/samplecode/SampleWarp.cpp index c7adad9..16c0bc8 100644 --- a/samplecode/SampleWarp.cpp +++ b/samplecode/SampleWarp.cpp @@ -8,6 +8,8 @@ #include "SkUtils.h" #include "SkImageDecoder.h" +#include "SkMeshUtils.h" + static SkPoint SkMakePoint(SkScalar x, SkScalar y) { SkPoint pt; pt.set(x, y); @@ -21,18 +23,6 @@ static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) { #include "SkBoundaryPatch.h" -static void set_pts(SkPoint pts[], int R, int C, SkBoundaryPatch* patch) { - SkScalar invR = SkScalarInvert(SkIntToScalar(R - 1)); - SkScalar invC = SkScalarInvert(SkIntToScalar(C - 1)); - - for (int y = 0; y < C; y++) { - SkScalar yy = y * invC; - for (int x = 0; x < R; x++) { - *pts++ = patch->evaluate(x * invR, yy); - } - } -} - static void set_cubic(SkPoint pts[4], SkScalar x0, SkScalar y0, SkScalar x3, SkScalar y3, SkScalar scale = 1) { SkPoint tmp, tmp2; @@ -53,82 +43,78 @@ static void set_cubic(SkPoint pts[4], SkScalar x0, SkScalar y0, pts[2] = tmp + tmp2; } -static void draw_texture(SkCanvas* canvas, const SkPoint verts[], int R, int C, - const SkBitmap& texture) { - int vertCount = R * C; - const int rows = R - 1; - const int cols = C - 1; - int idxCount = rows * cols * 6; - - SkAutoTArray texStorage(vertCount); - SkPoint* tex = texStorage.get(); - SkAutoTArray idxStorage(idxCount); - uint16_t* idx = idxStorage.get(); - - - const SkScalar dtx = texture.width() / rows; - const SkScalar dty = texture.height() / cols; - int index = 0; - for (int y = 0; y <= cols; y++) { - for (int x = 0; x <= rows; x++) { - tex->set(x*dtx, 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; - } - +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.setShader(SkShader::CreateBitmapShader(texture, - SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode))->unref(); - - canvas->drawVertices(SkCanvas::kTriangles_VertexMode, vertCount, verts, - texStorage.get(), NULL, NULL, idxStorage.get(), - idxCount, 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_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale) { - SkCubicBoundaryCurve L, T, R, B; +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); - set_cubic(L.fPts, 0, 0, 0, 100, scale); - set_cubic(T.fPts, 0, 0, 100, 0, scale); - set_cubic(R.fPts, 100, 0, 100, 100, -scale); - set_cubic(B.fPts, 0, 100, 100, 100, 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.setCurve(SkBoundaryPatch::kLeft, &L); - patch.setCurve(SkBoundaryPatch::kTop, &T); - patch.setCurve(SkBoundaryPatch::kRight, &R); - patch.setCurve(SkBoundaryPatch::kBottom, &B); - - const int Rows = 25; - const int Cols = 25; + patch.setBoundary(&cubic); + + const int Rows = 16; + const int Cols = 16; SkPoint pts[Rows * Cols]; - set_pts(pts, Rows, Cols, &patch); + 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); - draw_texture(canvas, pts, Rows, Cols, bm); -// canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(pts), -// pts, paint); + SkRect r = { 0, 0, 100, 100 }; + canvas->clipRect(r); + SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint); } /////////////////////////////////////////////////////////////////////////////// @@ -255,7 +241,7 @@ void Mesh::drawWireframe(SkCanvas* canvas, const SkPaint& paint) { /////////////////////////////////////////////////////////////////////////////// static SkScalar gScale = 0; -static SkScalar gDScale = 0.01; +static SkScalar gDScale = 0.02; class WarpView : public SkView { Mesh fMesh, fOrig; @@ -263,8 +249,8 @@ class WarpView : public SkView { public: WarpView() { SkBitmap bm; - // SkImageDecoder::DecodeFile("/skimages/beach.jpg", &bm); - SkImageDecoder::DecodeFile("/beach_shot.JPG", &bm); + SkImageDecoder::DecodeFile("/skimages/beach.jpg", &bm); + // SkImageDecoder::DecodeFile("/beach_shot.JPG", &bm); fBitmap = bm; SkRect bounds, texture; @@ -275,6 +261,9 @@ public: // fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture); fMesh.init(bounds, 30, 30, texture); fOrig = fMesh; + + fP0.set(0, 0); + fP1 = fP0; } protected: @@ -287,56 +276,9 @@ protected: return this->INHERITED::onQuery(evt); } - static SkPoint make_pt(SkScalar x, SkScalar y) { - SkPoint pt; - pt.set(x, y); - return pt; - } - - static SkScalar mapx0(SkScalar min, SkScalar max, SkScalar x0, SkScalar x1, - SkScalar x) { - if (x < x0) { - SkASSERT(x0 > min); - return x1 - SkScalarMulDiv(x1 - min, x0 - x, x0 - min); - } else { - SkASSERT(max > x0); - return x1 + SkScalarMulDiv(max - x1, x - x0, max - x0); - } - } - - static SkScalar mapx1(SkScalar min, SkScalar max, SkScalar x0, SkScalar x1, - SkScalar x) { - SkScalar newx; - if (x < x0) { - SkASSERT(x0 > min); - newx = x1 - SkScalarMulDiv(x1 - min, x0 - x, x0 - min); - } else { - SkASSERT(max > x0); - newx = x1 + SkScalarMulDiv(max - x1, x - x0, max - x0); - } - return x + (newx - x) * 0.5f; - } - - static SkPoint mappt(const SkRect& r, const SkPoint& p0, const SkPoint& p1, - const SkPoint& pt) { - return make_pt(mapx0(r.fLeft, r.fRight, p0.fX, p1.fX, pt.fX), - mapx0(r.fTop, r.fBottom, p0.fY, p1.fY, pt.fY)); - } - void warp(const SkPoint& p0, const SkPoint& p1) { - const SkRect& bounds = fOrig.bounds(); - int rows = fMesh.rows(); - int cols = fMesh.cols(); - - SkRect r = bounds; - r.inset(bounds.width() / 256, bounds.height() / 256); - if (r.contains(p0)) { - for (int y = 1; y < cols; y++) { - for (int x = 1; x < rows; x++) { - fMesh.pt(x, y) = mappt(bounds, p0, p1, fOrig.pt(x, y)); - } - } - } + fP0 = p0; + fP1 = p1; } virtual void onDraw(SkCanvas* canvas) { @@ -352,7 +294,8 @@ protected: paint.setShader(NULL); paint.setColor(SK_ColorRED); // fMesh.draw(canvas, paint); - + +#if 0 test_patch(canvas, fBitmap, gScale); gScale += gDScale; if (gScale > 2) { @@ -361,6 +304,9 @@ protected: gDScale = -gDScale; } this->inval(NULL); +#else + test_drag(canvas, fBitmap, fP0, fP1); +#endif } virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) { @@ -375,7 +321,7 @@ protected: private: SkIRect fBase, fRect; - + SkPoint fP0, fP1; typedef SkView INHERITED; }; diff --git a/src/utils/SkMeshUtils.cpp b/src/utils/SkMeshUtils.cpp new file mode 100644 index 0000000..0385b99 --- /dev/null +++ b/src/utils/SkMeshUtils.cpp @@ -0,0 +1,96 @@ +#include "SkMeshUtils.h" +#include "SkCanvas.h" +#include "SkPaint.h" + +SkMeshIndices::SkMeshIndices() { + sk_bzero(this, sizeof(*this)); +} + +SkMeshIndices::~SkMeshIndices() { + sk_free(fStorage); +} + +bool SkMeshIndices::init(SkPoint tex[], uint16_t indices[], + int texW, int texH, int rows, int cols) { + if (rows < 2 || cols < 2) { + sk_free(fStorage); + fStorage = NULL; + fTex = NULL; + fIndices = NULL; + fTexCount = fIndexCount = 0; + return false; + } + + sk_free(fStorage); + fStorage = NULL; + + fTexCount = rows * cols; + rows -= 1; + cols -= 1; + fIndexCount = rows * cols * 6; + + if (tex) { + fTex = tex; + fIndices = indices; + } else { + fStorage = sk_malloc_throw(fTexCount * sizeof(SkPoint) + + fIndexCount * sizeof(uint16_t)); + fTex = (SkPoint*)fStorage; + fIndices = (uint16_t*)(fTex + fTexCount); + } + + // compute the indices + { + uint16_t* idx = fIndices; + int index = 0; + for (int y = 0; y < cols; y++) { + for (int x = 0; x < rows; x++) { + *idx++ = index; + *idx++ = index + rows + 1; + *idx++ = index + 1; + + *idx++ = index + 1; + *idx++ = index + rows + 1; + *idx++ = index + rows + 2; + + index += 1; + } + index += 1; + } + } + + // compute texture coordinates + { + SkPoint* tex = fTex; + const SkScalar dx = SkIntToScalar(texW) / rows; + const SkScalar dy = SkIntToScalar(texH) / cols; + for (int y = 0; y <= cols; y++) { + for (int x = 0; x <= rows; x++) { + tex->set(x*dx, y*dy); + tex += 1; + } + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkShader.h" + +void SkMeshUtils::Draw(SkCanvas* canvas, const SkBitmap& bitmap, + int rows, int cols, const SkPoint verts[], + const SkColor colors[], const SkPaint& paint) { + SkMeshIndices idx; + + if (idx.init(bitmap.width(), bitmap.height(), rows, cols)) { + SkPaint p(paint); + p.setShader(SkShader::CreateBitmapShader(bitmap, + SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode))->unref(); + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, + rows * cols, verts, idx.tex(), colors, NULL, + idx.indices(), idx.indexCount(), p); + } +} + -- 2.7.4