aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/patch.cpp4
-rw-r--r--gm/patchgrid.cpp165
-rw-r--r--gyp/gmslides.gypi1
-rw-r--r--gyp/utils.gypi2
-rw-r--r--src/utils/SkPatchGrid.cpp188
-rw-r--r--src/utils/SkPatchGrid.h144
6 files changed, 502 insertions, 2 deletions
diff --git a/gm/patch.cpp b/gm/patch.cpp
index d4fe4ff1f3..2579993b82 100644
--- a/gm/patch.cpp
+++ b/gm/patch.cpp
@@ -87,9 +87,9 @@ protected:
virtual uint32_t onGetFlags() const SK_OVERRIDE {
return kSkipTiled_Flag;
}
-
+
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
-
+
SkPaint paint;
// The order of the colors and points is clockwise starting at upper-left corner.
diff --git a/gm/patchgrid.cpp b/gm/patchgrid.cpp
new file mode 100644
index 0000000000..79baf94253
--- /dev/null
+++ b/gm/patchgrid.cpp
@@ -0,0 +1,165 @@
+
+/*
+ * 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 "gm.h"
+#include "SkPatchGrid.h"
+
+static void draw_control_points(SkCanvas* canvas, const SkPoint cubics[12]) {
+ //draw control points
+ SkPaint paint;
+ SkPoint bottom[4];
+ SkPatchUtils::getBottomCubic(cubics, bottom);
+ SkPoint top[4];
+ SkPatchUtils::getTopCubic(cubics, top);
+ SkPoint left[4];
+ SkPatchUtils::getLeftCubic(cubics, left);
+ SkPoint right[4];
+ SkPatchUtils::getRightCubic(cubics, right);
+
+ paint.setColor(SK_ColorBLACK);
+ paint.setStrokeWidth(0.5);
+ 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(2);
+
+ 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);
+}
+
+namespace skiagm {
+/**
+ * This GM draws a grid of patches, it only uses colors so it could be considered a mesh gradient.
+ */
+class SkPatchGridGM : public GM {
+
+public:
+ SkPatchGridGM() {
+ this->setBGColor(0xFFFFFFFF);
+ }
+
+protected:
+ virtual SkString onShortName() SK_OVERRIDE {
+ return SkString("patch_grid");
+ }
+
+ virtual SkISize onISize() SK_OVERRIDE {
+ return SkISize::Make(800, 800);
+ }
+
+ virtual uint32_t onGetFlags() const SK_OVERRIDE {
+ return kSkipTiled_Flag;
+ }
+
+ virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+
+ SkPaint paint;
+
+ SkPoint vertices[4][5] = {
+ {{50,50}, {150,50}, {250,50},{350,50},{450,50}},
+ {{50,150}, {120,120}, {250,150},{350,150},{450,150}},
+ {{50,250}, {150,250}, {250,250},{350,250},{450,250}},
+ {{100,300}, {150,350}, {250,350},{350,350},{450,350}}
+ };
+
+ SkColor cornerColors[4][5] = {
+ {SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE},
+ {SK_ColorRED, SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE, SK_ColorRED},
+ {SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE},
+ {SK_ColorRED, SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE, SK_ColorRED},
+ };
+
+ SkPoint hrzCtrl[4][8] = {
+ {{75,30},{125,45},{175,70},{225,20},{275,50},{325,50},{375,5},{425,90}},
+ {{75,150},{125,150},{175,150},{225,150},{275,150},{325,150},{375,150},{425,150}},
+ {{75,250},{125,250},{175,250},{225,250},{275,200},{325,150},{375,250},{425,250}},
+ {{75,350},{125,350},{175,350},{225,350},{275,350},{325,350},{375,350},{425,350}}
+ };
+
+ SkPoint vrtCtrl[6][5] = {
+ {{50,75},{150,75},{250,75},{350,75},{450,75}},
+ {{50,125},{150,125},{250,125},{350,125},{450,125}},
+ {{50,175},{150,175},{220,225},{350,175},{470,225}},
+ {{50,225},{150,225},{220,175},{350,225},{470,155}},
+ {{50,275},{150,275},{250,275},{350,275},{400,305}},
+ {{50,325},{150,325},{250,325},{350,325},{450,325}}
+ };
+
+ static const int kRows = 3;
+ static const int kCols = 4;
+
+ canvas->scale(3, 3);
+ SkPatchGrid grid(kRows, kCols, SkPatchGrid::kColors_VertexType, NULL);
+ for (int i = 0; i < kRows; i++) {
+ for (int j = 0; j < kCols; j++) {
+ SkPoint points[12];
+
+ //set corners
+ points[SkPatchUtils::kTopP0_CubicCtrlPts] = vertices[i][j];
+ points[SkPatchUtils::kTopP3_CubicCtrlPts] = vertices[i][j + 1];
+ points[SkPatchUtils::kBottomP0_CubicCtrlPts] = vertices[i + 1][j];
+ points[SkPatchUtils::kBottomP3_CubicCtrlPts] = vertices[i + 1][j + 1];
+
+ points[SkPatchUtils::kTopP1_CubicCtrlPts] = hrzCtrl[i][j * 2];
+ points[SkPatchUtils::kTopP2_CubicCtrlPts] = hrzCtrl[i][j * 2 + 1];
+ points[SkPatchUtils::kBottomP1_CubicCtrlPts] = hrzCtrl[i + 1][j * 2];
+ points[SkPatchUtils::kBottomP2_CubicCtrlPts] = hrzCtrl[i + 1][j * 2 + 1];
+
+ points[SkPatchUtils::kLeftP1_CubicCtrlPts] = vrtCtrl[i * 2][j];
+ points[SkPatchUtils::kLeftP2_CubicCtrlPts] = vrtCtrl[i * 2 + 1][j];
+ points[SkPatchUtils::kRightP1_CubicCtrlPts] = vrtCtrl[i * 2][j + 1];
+ points[SkPatchUtils::kRightP2_CubicCtrlPts] = vrtCtrl[i * 2 + 1][j + 1];
+
+ SkColor colors[4];
+ colors[0] = cornerColors[i][j];
+ colors[1] = cornerColors[i][j + 1];
+ colors[3] = cornerColors[i + 1][j];
+ colors[2] = cornerColors[i + 1][j + 1];
+
+ grid.setPatch(j, i, points, colors, NULL);
+ }
+ }
+
+ grid.draw(canvas, paint);
+ SkISize dims = grid.getDimensions();
+ for (int y = 0; y < dims.height(); y++) {
+ for (int x = 0; x < dims.width(); x++) {
+ SkPoint cubics[12];
+ grid.getPatch(x, y, cubics, NULL, NULL);
+ draw_control_points(canvas, cubics);
+ }
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+DEF_GM(return SkNEW(SkPatchGridGM); )
+
+}
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index e1cb1a6fd8..c1f527f517 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -127,6 +127,7 @@
'../gm/optimizations.cpp',
'../gm/ovals.cpp',
'../gm/patch.cpp',
+ '../gm/patchgrid.cpp',
'../gm/patheffects.cpp',
'../gm/pathfill.cpp',
'../gm/pathinterior.cpp',
diff --git a/gyp/utils.gypi b/gyp/utils.gypi
index b033573dd9..9156b847c8 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/SkPatchGrid.cpp',
+ '<(skia_src_path)/utils/SkPatchGrid.h',
'<(skia_src_path)/utils/SkPatchUtils.cpp',
'<(skia_src_path)/utils/SkPatchUtils.h',
'<(skia_src_path)/utils/SkPathUtils.cpp',
diff --git a/src/utils/SkPatchGrid.cpp b/src/utils/SkPatchGrid.cpp
new file mode 100644
index 0000000000..b1fea57403
--- /dev/null
+++ b/src/utils/SkPatchGrid.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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 "SkPatchGrid.h"
+#include "SkPatchUtils.h"
+
+SkPatchGrid::SkPatchGrid(int rows, int cols, VertexType flags, SkXfermode* xfer)
+ : fRows(0)
+ , fCols(0)
+ , fModeFlags(kNone_VertexType)
+ , fCornerPts(NULL)
+ , fCornerColors(NULL)
+ , fTexCoords(NULL)
+ , fHrzCtrlPts(NULL)
+ , fVrtCtrlPts(NULL)
+ , fXferMode(NULL) {
+ this->reset(rows, cols, flags, xfer);
+}
+
+SkPatchGrid::~SkPatchGrid() {
+ SkDELETE_ARRAY(fCornerPts);
+ SkDELETE_ARRAY(fCornerColors);
+ SkDELETE_ARRAY(fTexCoords);
+ SkDELETE_ARRAY(fHrzCtrlPts);
+ SkDELETE_ARRAY(fVrtCtrlPts);
+}
+
+bool SkPatchGrid::setPatch(int x, int y, const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4]) {
+ // Check for the passed paramaters to be within the range of the grid dimensions and a valid
+ // pointer for the cubics' control points.
+ if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1 || NULL == cubics) {
+ return false;
+ }
+
+ // setup corners and colors
+ int cornerPos = y * (fCols + 1) + x;
+ fCornerPts[cornerPos] = cubics[SkPatchUtils::kTopP0_CubicCtrlPts];
+ fCornerPts[cornerPos + 1] = cubics[SkPatchUtils::kTopP3_CubicCtrlPts];
+ fCornerPts[cornerPos + (fCols + 1)] = cubics[SkPatchUtils::kBottomP0_CubicCtrlPts];
+ fCornerPts[cornerPos + (fCols + 1) + 1] = cubics[SkPatchUtils::kBottomP3_CubicCtrlPts];
+
+ // set horizontal control points
+ int hrzPos = y * (fCols * 2) + (x * 2);
+ fHrzCtrlPts[hrzPos] = cubics[SkPatchUtils::kTopP1_CubicCtrlPts];
+ fHrzCtrlPts[hrzPos + 1] = cubics[SkPatchUtils::kTopP2_CubicCtrlPts];
+ fHrzCtrlPts[hrzPos + (fCols * 2)] = cubics[SkPatchUtils::kBottomP1_CubicCtrlPts];
+ fHrzCtrlPts[hrzPos + (fCols * 2) + 1] = cubics[SkPatchUtils::kBottomP2_CubicCtrlPts];
+
+ // set vertical control points
+ int vrtPos = (y*2) * (fCols + 1) + x;
+ fVrtCtrlPts[vrtPos] = cubics[SkPatchUtils::kLeftP1_CubicCtrlPts];
+ fVrtCtrlPts[vrtPos + 1] = cubics[SkPatchUtils::kRightP1_CubicCtrlPts];
+ fVrtCtrlPts[vrtPos + (fCols + 1)] = cubics[SkPatchUtils::kLeftP2_CubicCtrlPts];
+ fVrtCtrlPts[vrtPos + (fCols + 1) + 1] = cubics[SkPatchUtils::kRightP2_CubicCtrlPts];
+
+ // set optional values (colors and texture coordinates)
+ if ((fModeFlags & kColors_VertexType) && NULL != colors) {
+ fCornerColors[cornerPos] = colors[0];
+ fCornerColors[cornerPos + 1] = colors[1];
+ fCornerColors[cornerPos + (fCols + 1)] = colors[3];
+ fCornerColors[cornerPos + (fCols + 1) + 1] = colors[2];
+ }
+
+ if ((fModeFlags & kTexs_VertexType) && NULL != texCoords) {
+ fTexCoords[cornerPos] = texCoords[0];
+ fTexCoords[cornerPos + 1] = texCoords[1];
+ fTexCoords[cornerPos + (fCols + 1)] = texCoords[3];
+ fTexCoords[cornerPos + (fCols + 1) + 1] = texCoords[2];
+ }
+
+ return true;
+}
+
+bool SkPatchGrid::getPatch(int x, int y, SkPoint cubics[12], SkColor colors[4],
+ SkPoint texCoords[4]) const {
+
+ if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1 || NULL == cubics) {
+ return false;
+ }
+
+ // set the patch by building the array of points and colors with the corresponding values.
+ int cornerPos = y * (fCols + 1) + x;
+ cubics[SkPatchUtils::kTopP0_CubicCtrlPts] = fCornerPts[cornerPos];
+ cubics[SkPatchUtils::kTopP3_CubicCtrlPts] = fCornerPts[cornerPos + 1];
+ cubics[SkPatchUtils::kBottomP0_CubicCtrlPts] = fCornerPts[cornerPos + (fCols + 1)];
+ cubics[SkPatchUtils::kBottomP3_CubicCtrlPts] = fCornerPts[cornerPos + (fCols + 1) + 1];
+
+ int hrzPos = y * (fCols * 2) + (x * 2);
+ cubics[SkPatchUtils::kTopP1_CubicCtrlPts] = fHrzCtrlPts[hrzPos];
+ cubics[SkPatchUtils::kTopP2_CubicCtrlPts] = fHrzCtrlPts[hrzPos + 1];
+ cubics[SkPatchUtils::kBottomP1_CubicCtrlPts] = fHrzCtrlPts[hrzPos + (fCols * 2)];
+ cubics[SkPatchUtils::kBottomP2_CubicCtrlPts] = fHrzCtrlPts[hrzPos + (fCols * 2) + 1];
+
+ int vrtPos = (y*2) * (fCols + 1) + x;
+ cubics[SkPatchUtils::kLeftP1_CubicCtrlPts] = fVrtCtrlPts[vrtPos];
+ cubics[SkPatchUtils::kRightP1_CubicCtrlPts] = fVrtCtrlPts[vrtPos + 1];
+ cubics[SkPatchUtils::kLeftP2_CubicCtrlPts] = fVrtCtrlPts[vrtPos + (fCols + 1)];
+ cubics[SkPatchUtils::kRightP2_CubicCtrlPts] = fVrtCtrlPts[vrtPos + (fCols + 1) + 1];
+
+ if ((fModeFlags & kColors_VertexType) && NULL != colors) {
+ colors[0] = fCornerColors[cornerPos];
+ colors[1] = fCornerColors[cornerPos + 1];
+ colors[3] = fCornerColors[cornerPos + (fCols + 1)];
+ colors[2] = fCornerColors[cornerPos + (fCols + 1) + 1];
+ }
+
+ if ((fModeFlags & kTexs_VertexType) && NULL != texCoords) {
+ texCoords[0] = fTexCoords[cornerPos];
+ texCoords[1] = fTexCoords[cornerPos + 1];
+ texCoords[3] = fTexCoords[cornerPos + (fCols + 1)];
+ texCoords[2] = fTexCoords[cornerPos + (fCols + 1) + 1];
+ }
+
+ return true;
+}
+
+void SkPatchGrid::reset(int rows, int cols, VertexType flags, SkXfermode* xMode) {
+ SkDELETE_ARRAY(fCornerPts);
+ SkDELETE_ARRAY(fCornerColors);
+ SkDELETE_ARRAY(fTexCoords);
+ SkDELETE_ARRAY(fHrzCtrlPts);
+ SkDELETE_ARRAY(fVrtCtrlPts);
+
+ fCols = cols;
+ fRows = rows;
+ fModeFlags = flags;
+ fXferMode = xMode;
+
+ fCornerPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * (fCols + 1));
+ fHrzCtrlPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * fCols * 2);
+ fVrtCtrlPts = SkNEW_ARRAY(SkPoint, fRows * 2 * (fCols + 1));
+ memset(fCornerPts, 0, (fRows + 1) * (fCols + 1) * sizeof(SkPoint));
+ memset(fHrzCtrlPts, 0, (fRows + 1) * fCols * 2 * sizeof(SkPoint));
+ memset(fVrtCtrlPts, 0, fRows * 2 * (fCols + 1) * sizeof(SkPoint));
+
+ if (fModeFlags & kColors_VertexType) {
+ fCornerColors = SkNEW_ARRAY(SkColor, (fRows + 1) * (fCols + 1));
+ memset(fCornerColors, 0, (fRows + 1) * (fCols + 1) * sizeof(SkColor));
+ }
+
+ if (fModeFlags & kTexs_VertexType) {
+ fTexCoords = SkNEW_ARRAY(SkPoint, (fRows + 1) * (fCols + 1));
+ memset(fTexCoords, 0, (fRows + 1) * (fCols + 1) * sizeof(SkPoint));
+ }
+}
+
+void SkPatchGrid::draw(SkCanvas* canvas, SkPaint& paint) {
+ int* maxCols = SkNEW_ARRAY(int, fCols);
+ int* maxRows = SkNEW_ARRAY(int, fRows);
+ memset(maxCols, 0, fCols * sizeof(int));
+ memset(maxRows, 0, fRows * sizeof(int));
+
+ // Get the maximum level of detail per axis for each row and column
+ for (int y = 0; y < fRows; y++) {
+ for (int x = 0; x < fCols; x++) {
+ SkPoint cubics[12];
+ this->getPatch(x, y, cubics, NULL, NULL);
+ SkMatrix matrix = canvas->getTotalMatrix();
+ SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
+ maxCols[x] = SkMax32(maxCols[x], lod.width());
+ maxRows[y] = SkMax32(maxRows[y], lod.height());
+ }
+ }
+ // Draw the patches by generating their geometry with the maximum level of detail per axis.
+ for (int x = 0; x < fCols; x++) {
+ for (int y = 0; y < fRows; y++) {
+ SkPoint cubics[12];
+ SkPoint texCoords[4];
+ SkColor colors[4];
+ this->getPatch(x, y, cubics, colors, texCoords);
+ SkPatchUtils::VertexData data;
+ SkPatchUtils::getVertexData(&data, cubics,
+ fModeFlags & kColors_VertexType ? colors : NULL,
+ fModeFlags & kTexs_VertexType ? texCoords : NULL,
+ maxCols[x], maxRows[y]);
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount,
+ data.fPoints, data.fTexCoords, data.fColors, fXferMode,
+ data.fIndices, data.fIndexCount, paint);
+ }
+ }
+ SkDELETE_ARRAY(maxCols);
+ SkDELETE_ARRAY(maxRows);
+}
diff --git a/src/utils/SkPatchGrid.h b/src/utils/SkPatchGrid.h
new file mode 100644
index 0000000000..cf90098c68
--- /dev/null
+++ b/src/utils/SkPatchGrid.h
@@ -0,0 +1,144 @@
+/*
+ * 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 SkPatchGrid_DEFINED
+#define SkPatchGrid_DEFINED
+
+#include "SkCanvas.h"
+#include "SkPatchUtils.h"
+#include "SkXfermode.h"
+
+/**
+ * Class that represents a grid of patches. Adjacent patches share their corners and a color is
+ * specified at each one of them. The colors are bilinearly interpolated across the patch.
+ *
+ * This implementation defines a bidimensional array of patches. There are 3 arrays to store the
+ * control points of the patches to avoid storing repeated data since there are several points
+ * shared between adjacent patches.
+ *
+ * The array fCornerPts stores the corner control points of the patches.
+ * The array fHrzPts holds the intermidiate control points of the top and bottom curves of a patch.
+ * The array fVrtPts holds the intermidiate control points of the left and right curves of a patch.
+ * The array fCornerColors holds the corner colors in the same format as fCornerPts.
+ * The array fTexCoords holds the texture coordinates in the same format as fCornerpts.
+ *
+ * fCornerPts fHrzPts fVrtPts
+ * -------------- ------------------- --------------
+ * | C0 | C1 | C2 | | H0 | H1 | H2 | H3 | | V0 | V1 | V2 |
+ * -------------- ------------------ ---------------
+ * | C3 | C4 | C5 | | H4 | H5 | H6 | H7 | | V4 | V5 | V6 |
+ * -------------- ------------------- --------------
+ * | C6 | C7 | C8 | | H8 | H9 | H10| H11| | V6 | V7 | V8 |
+ * -------------- ------------------- --------------
+ * | V9 | V10| V11|
+ * --------------
+ *
+ * With the above configuration we would have a 2x2 grid of patches:
+ * H0 H1 H2 H3
+ * / \/ \
+ * C0-------C1-------C2
+ * /| | |\
+ * v0 | v1 | v2
+ * v3 | V4 | v5
+ * \| | |/
+ * C3-H4-H5-C4-H6-H7-C5
+ * /| | |\
+ * v6 | v7 | v8
+ * v9 | v10 | v11
+ * \| | |/
+ * C6-------C7-------C8
+ * \ / \ /
+ * H8 H9 H10 H11
+ *
+ * When trying to get a patch at a certain position it justs builds it with the corresponding
+ * points.
+ * When adding a patch it tries to add the points at their corresponding position trying to comply
+ * with the adjacent points or overwriting them.
+ *
+ * Based the idea on the SVG2 spec for mesh gradients in which a grid of patches is build as in the
+ * the following example:
+ * <meshGradient x="100" y="100">
+ * <meshRow>
+ * <meshPatch>
+ * <stop .../>
+ * Up to four stops in first patch. See details below.
+ * </meshPatch>
+ * <meshPatch>
+ * Any number of meshPatches in row.
+ * </meshPatch>
+ * </meshRow>
+ * <meshRow>
+ * Any number of meshRows, each with the same number of meshPatches as in the first row.
+ * </meshRow>
+ * </meshGradient>
+ */
+class SkPatchGrid {
+
+public:
+
+ enum VertexType {
+ kNone_VertexType = 0X00,
+ kColors_VertexType = 0x01,
+ kTexs_VertexType = 0x02,
+ kColorsAndTexs_VertexType = 0x03
+ };
+
+ SkPatchGrid(int rows = 0, int cols = 0, VertexType flags = kNone_VertexType,
+ SkXfermode* xfer = NULL);
+
+ ~SkPatchGrid();
+
+ /**
+ * Add a patch at location (x,y) overwriting the previous patch and shared points so they
+ * mantain C0 connectivity.
+ * The control points must be passed in a clockwise order starting at the top left corner.
+ * The colors and texCoords are the values at the corners of the patch which will be bilerp
+ * across it, they must also be in counterclockwise order starting at the top left corner.
+ */
+ bool setPatch(int x, int y, const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4]);
+
+ /**
+ * Get patch at location (x,y). If cubics, colors or texCoords is not NULL it sets patch's
+ * array with its corresponding values.
+ * The function returns false if the cubics parameter is NULL or if the (x,y) coordinates are
+ * not within the range of the grid.
+ */
+ bool getPatch(int x, int y, SkPoint cubics[12], SkColor colors[4], SkPoint texCoords[4]) const;
+
+ /**
+ * Resets the grid of patches to contain rows and cols of patches.
+ */
+ void reset(int rows, int cols, VertexType flags, SkXfermode* xMode);
+
+ /**
+ * Draws the grid of patches. The patches are drawn starting at patch (0,0) drawing columns, so
+ * for a 2x2 grid the order would be (0,0)->(0,1)->(1,0)->(1,1). The order follows the order
+ * of the parametric coordinates of the coons patch.
+ */
+ void draw(SkCanvas* canvas, SkPaint& paint);
+
+ /**
+ * Get the dimensions of the grid of patches.
+ */
+ SkISize getDimensions() const {
+ return SkISize::Make(fCols, fRows);
+ }
+
+private:
+ int fRows, fCols;
+ VertexType fModeFlags;
+ SkPoint* fCornerPts;
+ SkColor* fCornerColors;
+ SkPoint* fTexCoords;
+ SkPoint* fHrzCtrlPts;
+ SkPoint* fVrtCtrlPts;
+ SkXfermode* fXferMode;
+};
+
+
+#endif