aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--experimental/SkBoundaryPatch.cpp61
-rw-r--r--experimental/SkBoundaryPatch.h41
-rw-r--r--include/utils/SkMeshUtils.h43
-rw-r--r--samplecode/SampleAnimator.cpp45
-rw-r--r--samplecode/SampleWarp.cpp200
-rw-r--r--src/utils/SkMeshUtils.cpp96
6 files changed, 319 insertions, 167 deletions
diff --git a/experimental/SkBoundaryPatch.cpp b/experimental/SkBoundaryPatch.cpp
index 1644f720ac..cdbc877634 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 264ee2961d..835fc3e641 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 0000000000..1235485880
--- /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 2909ebc781..4ba88729a8 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 c7adad9490..16c0bc82be 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<SkPoint> texStorage(vertCount);
- SkPoint* tex = texStorage.get();
- SkAutoTArray<uint16_t> 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 0000000000..0385b99d01
--- /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);
+ }
+}
+