1cc03adb90901d226e8b0252a187b19a68fabcc42dandov/*
2cc03adb90901d226e8b0252a187b19a68fabcc42dandov * Copyright 2014 Google Inc.
3cc03adb90901d226e8b0252a187b19a68fabcc42dandov *
4cc03adb90901d226e8b0252a187b19a68fabcc42dandov * Use of this source code is governed by a BSD-style license that can be
5cc03adb90901d226e8b0252a187b19a68fabcc42dandov * found in the LICENSE file.
6cc03adb90901d226e8b0252a187b19a68fabcc42dandov */
7cc03adb90901d226e8b0252a187b19a68fabcc42dandov
8cc03adb90901d226e8b0252a187b19a68fabcc42dandov#include "SkPatchGrid.h"
9cc03adb90901d226e8b0252a187b19a68fabcc42dandov#include "SkPatchUtils.h"
10cc03adb90901d226e8b0252a187b19a68fabcc42dandov
11cc03adb90901d226e8b0252a187b19a68fabcc42dandovSkPatchGrid::SkPatchGrid(int rows, int cols, VertexType flags, SkXfermode* xfer)
12cc03adb90901d226e8b0252a187b19a68fabcc42dandov    : fRows(0)
13cc03adb90901d226e8b0252a187b19a68fabcc42dandov    , fCols(0)
14cc03adb90901d226e8b0252a187b19a68fabcc42dandov    , fModeFlags(kNone_VertexType)
15cc03adb90901d226e8b0252a187b19a68fabcc42dandov    , fCornerPts(NULL)
16cc03adb90901d226e8b0252a187b19a68fabcc42dandov    , fCornerColors(NULL)
17cc03adb90901d226e8b0252a187b19a68fabcc42dandov    , fTexCoords(NULL)
18cc03adb90901d226e8b0252a187b19a68fabcc42dandov    , fHrzCtrlPts(NULL)
19cc03adb90901d226e8b0252a187b19a68fabcc42dandov    , fVrtCtrlPts(NULL)
20cc03adb90901d226e8b0252a187b19a68fabcc42dandov    , fXferMode(NULL) {
21cc03adb90901d226e8b0252a187b19a68fabcc42dandov        this->reset(rows, cols, flags, xfer);
22cc03adb90901d226e8b0252a187b19a68fabcc42dandov}
23cc03adb90901d226e8b0252a187b19a68fabcc42dandov
24cc03adb90901d226e8b0252a187b19a68fabcc42dandovSkPatchGrid::~SkPatchGrid() {
25cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(fCornerPts);
26cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(fCornerColors);
27cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(fTexCoords);
28cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(fHrzCtrlPts);
29cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(fVrtCtrlPts);
30cc03adb90901d226e8b0252a187b19a68fabcc42dandov}
31cc03adb90901d226e8b0252a187b19a68fabcc42dandov
32cc03adb90901d226e8b0252a187b19a68fabcc42dandovbool SkPatchGrid::setPatch(int x, int y, const SkPoint cubics[12], const SkColor colors[4],
33cc03adb90901d226e8b0252a187b19a68fabcc42dandov                           const SkPoint texCoords[4]) {
34cc03adb90901d226e8b0252a187b19a68fabcc42dandov    // Check for the passed paramaters to be within the range of the grid dimensions and a valid
35cc03adb90901d226e8b0252a187b19a68fabcc42dandov    // pointer for the cubics' control points.
36cc03adb90901d226e8b0252a187b19a68fabcc42dandov    if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1 || NULL == cubics) {
37cc03adb90901d226e8b0252a187b19a68fabcc42dandov        return false;
38cc03adb90901d226e8b0252a187b19a68fabcc42dandov    }
39cc03adb90901d226e8b0252a187b19a68fabcc42dandov
40cc03adb90901d226e8b0252a187b19a68fabcc42dandov    // setup corners and colors
41cc03adb90901d226e8b0252a187b19a68fabcc42dandov    int cornerPos = y * (fCols + 1) + x;
42cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fCornerPts[cornerPos] = cubics[SkPatchUtils::kTopP0_CubicCtrlPts];
43cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fCornerPts[cornerPos + 1] = cubics[SkPatchUtils::kTopP3_CubicCtrlPts];
44cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fCornerPts[cornerPos + (fCols + 1)] = cubics[SkPatchUtils::kBottomP0_CubicCtrlPts];
45cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fCornerPts[cornerPos + (fCols + 1) + 1] = cubics[SkPatchUtils::kBottomP3_CubicCtrlPts];
46cc03adb90901d226e8b0252a187b19a68fabcc42dandov
47cc03adb90901d226e8b0252a187b19a68fabcc42dandov    // set horizontal control points
48cc03adb90901d226e8b0252a187b19a68fabcc42dandov    int hrzPos = y * (fCols * 2) + (x * 2);
49cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fHrzCtrlPts[hrzPos] = cubics[SkPatchUtils::kTopP1_CubicCtrlPts];
50cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fHrzCtrlPts[hrzPos + 1] = cubics[SkPatchUtils::kTopP2_CubicCtrlPts];
51cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fHrzCtrlPts[hrzPos + (fCols * 2)] = cubics[SkPatchUtils::kBottomP1_CubicCtrlPts];
52cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fHrzCtrlPts[hrzPos + (fCols * 2) + 1] = cubics[SkPatchUtils::kBottomP2_CubicCtrlPts];
53cc03adb90901d226e8b0252a187b19a68fabcc42dandov
54cc03adb90901d226e8b0252a187b19a68fabcc42dandov    // set vertical control points
55cc03adb90901d226e8b0252a187b19a68fabcc42dandov    int vrtPos = (y*2) * (fCols + 1) + x;
56cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fVrtCtrlPts[vrtPos] = cubics[SkPatchUtils::kLeftP1_CubicCtrlPts];
57cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fVrtCtrlPts[vrtPos + 1] = cubics[SkPatchUtils::kRightP1_CubicCtrlPts];
58cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fVrtCtrlPts[vrtPos + (fCols + 1)] = cubics[SkPatchUtils::kLeftP2_CubicCtrlPts];
59cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fVrtCtrlPts[vrtPos + (fCols + 1) + 1] = cubics[SkPatchUtils::kRightP2_CubicCtrlPts];
60cc03adb90901d226e8b0252a187b19a68fabcc42dandov
61cc03adb90901d226e8b0252a187b19a68fabcc42dandov    // set optional values (colors and texture coordinates)
6249f085dddff10473b6ebf832a974288300224e60bsalomon    if ((fModeFlags & kColors_VertexType)  && colors) {
63cc03adb90901d226e8b0252a187b19a68fabcc42dandov        fCornerColors[cornerPos] = colors[0];
64cc03adb90901d226e8b0252a187b19a68fabcc42dandov        fCornerColors[cornerPos + 1] = colors[1];
65cc03adb90901d226e8b0252a187b19a68fabcc42dandov        fCornerColors[cornerPos + (fCols + 1)] = colors[3];
66cc03adb90901d226e8b0252a187b19a68fabcc42dandov        fCornerColors[cornerPos + (fCols + 1) + 1] = colors[2];
67cc03adb90901d226e8b0252a187b19a68fabcc42dandov    }
68cc03adb90901d226e8b0252a187b19a68fabcc42dandov
6949f085dddff10473b6ebf832a974288300224e60bsalomon    if ((fModeFlags & kTexs_VertexType) && texCoords) {
70cc03adb90901d226e8b0252a187b19a68fabcc42dandov        fTexCoords[cornerPos] = texCoords[0];
71cc03adb90901d226e8b0252a187b19a68fabcc42dandov        fTexCoords[cornerPos + 1] = texCoords[1];
72cc03adb90901d226e8b0252a187b19a68fabcc42dandov        fTexCoords[cornerPos + (fCols + 1)] = texCoords[3];
73cc03adb90901d226e8b0252a187b19a68fabcc42dandov        fTexCoords[cornerPos + (fCols + 1) + 1] = texCoords[2];
74cc03adb90901d226e8b0252a187b19a68fabcc42dandov    }
75cc03adb90901d226e8b0252a187b19a68fabcc42dandov
76cc03adb90901d226e8b0252a187b19a68fabcc42dandov    return true;
77cc03adb90901d226e8b0252a187b19a68fabcc42dandov}
78cc03adb90901d226e8b0252a187b19a68fabcc42dandov
79cc03adb90901d226e8b0252a187b19a68fabcc42dandovbool SkPatchGrid::getPatch(int x, int y, SkPoint cubics[12], SkColor colors[4],
80cc03adb90901d226e8b0252a187b19a68fabcc42dandov                           SkPoint texCoords[4]) const {
81cc03adb90901d226e8b0252a187b19a68fabcc42dandov
82cc03adb90901d226e8b0252a187b19a68fabcc42dandov    if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1 || NULL == cubics) {
83cc03adb90901d226e8b0252a187b19a68fabcc42dandov        return false;
84cc03adb90901d226e8b0252a187b19a68fabcc42dandov    }
85cc03adb90901d226e8b0252a187b19a68fabcc42dandov
86cc03adb90901d226e8b0252a187b19a68fabcc42dandov    // set the patch by building the array of points and colors with the corresponding values.
87cc03adb90901d226e8b0252a187b19a68fabcc42dandov    int cornerPos = y * (fCols + 1) + x;
88cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kTopP0_CubicCtrlPts] = fCornerPts[cornerPos];
89cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kTopP3_CubicCtrlPts] = fCornerPts[cornerPos + 1];
90cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kBottomP0_CubicCtrlPts] = fCornerPts[cornerPos + (fCols + 1)];
91cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kBottomP3_CubicCtrlPts] = fCornerPts[cornerPos + (fCols + 1) + 1];
92cc03adb90901d226e8b0252a187b19a68fabcc42dandov
93cc03adb90901d226e8b0252a187b19a68fabcc42dandov    int hrzPos = y * (fCols * 2) + (x * 2);
94cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kTopP1_CubicCtrlPts] = fHrzCtrlPts[hrzPos];
95cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kTopP2_CubicCtrlPts] = fHrzCtrlPts[hrzPos + 1];
96cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kBottomP1_CubicCtrlPts] = fHrzCtrlPts[hrzPos + (fCols * 2)];
97cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kBottomP2_CubicCtrlPts] = fHrzCtrlPts[hrzPos + (fCols * 2) + 1];
98cc03adb90901d226e8b0252a187b19a68fabcc42dandov
99cc03adb90901d226e8b0252a187b19a68fabcc42dandov    int vrtPos = (y*2) * (fCols + 1) + x;
100cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kLeftP1_CubicCtrlPts] = fVrtCtrlPts[vrtPos];
101cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kRightP1_CubicCtrlPts] = fVrtCtrlPts[vrtPos + 1];
102cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kLeftP2_CubicCtrlPts] = fVrtCtrlPts[vrtPos + (fCols + 1)];
103cc03adb90901d226e8b0252a187b19a68fabcc42dandov    cubics[SkPatchUtils::kRightP2_CubicCtrlPts] = fVrtCtrlPts[vrtPos + (fCols + 1) + 1];
104cc03adb90901d226e8b0252a187b19a68fabcc42dandov
10549f085dddff10473b6ebf832a974288300224e60bsalomon    if ((fModeFlags & kColors_VertexType)  && colors) {
106cc03adb90901d226e8b0252a187b19a68fabcc42dandov        colors[0] = fCornerColors[cornerPos];
107cc03adb90901d226e8b0252a187b19a68fabcc42dandov        colors[1] = fCornerColors[cornerPos + 1];
108cc03adb90901d226e8b0252a187b19a68fabcc42dandov        colors[3] = fCornerColors[cornerPos + (fCols + 1)];
109cc03adb90901d226e8b0252a187b19a68fabcc42dandov        colors[2] = fCornerColors[cornerPos + (fCols + 1) + 1];
110cc03adb90901d226e8b0252a187b19a68fabcc42dandov    }
111cc03adb90901d226e8b0252a187b19a68fabcc42dandov
11249f085dddff10473b6ebf832a974288300224e60bsalomon    if ((fModeFlags & kTexs_VertexType)  && texCoords) {
113cc03adb90901d226e8b0252a187b19a68fabcc42dandov        texCoords[0] = fTexCoords[cornerPos];
114cc03adb90901d226e8b0252a187b19a68fabcc42dandov        texCoords[1] = fTexCoords[cornerPos + 1];
115cc03adb90901d226e8b0252a187b19a68fabcc42dandov        texCoords[3] = fTexCoords[cornerPos + (fCols + 1)];
116cc03adb90901d226e8b0252a187b19a68fabcc42dandov        texCoords[2] = fTexCoords[cornerPos + (fCols + 1) + 1];
117cc03adb90901d226e8b0252a187b19a68fabcc42dandov    }
118cc03adb90901d226e8b0252a187b19a68fabcc42dandov
119cc03adb90901d226e8b0252a187b19a68fabcc42dandov    return true;
120cc03adb90901d226e8b0252a187b19a68fabcc42dandov}
121cc03adb90901d226e8b0252a187b19a68fabcc42dandov
122cc03adb90901d226e8b0252a187b19a68fabcc42dandovvoid SkPatchGrid::reset(int rows, int cols, VertexType flags, SkXfermode* xMode) {
123cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(fCornerPts);
124cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(fCornerColors);
125cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(fTexCoords);
126cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(fHrzCtrlPts);
127cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(fVrtCtrlPts);
128cc03adb90901d226e8b0252a187b19a68fabcc42dandov
129cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fCols = cols;
130cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fRows = rows;
131cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fModeFlags = flags;
132cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fXferMode = xMode;
133cc03adb90901d226e8b0252a187b19a68fabcc42dandov
134cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fCornerPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * (fCols + 1));
135cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fHrzCtrlPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * fCols * 2);
136cc03adb90901d226e8b0252a187b19a68fabcc42dandov    fVrtCtrlPts = SkNEW_ARRAY(SkPoint, fRows * 2 * (fCols + 1));
137cc03adb90901d226e8b0252a187b19a68fabcc42dandov    memset(fCornerPts, 0, (fRows + 1) * (fCols + 1) * sizeof(SkPoint));
138cc03adb90901d226e8b0252a187b19a68fabcc42dandov    memset(fHrzCtrlPts, 0, (fRows + 1) * fCols * 2 * sizeof(SkPoint));
139cc03adb90901d226e8b0252a187b19a68fabcc42dandov    memset(fVrtCtrlPts, 0, fRows * 2 * (fCols + 1) * sizeof(SkPoint));
140cc03adb90901d226e8b0252a187b19a68fabcc42dandov
141cc03adb90901d226e8b0252a187b19a68fabcc42dandov    if (fModeFlags & kColors_VertexType) {
142cc03adb90901d226e8b0252a187b19a68fabcc42dandov        fCornerColors = SkNEW_ARRAY(SkColor, (fRows + 1) * (fCols + 1));
143cc03adb90901d226e8b0252a187b19a68fabcc42dandov        memset(fCornerColors, 0, (fRows + 1) * (fCols + 1) * sizeof(SkColor));
144cc03adb90901d226e8b0252a187b19a68fabcc42dandov    }
145cc03adb90901d226e8b0252a187b19a68fabcc42dandov
146cc03adb90901d226e8b0252a187b19a68fabcc42dandov    if (fModeFlags & kTexs_VertexType) {
147cc03adb90901d226e8b0252a187b19a68fabcc42dandov        fTexCoords = SkNEW_ARRAY(SkPoint, (fRows + 1) * (fCols + 1));
148cc03adb90901d226e8b0252a187b19a68fabcc42dandov        memset(fTexCoords, 0, (fRows + 1) * (fCols + 1) * sizeof(SkPoint));
149cc03adb90901d226e8b0252a187b19a68fabcc42dandov    }
150cc03adb90901d226e8b0252a187b19a68fabcc42dandov}
151cc03adb90901d226e8b0252a187b19a68fabcc42dandov
152cc03adb90901d226e8b0252a187b19a68fabcc42dandovvoid SkPatchGrid::draw(SkCanvas* canvas, SkPaint& paint) {
153cc03adb90901d226e8b0252a187b19a68fabcc42dandov    int* maxCols = SkNEW_ARRAY(int, fCols);
154cc03adb90901d226e8b0252a187b19a68fabcc42dandov    int* maxRows = SkNEW_ARRAY(int, fRows);
155cc03adb90901d226e8b0252a187b19a68fabcc42dandov    memset(maxCols, 0, fCols * sizeof(int));
156cc03adb90901d226e8b0252a187b19a68fabcc42dandov    memset(maxRows, 0, fRows * sizeof(int));
157cc03adb90901d226e8b0252a187b19a68fabcc42dandov
158cc03adb90901d226e8b0252a187b19a68fabcc42dandov    // Get the maximum level of detail per axis for each row and column
159cc03adb90901d226e8b0252a187b19a68fabcc42dandov    for (int y = 0; y < fRows; y++) {
160cc03adb90901d226e8b0252a187b19a68fabcc42dandov        for (int x = 0; x < fCols; x++) {
161cc03adb90901d226e8b0252a187b19a68fabcc42dandov            SkPoint cubics[12];
162cc03adb90901d226e8b0252a187b19a68fabcc42dandov            this->getPatch(x, y, cubics, NULL, NULL);
163cc03adb90901d226e8b0252a187b19a68fabcc42dandov            SkMatrix matrix = canvas->getTotalMatrix();
164cc03adb90901d226e8b0252a187b19a68fabcc42dandov            SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
165cc03adb90901d226e8b0252a187b19a68fabcc42dandov            maxCols[x] = SkMax32(maxCols[x], lod.width());
166cc03adb90901d226e8b0252a187b19a68fabcc42dandov            maxRows[y] = SkMax32(maxRows[y], lod.height());
167cc03adb90901d226e8b0252a187b19a68fabcc42dandov        }
168cc03adb90901d226e8b0252a187b19a68fabcc42dandov    }
169cc03adb90901d226e8b0252a187b19a68fabcc42dandov    // Draw the patches by generating their geometry with the maximum level of detail per axis.
170cc03adb90901d226e8b0252a187b19a68fabcc42dandov    for (int x = 0; x < fCols; x++) {
171cc03adb90901d226e8b0252a187b19a68fabcc42dandov        for (int y = 0; y < fRows; y++) {
172cc03adb90901d226e8b0252a187b19a68fabcc42dandov            SkPoint cubics[12];
173cc03adb90901d226e8b0252a187b19a68fabcc42dandov            SkPoint texCoords[4];
174cc03adb90901d226e8b0252a187b19a68fabcc42dandov            SkColor colors[4];
175cc03adb90901d226e8b0252a187b19a68fabcc42dandov            this->getPatch(x, y, cubics, colors, texCoords);
176cc03adb90901d226e8b0252a187b19a68fabcc42dandov            SkPatchUtils::VertexData data;
1777e5598a004d0aceb630707053566bee523feea66dandov            if (SkPatchUtils::getVertexData(&data, cubics,
1787e5598a004d0aceb630707053566bee523feea66dandov                                            fModeFlags & kColors_VertexType ? colors : NULL,
1797e5598a004d0aceb630707053566bee523feea66dandov                                            fModeFlags & kTexs_VertexType ? texCoords : NULL,
1807e5598a004d0aceb630707053566bee523feea66dandov                                            maxCols[x], maxRows[y])) {
1817e5598a004d0aceb630707053566bee523feea66dandov                canvas->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount,
1827e5598a004d0aceb630707053566bee523feea66dandov                                     data.fPoints, data.fTexCoords, data.fColors, fXferMode,
1837e5598a004d0aceb630707053566bee523feea66dandov                                     data.fIndices, data.fIndexCount, paint);
1847e5598a004d0aceb630707053566bee523feea66dandov            }
185cc03adb90901d226e8b0252a187b19a68fabcc42dandov        }
186cc03adb90901d226e8b0252a187b19a68fabcc42dandov    }
187cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(maxCols);
188cc03adb90901d226e8b0252a187b19a68fabcc42dandov    SkDELETE_ARRAY(maxRows);
189cc03adb90901d226e8b0252a187b19a68fabcc42dandov}
190