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) 15 , fCornerPts(NULL) 16 , fCornerColors(NULL) 17 , fTexCoords(NULL) 18 , fHrzCtrlPts(NULL) 19 , fVrtCtrlPts(NULL) 20 , fXferMode(NULL) { 21 this->reset(rows, cols, flags, xfer); 22 } 23 24 SkPatchGrid::~SkPatchGrid() { 25 SkDELETE_ARRAY(fCornerPts); 26 SkDELETE_ARRAY(fCornerColors); 27 SkDELETE_ARRAY(fTexCoords); 28 SkDELETE_ARRAY(fHrzCtrlPts); 29 SkDELETE_ARRAY(fVrtCtrlPts); 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. 36 if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1 || NULL == cubics) { 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) 62 if ((fModeFlags & kColors_VertexType) && colors) { 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 69 if ((fModeFlags & kTexs_VertexType) && texCoords) { 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 82 if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1 || NULL == cubics) { 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 105 if ((fModeFlags & kColors_VertexType) && colors) { 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 112 if ((fModeFlags & kTexs_VertexType) && texCoords) { 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) { 123 SkDELETE_ARRAY(fCornerPts); 124 SkDELETE_ARRAY(fCornerColors); 125 SkDELETE_ARRAY(fTexCoords); 126 SkDELETE_ARRAY(fHrzCtrlPts); 127 SkDELETE_ARRAY(fVrtCtrlPts); 128 129 fCols = cols; 130 fRows = rows; 131 fModeFlags = flags; 132 fXferMode = xMode; 133 134 fCornerPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * (fCols + 1)); 135 fHrzCtrlPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * fCols * 2); 136 fVrtCtrlPts = SkNEW_ARRAY(SkPoint, fRows * 2 * (fCols + 1)); 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) { 142 fCornerColors = SkNEW_ARRAY(SkColor, (fRows + 1) * (fCols + 1)); 143 memset(fCornerColors, 0, (fRows + 1) * (fCols + 1) * sizeof(SkColor)); 144 } 145 146 if (fModeFlags & kTexs_VertexType) { 147 fTexCoords = SkNEW_ARRAY(SkPoint, (fRows + 1) * (fCols + 1)); 148 memset(fTexCoords, 0, (fRows + 1) * (fCols + 1) * sizeof(SkPoint)); 149 } 150 } 151 152 void SkPatchGrid::draw(SkCanvas* canvas, SkPaint& paint) { 153 int* maxCols = SkNEW_ARRAY(int, fCols); 154 int* maxRows = SkNEW_ARRAY(int, fRows); 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]; 162 this->getPatch(x, y, cubics, NULL, NULL); 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; 177 if (SkPatchUtils::getVertexData(&data, cubics, 178 fModeFlags & kColors_VertexType ? colors : NULL, 179 fModeFlags & kTexs_VertexType ? texCoords : NULL, 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 } 185 } 186 } 187 SkDELETE_ARRAY(maxCols); 188 SkDELETE_ARRAY(maxRows); 189 } 190