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