aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar dandov <dandov@google.com>2014-08-04 10:02:00 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-08-04 10:02:00 -0700
commitecfff21bde1f0ca3c36533eded325066b5f2d42d (patch)
tree72fd989d958f337a3b6c779cc3f8f34378645501
parentd3d6b818c70fa809837eb0cdf2ff5a5d4c6dff53 (diff)
SkCanvas interface for drawing a patch.
Added function SkCanvas::drawPatch to the API. This function receives the patch to draw and the paint. Added function SkBaseDevice::drawPatch to the API. This function also receives the patch to draw and the paint. Currently SkGpuDevice and SkBitmapDevice generate the mesh taking into account the scale factor and call the corresponding device's drawVertices. BUG=skia: R=jvanverth@google.com, egdaniel@google.com, bsalomon@google.com Author: dandov@google.com Review URL: https://codereview.chromium.org/424663006
-rw-r--r--gm/patch.cpp146
-rw-r--r--gyp/utils.gypi2
-rw-r--r--include/core/SkCanvas.h3
-rw-r--r--include/core/SkDevice.h2
-rw-r--r--include/core/SkPatch.h40
-rw-r--r--include/utils/SkDeferredCanvas.h1
-rw-r--r--src/core/SkCanvas.cpp19
-rw-r--r--src/core/SkDevice.cpp13
-rw-r--r--src/core/SkPatch.cpp124
-rw-r--r--src/utils/SkDeferredCanvas.cpp6
-rw-r--r--src/utils/SkPatchUtils.cpp57
-rw-r--r--src/utils/SkPatchUtils.h23
12 files changed, 314 insertions, 122 deletions
diff --git a/gm/patch.cpp b/gm/patch.cpp
index eb99944c0b..5658ef6a88 100644
--- a/gm/patch.cpp
+++ b/gm/patch.cpp
@@ -14,14 +14,71 @@
#include "GrContext.h"
#include "GrTest.h"
-
#include "SkPatch.h"
+static void draw_control_points(SkCanvas* canvas, SkPatch& patch, SkPaint& paint) {
+ //draw control points
+ SkPaint copy(paint);
+ SkPoint bottom[4];
+ patch.getBottomPoints(bottom);
+ SkPoint top[4];
+ patch.getTopPoints(top);
+ SkPoint left[4];
+ patch.getLeftPoints(left);
+ SkPoint right[4];
+ patch.getRightPoints(right);
+
+ copy.setColor(SK_ColorBLACK);
+ copy.setStrokeWidth(0.5);
+ SkPoint corners[4] = { bottom[0], bottom[3], top[0], top[3] };
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 4, bottom, copy);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, bottom+1, copy);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 4, top, copy);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 4, left, copy);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 4, right, copy);
+
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, top+1, copy);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, left+1, copy);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, right+1, copy);
+
+ copy.setStrokeWidth(2);
+
+ copy.setColor(SK_ColorRED);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, corners, copy);
+
+ copy.setColor(SK_ColorBLUE);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, bottom+1, copy);
+
+ copy.setColor(SK_ColorCYAN);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, top+1, copy);
+
+ copy.setColor(SK_ColorYELLOW);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, left+1, copy);
+
+ copy.setColor(SK_ColorGREEN);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, right+1, copy);
+}
+
+static void draw_random_patch(SkPoint points[12], SkColor colors[4], SkCanvas* canvas,
+ SkPaint& paint, SkRandom* rnd) {
+ SkPoint ptsCpy[12];
+ memcpy(ptsCpy, points, 12 * sizeof(SkPoint));
+ for (int i = 0; i < 5; i++) {
+ int index = rnd->nextRangeU(0, 11);
+ SkScalar dx = rnd->nextRangeScalar(-50, 50), dy = rnd->nextRangeScalar(-50, 50);
+ ptsCpy[index].offset(dx, dy);
+ }
+ SkPatch patch(ptsCpy, colors);
+ canvas->drawPatch(patch, paint);
+ draw_control_points(canvas, patch, paint);
+}
+
namespace skiagm {
/**
* This GM draws a SkPatch.
*/
class SkPatchGM : public GM {
+
public:
SkPatchGM() {
this->setBGColor(0xFFFFFFFF);
@@ -37,77 +94,50 @@ protected:
}
virtual uint32_t onGetFlags() const SK_OVERRIDE {
- return kGPUOnly_Flag;
+ return kSkipTiled_Flag | kSkipPipe_Flag | kSkipPicture_Flag;
}
-
-
+
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
-
+
SkPaint paint;
SkColor colors[4] = {
SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorCYAN
};
- SkPoint points[] = {
- {100,100},{130,50},{500,70}, {650,60},
- {350,125},{490,555},{600,700},
- {515,595},{140,550},{110,590},
- {125,400},{70,150}
-
+ SkPoint points[12] = {
+ {50,50},{75,20},{125,80}, {150,50},
+ {120,75},{180,125},{150,150},
+ {125,120},{75,180},{50,150},
+ {20,125},{80,75}
};
-
- SkPatch coons(points, colors);
- SkPatch::VertexData data;
- coons.getVertexData(&data, 10);
-
- canvas->drawVertices(SkCanvas::kTriangles_VertexMode,data.fVertexCount,
- data.fPoints, data.fTexCoords, data.fColors, NULL, data.fIndices,
- data.fIndexCount, paint);
-
- //draw control points
- SkPoint bottom[4];
- coons.getBottomPoints(bottom);
- SkPoint top[4];
- coons.getTopPoints(top);
- SkPoint left[4];
- coons.getLeftPoints(left);
- SkPoint right[4];
- coons.getRightPoints(right);
-
- SkPoint corners[4] = { bottom[0], bottom[3], top[0], top[3] };
- canvas->drawPoints(SkCanvas::kLines_PointMode, 4, bottom, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 2, bottom+1, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 4, top, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 4, left, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 4, right, paint);
-
- canvas->drawPoints(SkCanvas::kLines_PointMode, 2, top+1, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 2, left+1, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 2, right+1, paint);
-
- paint.setStrokeWidth(10);
-
- paint.setColor(SK_ColorRED);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, corners, paint);
-
- paint.setColor(SK_ColorBLUE);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, bottom+1, paint);
-
- paint.setColor(SK_ColorCYAN);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, top+1, paint);
-
- paint.setColor(SK_ColorYELLOW);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, left+1, paint);
-
- paint.setColor(SK_ColorGREEN);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, right+1, paint);
+ SkRandom rnd;
+ SkScalar scale = 0.5f;
+ canvas->save();
+ for (SkScalar x = 0; x < 4; x++) {
+ canvas->save();
+ canvas->scale(scale * (x + 1), scale * (x + 1));
+ canvas->translate(x * 100, 0);
+ draw_random_patch(points, colors, canvas, paint, &rnd);
+ canvas->restore();
+ }
+ canvas->translate(0, 270);
+ SkScalar skew = 0.1f;
+ for (SkScalar x = 0; x < 4; x++) {
+ canvas->save();
+ canvas->scale(scale * (x + 1), scale * (x + 1));
+ canvas->skew(skew * (x + 1), skew * (x + 1));
+ canvas->translate(x * 100, 0);
+ draw_random_patch(points, colors, canvas, paint, &rnd);
+ canvas->restore();
+ }
+ canvas->restore();
}
private:
typedef GM INHERITED;
};
-DEF_GM( return SkNEW(SkPatchGM); )
+DEF_GM(return SkNEW(SkPatchGM); )
}
diff --git a/gyp/utils.gypi b/gyp/utils.gypi
index c8fc3f02df..c90d19344c 100644
--- a/gyp/utils.gypi
+++ b/gyp/utils.gypi
@@ -78,6 +78,8 @@
'<(skia_src_path)/utils/SkParseColor.cpp',
'<(skia_src_path)/utils/SkParsePath.cpp',
'<(skia_src_path)/utils/SkPictureUtils.cpp',
+ '<(skia_src_path)/utils/SkPatchUtils.cpp',
+ '<(skia_src_path)/utils/SkPatchUtils.h',
'<(skia_src_path)/utils/SkPathUtils.cpp',
'<(skia_src_path)/utils/SkProxyCanvas.cpp',
'<(skia_src_path)/utils/SkSHA1.cpp',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index d68a9c50ab..5c4db207cc 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -14,6 +14,7 @@
#include "SkClipStack.h"
#include "SkPaint.h"
#include "SkRefCnt.h"
+#include "SkPatch.h"
#include "SkPath.h"
#include "SkRegion.h"
#include "SkXfermode.h"
@@ -1006,6 +1007,8 @@ public:
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint);
+
+ virtual void drawPatch(const SkPatch& patch, const SkPaint& paint);
/** Send a blob of data to the canvas.
For canvases that draw, this call is effectively a no-op, as the data
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 504138df1e..3e5e42b48f 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -242,6 +242,8 @@ protected:
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint) = 0;
+ // default implementation calls drawVertices
+ virtual void drawPatch(const SkDraw&, const SkPatch& patch, const SkPaint& paint);
/** The SkDevice passed will be an SkDevice which was returned by a call to
onCreateDevice on this device with kSaveLayer_Usage.
*/
diff --git a/include/core/SkPatch.h b/include/core/SkPatch.h
index 2354423aba..3e06c3fc91 100644
--- a/include/core/SkPatch.h
+++ b/include/core/SkPatch.h
@@ -46,6 +46,7 @@ public:
}
};
+ // Enums for control points based on the order specified in the constructor (clockwise).
enum CubicCtrlPts {
kTopP0_CubicCtrlPts = 0,
kTopP1_CubicCtrlPts = 1,
@@ -68,6 +69,14 @@ public:
kLeftP3_CubicCtrlPts = 9,
};
+ // Enum for corner colors also clockwise.
+ enum CornerColors {
+ kTopLeft_CornerColors = 0,
+ kTopRight_CornerColors,
+ kBottomRight_CornerColors,
+ kBottomLeft_CornerColors
+ };
+
/**
* Points are in the following order:
* (top curve)
@@ -76,49 +85,62 @@ public:
* 10 5
* 9 8 7 6
* (bottom curve)
- * Used pointer to an array to guarantee that this method receives an array of 4 SkColors
*/
SkPatch(SkPoint points[12], SkColor colors[4]);
/**
* Function that evaluates the coons patch interpolation.
* data refers to the pointer of the PatchData struct in which the tessellation data is set.
- * divisions defines the number of steps in which the SkPatch is going to be subdivided per
- * axis.
+ * lod refers the level of detail for each axis.
*/
- bool getVertexData(SkPatch::VertexData* data, int divisions);
+ bool getVertexData(SkPatch::VertexData* data, int lodX, int lodY) const;
- void getTopPoints(SkPoint points[4]) {
+ void getTopPoints(SkPoint points[4]) const {
points[0] = fCtrlPoints[kTopP0_CubicCtrlPts];
points[1] = fCtrlPoints[kTopP1_CubicCtrlPts];
points[2] = fCtrlPoints[kTopP2_CubicCtrlPts];
points[3] = fCtrlPoints[kTopP3_CubicCtrlPts];
}
- void getBottomPoints(SkPoint points[4]) {
+ void getBottomPoints(SkPoint points[4]) const {
points[0] = fCtrlPoints[kBottomP0_CubicCtrlPts];
points[1] = fCtrlPoints[kBottomP1_CubicCtrlPts];
points[2] = fCtrlPoints[kBottomP2_CubicCtrlPts];
points[3] = fCtrlPoints[kBottomP3_CubicCtrlPts];
}
- void getLeftPoints(SkPoint points[4]) {
+ void getLeftPoints(SkPoint points[4]) const {
points[0] = fCtrlPoints[kLeftP0_CubicCtrlPts];
points[1] = fCtrlPoints[kLeftP1_CubicCtrlPts];
points[2] = fCtrlPoints[kLeftP2_CubicCtrlPts];
points[3] = fCtrlPoints[kLeftP3_CubicCtrlPts];
}
- void getRightPoints(SkPoint points[4]) {
+ void getRightPoints(SkPoint points[4]) const {
points[0] = fCtrlPoints[kRightP0_CubicCtrlPts];
points[1] = fCtrlPoints[kRightP1_CubicCtrlPts];
points[2] = fCtrlPoints[kRightP2_CubicCtrlPts];
points[3] = fCtrlPoints[kRightP3_CubicCtrlPts];
}
+ void getCornerPoints(SkPoint points[4]) const {
+ points[0] = fCtrlPoints[kTopP0_CubicCtrlPts];
+ points[1] = fCtrlPoints[kTopP3_CubicCtrlPts];
+ points[2] = fCtrlPoints[kBottomP3_CubicCtrlPts];
+ points[3] = fCtrlPoints[kBottomP0_CubicCtrlPts];
+ }
+
+ const SkPoint* getControlPoints() const {
+ return fCtrlPoints;
+ }
+
+ const SkColor* getColors() const {
+ return fCornerColors;
+ }
+
private:
SkPoint fCtrlPoints[12];
- SkPMColor fCornerColors[4];
+ SkColor fCornerColors[4];
};
#endif
diff --git a/include/utils/SkDeferredCanvas.h b/include/utils/SkDeferredCanvas.h
index 0e2ed45c5a..f37e9d8829 100644
--- a/include/utils/SkDeferredCanvas.h
+++ b/include/utils/SkDeferredCanvas.h
@@ -168,6 +168,7 @@ public:
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint) SK_OVERRIDE;
+ virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter) SK_OVERRIDE;
protected:
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index a561316b7f..3320d18fc0 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -2253,6 +2253,25 @@ void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
LOOPER_END
}
+void SkCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+
+ // Since a patch is always within the convex hull of the control points, we discard it when its
+ // bounding rectangle is completely outside the current clip.
+ SkRect bounds;
+ bounds.set(patch.getControlPoints(), 12);
+ if (this->quickReject(bounds)) {
+ return;
+ }
+
+ LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
+
+ while (iter.next()) {
+ iter.fDevice->drawPatch(iter, patch, paint);
+ }
+
+ LOOPER_END
+}
+
//////////////////////////////////////////////////////////////////////////////
// These methods are NOT virtual, and therefore must call back into virtual
// methods, rather than actually drawing themselves.
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index e71c889451..e71500a962 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -6,7 +6,9 @@
*/
#include "SkDevice.h"
+#include "SkDraw.h"
#include "SkMetaData.h"
+#include "SkPatchUtils.h"
SkBaseDevice::SkBaseDevice()
: fLeakyProperties(SkDeviceProperties::MakeDefault())
@@ -77,6 +79,17 @@ void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
this->drawPath(draw, path, paint, preMatrix, pathIsMutable);
}
+void SkBaseDevice::drawPatch(const SkDraw& draw, const SkPatch& patch, const SkPaint& paint) {
+ SkPatch::VertexData data;
+
+ SkISize lod = SkPatchUtils::GetLevelOfDetail(patch, draw.fMatrix);
+
+ // It automatically adjusts lodX and lodY in case it exceeds the number of indices.
+ patch.getVertexData(&data, lod.width(), lod.height());
+ this->drawVertices(draw, SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints,
+ data.fTexCoords, data.fColors, NULL, data.fIndices, data.fIndexCount, paint);
+}
+
bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) {
#ifdef SK_DEBUG
SkASSERT(info.width() > 0 && info.height() > 0);
diff --git a/src/core/SkPatch.cpp b/src/core/SkPatch.cpp
index acd6cb9b57..cc967d5cee 100644
--- a/src/core/SkPatch.cpp
+++ b/src/core/SkPatch.cpp
@@ -53,6 +53,21 @@ public:
this->restart(1);
}
+ explicit FwDCubicEvaluator(SkPoint points[4]) {
+ for (int i = 0; i< 4; i++) {
+ fPoints[i] = points[i];
+ }
+
+ SkScalar cx[4], cy[4];
+ SkGetCubicCoeff(fPoints, cx, cy);
+ fCoefs[0].set(cx[0], cy[0]);
+ fCoefs[1].set(cx[1], cy[1]);
+ fCoefs[2].set(cx[2], cy[2]);
+ fCoefs[3].set(cx[3], cy[3]);
+
+ this->restart(1);
+ }
+
/**
* Restarts the forward differences evaluator to the first value of t = 0.
*/
@@ -104,14 +119,13 @@ private:
SkPatch::SkPatch(SkPoint points[12], SkColor colors[4]) {
- for (int i = 0; i<12; i++) {
+ for (int i = 0; i < 12; i++) {
fCtrlPoints[i] = points[i];
}
+ for (int i = 0; i < 4; i++) {
+ fCornerColors[i] = colors[i];
+ }
- fCornerColors[0] = SkPreMultiplyColor(colors[0]);
- fCornerColors[1] = SkPreMultiplyColor(colors[1]);
- fCornerColors[2] = SkPreMultiplyColor(colors[2]);
- fCornerColors[3] = SkPreMultiplyColor(colors[3]);
}
uint8_t bilinear(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01, SkScalar c11) {
@@ -120,51 +134,51 @@ uint8_t bilinear(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar
return uint8_t(a * (1.f - ty) + b * ty);
}
-bool SkPatch::getVertexData(SkPatch::VertexData* data, int divisions) {
+bool SkPatch::getVertexData(SkPatch::VertexData* data, int lodX, int lodY) const {
- if (divisions < 1) {
+ if (lodX < 1 || lodY < 1) {
return false;
}
- int divX = divisions, divY = divisions;
+ // premultiply colors to avoid color bleeding.
+ SkPMColor colors[4];
+ for (int i = 0; i < 4; i++) {
+ colors[i] = SkPreMultiplyColor(fCornerColors[i]);
+ }
- data->fVertexCount = (divX + 1) * (divY + 1);
- data->fIndexCount = divX * divY * 6;
+ // number of indices is limited by size of uint16_t, so we clamp it to avoid overflow
+ data->fVertexCount = SkMin32((lodX + 1) * (lodY + 1), 65536);
+ lodX = SkMin32(lodX, 255);
+ lodY = SkMin32(lodY, 255);
+ data->fIndexCount = lodX * lodY * 6;
data->fPoints = SkNEW_ARRAY(SkPoint, data->fVertexCount);
data->fColors = SkNEW_ARRAY(uint32_t, data->fVertexCount);
data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount);
data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount);
- FwDCubicEvaluator fBottom(fCtrlPoints[kBottomP0_CubicCtrlPts],
- fCtrlPoints[kBottomP1_CubicCtrlPts],
- fCtrlPoints[kBottomP2_CubicCtrlPts],
- fCtrlPoints[kBottomP3_CubicCtrlPts]),
- fTop(fCtrlPoints[kTopP0_CubicCtrlPts],
- fCtrlPoints[kTopP1_CubicCtrlPts],
- fCtrlPoints[kTopP2_CubicCtrlPts],
- fCtrlPoints[kTopP2_CubicCtrlPts]),
- fLeft(fCtrlPoints[kLeftP0_CubicCtrlPts],
- fCtrlPoints[kLeftP1_CubicCtrlPts],
- fCtrlPoints[kLeftP2_CubicCtrlPts],
- fCtrlPoints[kLeftP3_CubicCtrlPts]),
- fRight(fCtrlPoints[kRightP0_CubicCtrlPts],
- fCtrlPoints[kRightP1_CubicCtrlPts],
- fCtrlPoints[kRightP2_CubicCtrlPts],
- fCtrlPoints[kRightP3_CubicCtrlPts]);
-
- fBottom.restart(divX);
- fTop.restart(divX);
+ SkPoint pts[4];
+ this->getBottomPoints(pts);
+ FwDCubicEvaluator fBottom(pts);
+ this->getTopPoints(pts);
+ FwDCubicEvaluator fTop(pts);
+ this->getLeftPoints(pts);
+ FwDCubicEvaluator fLeft(pts);
+ this->getRightPoints(pts);
+ FwDCubicEvaluator fRight(pts);
+
+ fBottom.restart(lodX);
+ fTop.restart(lodX);
SkScalar u = 0.0f;
- int stride = divY + 1;
- for (int x = 0; x <= divX; x++) {
+ int stride = lodY + 1;
+ for (int x = 0; x <= lodX; x++) {
SkPoint bottom = fBottom.next(), top = fTop.next();
- fLeft.restart(divY);
- fRight.restart(divY);
+ fLeft.restart(lodY);
+ fRight.restart(lodY);
SkScalar v = 0.f;
- for (int y = 0; y <= divY; y++) {
- int dataIndex = x * (divX + 1) + y;
+ for (int y = 0; y <= lodY; y++) {
+ int dataIndex = x * (lodY + 1) + y;
SkPoint left = fLeft.next(), right = fRight.next();
@@ -184,31 +198,31 @@ bool SkPatch::getVertexData(SkPatch::VertexData* data, int divisions) {
data->fPoints[dataIndex] = s0 + s1 - s2;
uint8_t a = bilinear(u, v,
- SkScalar(SkColorGetA(fCornerColors[0])),
- SkScalar(SkColorGetA(fCornerColors[1])),
- SkScalar(SkColorGetA(fCornerColors[2])),
- SkScalar(SkColorGetA(fCornerColors[3])));
+ SkScalar(SkColorGetA(colors[kTopLeft_CornerColors])),
+ SkScalar(SkColorGetA(colors[kTopRight_CornerColors])),
+ SkScalar(SkColorGetA(colors[kBottomLeft_CornerColors])),
+ SkScalar(SkColorGetA(colors[kBottomRight_CornerColors])));
uint8_t r = bilinear(u, v,
- SkScalar(SkColorGetR(fCornerColors[0])),
- SkScalar(SkColorGetR(fCornerColors[1])),
- SkScalar(SkColorGetR(fCornerColors[2])),
- SkScalar(SkColorGetR(fCornerColors[3])));
+ SkScalar(SkColorGetR(colors[kTopLeft_CornerColors])),
+ SkScalar(SkColorGetR(colors[kTopRight_CornerColors])),
+ SkScalar(SkColorGetR(colors[kBottomLeft_CornerColors])),
+ SkScalar(SkColorGetR(colors[kBottomRight_CornerColors])));
uint8_t g = bilinear(u, v,
- SkScalar(SkColorGetG(fCornerColors[0])),
- SkScalar(SkColorGetG(fCornerColors[1])),
- SkScalar(SkColorGetG(fCornerColors[2])),
- SkScalar(SkColorGetG(fCornerColors[3])));
+ SkScalar(SkColorGetG(colors[kTopLeft_CornerColors])),
+ SkScalar(SkColorGetG(colors[kTopRight_CornerColors])),
+ SkScalar(SkColorGetG(colors[kBottomLeft_CornerColors])),
+ SkScalar(SkColorGetG(colors[kBottomRight_CornerColors])));
uint8_t b = bilinear(u, v,
- SkScalar(SkColorGetB(fCornerColors[0])),
- SkScalar(SkColorGetB(fCornerColors[1])),
- SkScalar(SkColorGetB(fCornerColors[2])),
- SkScalar(SkColorGetB(fCornerColors[3])));
+ SkScalar(SkColorGetB(colors[kTopLeft_CornerColors])),
+ SkScalar(SkColorGetB(colors[kTopRight_CornerColors])),
+ SkScalar(SkColorGetB(colors[kBottomLeft_CornerColors])),
+ SkScalar(SkColorGetB(colors[kBottomRight_CornerColors])));
data->fColors[dataIndex] = SkPackARGB32(a,r,g,b);
data->fTexCoords[dataIndex] = SkPoint::Make(u, v);
- if(x < divX && y < divY) {
- int i = 6 * (x * divY + y);
+ if(x < lodX && y < lodY) {
+ int i = 6 * (x * lodY + y);
data->fIndices[i] = x * stride + y;
data->fIndices[i + 1] = x * stride + 1 + y;
data->fIndices[i + 2] = (x + 1) * stride + 1 + y;
@@ -216,9 +230,9 @@ bool SkPatch::getVertexData(SkPatch::VertexData* data, int divisions) {
data->fIndices[i + 4] = data->fIndices[i + 2];
data->fIndices[i + 5] = (x + 1) * stride + y;
}
- v += 1.f / divY;
+ v = SkScalarClampMax(v + 1.f / lodY, 1);
}
- u += 1.f / divX;
+ u = SkScalarClampMax(u + 1.f / lodX, 1);
}
return true;
}
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 19957fd81d..2820bac48d 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -224,6 +224,8 @@ protected:
SkXfermode* xmode, const uint16_t indices[],
int indexCount, const SkPaint& paint) SK_OVERRIDE
{SkASSERT(0);}
+ virtual void drawPatch(const SkDraw&, const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE
+ {SkASSERT(0);}
virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
const SkPaint&) SK_OVERRIDE
{SkASSERT(0);}
@@ -914,6 +916,10 @@ void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
this->recordedDrawCommand();
}
+void SkDeferredCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+ //TODO
+}
+
SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
this->drawingCanvas()->setDrawFilter(filter);
this->INHERITED::setDrawFilter(filter);
diff --git a/src/utils/SkPatchUtils.cpp b/src/utils/SkPatchUtils.cpp
new file mode 100644
index 0000000000..7dd0a09d97
--- /dev/null
+++ b/src/utils/SkPatchUtils.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPatchUtils.h"
+
+#include "SkGeometry.h"
+
+// size in pixels of each partition per axis, adjust this knob
+static const int kPartitionSize = 30;
+
+/**
+ * Calculate the approximate arc length given a bezier curve's control points.
+ */
+static SkScalar approx_arc_length(SkPoint* points, int count) {
+ if (count < 2) {
+ return 0;
+ }
+ SkScalar arcLength = 0;
+ for (int i = 0; i < count - 1; i++) {
+ arcLength += SkPoint::Distance(points[i], points[i + 1]);
+ }
+ return arcLength;
+}
+
+SkISize SkPatchUtils::GetLevelOfDetail(const SkPatch& patch, const SkMatrix* matrix) {
+
+ SkPoint mapPts[12];
+ matrix->mapPoints(mapPts, patch.getControlPoints(), 12);
+
+ // Approximate length of each cubic.
+ SkPoint pts[4];
+ patch.getTopPoints(pts);
+ matrix->mapPoints(pts, 4);
+ SkScalar topLength = approx_arc_length(pts, 4);
+
+ patch.getBottomPoints(pts);
+ matrix->mapPoints(pts, 4);
+ SkScalar bottomLength = approx_arc_length(pts, 4);
+
+ patch.getLeftPoints(pts);
+ matrix->mapPoints(pts, 4);
+ SkScalar leftLength = approx_arc_length(pts, 4);
+
+ patch.getRightPoints(pts);
+ matrix->mapPoints(pts, 4);
+ SkScalar rightLength = approx_arc_length(pts, 4);
+
+ // Level of detail per axis, based on the larger side between top and bottom or left and right
+ int lodX = static_cast<int>(SkMaxScalar(topLength, bottomLength) / kPartitionSize);
+ int lodY = static_cast<int>(SkMaxScalar(leftLength, rightLength) / kPartitionSize);
+
+ return SkISize::Make(SkMax32(4, lodX), SkMax32(4, lodY));
+}
diff --git a/src/utils/SkPatchUtils.h b/src/utils/SkPatchUtils.h
new file mode 100644
index 0000000000..f2e3b43ed1
--- /dev/null
+++ b/src/utils/SkPatchUtils.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPatchUtils_DEFINED
+#define SkPatchUtils_DEFINED
+
+#include "SkPatch.h"
+#include "SkMatrix.h"
+
+class SK_API SkPatchUtils {
+
+public:
+ /**
+ * Method that calculates a level of detail (number of subdivisions) for a patch in both axis.
+ */
+ static SkISize GetLevelOfDetail(const SkPatch& patch, const SkMatrix* matrix);
+};
+
+#endif