Home | History | Annotate | Download | only in utils
      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