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