/* * 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) : fRows(0) , fCols(0) , fModeFlags(kNone_VertexType) , fCornerPts(nullptr) , fCornerColors(nullptr) , fTexCoords(nullptr) , fHrzCtrlPts(nullptr) , fVrtCtrlPts(nullptr) { this->reset(rows, cols, flags, SkBlendMode::kModulate); } 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, SkBlendMode blendmode) { delete[] fCornerPts; delete[] fCornerColors; delete[] fTexCoords; delete[] fHrzCtrlPts; delete[] fVrtCtrlPts; fCols = cols; fRows = rows; fModeFlags = flags; fBlendMode = blendmode; 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, fBlendMode, data.fIndices, data.fIndexCount, paint); } } } delete[] maxCols; delete[] maxRows; }