| /* |
| * 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(nullptr) |
| , fCornerColors(nullptr) |
| , fTexCoords(nullptr) |
| , fHrzCtrlPts(nullptr) |
| , fVrtCtrlPts(nullptr) |
| , fXferMode(nullptr) { |
| this->reset(rows, cols, flags, xfer); |
| } |
| |
| SkPatchGrid::~SkPatchGrid() { |
| delete[] fCornerPts; |
| delete[] fCornerColors; |
| delete[] fTexCoords; |
| delete[] fHrzCtrlPts; |
| delete[] 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 || nullptr == 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) && 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) && 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 || nullptr == 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) && 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) && 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) { |
| delete[] fCornerPts; |
| delete[] fCornerColors; |
| delete[] fTexCoords; |
| delete[] fHrzCtrlPts; |
| delete[] fVrtCtrlPts; |
| |
| fCols = cols; |
| fRows = rows; |
| fModeFlags = flags; |
| fXferMode = xMode; |
| |
| fCornerPts = new SkPoint[(fRows + 1) * (fCols + 1)]; |
| fHrzCtrlPts = new SkPoint[(fRows + 1) * fCols * 2]; |
| fVrtCtrlPts = new 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 = new SkColor[(fRows + 1) * (fCols + 1)]; |
| memset(fCornerColors, 0, (fRows + 1) * (fCols + 1) * sizeof(SkColor)); |
| } |
| |
| if (fModeFlags & kTexs_VertexType) { |
| fTexCoords = new SkPoint[(fRows + 1) * (fCols + 1)]; |
| memset(fTexCoords, 0, (fRows + 1) * (fCols + 1) * sizeof(SkPoint)); |
| } |
| } |
| |
| void SkPatchGrid::draw(SkCanvas* canvas, SkPaint& paint) { |
| int* maxCols = new int[fCols]; |
| int* maxRows = new 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, nullptr, nullptr); |
| 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; |
| if (SkPatchUtils::getVertexData(&data, cubics, |
| fModeFlags & kColors_VertexType ? colors : nullptr, |
| fModeFlags & kTexs_VertexType ? texCoords : nullptr, |
| maxCols[x], maxRows[y])) { |
| canvas->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount, |
| data.fPoints, data.fTexCoords, data.fColors, fXferMode, |
| data.fIndices, data.fIndexCount, paint); |
| } |
| } |
| } |
| delete[] maxCols; |
| delete[] maxRows; |
| } |