Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "OpenGLRenderer"
     18 
     19 #include <cmath>
     20 
     21 #include <utils/Log.h>
     22 
     23 #include "Caches.h"
     24 #include "Patch.h"
     25 #include "Properties.h"
     26 #include "UvMapper.h"
     27 
     28 namespace android {
     29 namespace uirenderer {
     30 
     31 ///////////////////////////////////////////////////////////////////////////////
     32 // Constructors/destructor
     33 ///////////////////////////////////////////////////////////////////////////////
     34 
     35 Patch::Patch(): vertices(NULL), verticesCount(0), indexCount(0), hasEmptyQuads(false) {
     36 }
     37 
     38 Patch::~Patch() {
     39     delete[] vertices;
     40 }
     41 
     42 ///////////////////////////////////////////////////////////////////////////////
     43 // Vertices management
     44 ///////////////////////////////////////////////////////////////////////////////
     45 
     46 uint32_t Patch::getSize() const {
     47     return verticesCount * sizeof(TextureVertex);
     48 }
     49 
     50 TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight,
     51         float width, float height, const Res_png_9patch* patch) {
     52     UvMapper mapper;
     53     return createMesh(bitmapWidth, bitmapHeight, width, height, mapper, patch);
     54 }
     55 
     56 TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight,
     57         float width, float height, const UvMapper& mapper, const Res_png_9patch* patch) {
     58     if (vertices) return vertices;
     59 
     60     int8_t emptyQuads = 0;
     61     mColors = patch->getColors();
     62 
     63     const int8_t numColors = patch->numColors;
     64     if (uint8_t(numColors) < sizeof(uint32_t) * 4) {
     65         for (int8_t i = 0; i < numColors; i++) {
     66             if (mColors[i] == 0x0) {
     67                 emptyQuads++;
     68             }
     69         }
     70     }
     71 
     72     hasEmptyQuads = emptyQuads > 0;
     73 
     74     uint32_t xCount = patch->numXDivs;
     75     uint32_t yCount = patch->numYDivs;
     76 
     77     uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 4;
     78     if (maxVertices == 0) return NULL;
     79 
     80     TextureVertex* tempVertices = new TextureVertex[maxVertices];
     81     TextureVertex* vertex = tempVertices;
     82 
     83     const int32_t* xDivs = patch->getXDivs();
     84     const int32_t* yDivs = patch->getYDivs();
     85 
     86     const uint32_t xStretchCount = (xCount + 1) >> 1;
     87     const uint32_t yStretchCount = (yCount + 1) >> 1;
     88 
     89     float stretchX = 0.0f;
     90     float stretchY = 0.0f;
     91 
     92     float rescaleX = 1.0f;
     93     float rescaleY = 1.0f;
     94 
     95     if (xStretchCount > 0) {
     96         uint32_t stretchSize = 0;
     97         for (uint32_t i = 1; i < xCount; i += 2) {
     98             stretchSize += xDivs[i] - xDivs[i - 1];
     99         }
    100         const float xStretchTex = stretchSize;
    101         const float fixed = bitmapWidth - stretchSize;
    102         const float xStretch = fmaxf(width - fixed, 0.0f);
    103         stretchX = xStretch / xStretchTex;
    104         rescaleX = fixed == 0.0f ? 0.0f : fminf(fmaxf(width, 0.0f) / fixed, 1.0f);
    105     }
    106 
    107     if (yStretchCount > 0) {
    108         uint32_t stretchSize = 0;
    109         for (uint32_t i = 1; i < yCount; i += 2) {
    110             stretchSize += yDivs[i] - yDivs[i - 1];
    111         }
    112         const float yStretchTex = stretchSize;
    113         const float fixed = bitmapHeight - stretchSize;
    114         const float yStretch = fmaxf(height - fixed, 0.0f);
    115         stretchY = yStretch / yStretchTex;
    116         rescaleY = fixed == 0.0f ? 0.0f : fminf(fmaxf(height, 0.0f) / fixed, 1.0f);
    117     }
    118 
    119     uint32_t quadCount = 0;
    120 
    121     float previousStepY = 0.0f;
    122 
    123     float y1 = 0.0f;
    124     float y2 = 0.0f;
    125     float v1 = 0.0f;
    126 
    127     mUvMapper = mapper;
    128 
    129     for (uint32_t i = 0; i < yCount; i++) {
    130         float stepY = yDivs[i];
    131         const float segment = stepY - previousStepY;
    132 
    133         if (i & 1) {
    134             y2 = y1 + floorf(segment * stretchY + 0.5f);
    135         } else {
    136             y2 = y1 + segment * rescaleY;
    137         }
    138 
    139         float vOffset = y1 == y2 ? 0.0f : 0.5 - (0.5 * segment / (y2 - y1));
    140         float v2 = fmax(0.0f, stepY - vOffset) / bitmapHeight;
    141         v1 += vOffset / bitmapHeight;
    142 
    143         if (stepY > 0.0f) {
    144             generateRow(xDivs, xCount, vertex, y1, y2, v1, v2, stretchX, rescaleX,
    145                     width, bitmapWidth, quadCount);
    146         }
    147 
    148         y1 = y2;
    149         v1 = stepY / bitmapHeight;
    150 
    151         previousStepY = stepY;
    152     }
    153 
    154     if (previousStepY != bitmapHeight) {
    155         y2 = height;
    156         generateRow(xDivs, xCount, vertex, y1, y2, v1, 1.0f, stretchX, rescaleX,
    157                 width, bitmapWidth, quadCount);
    158     }
    159 
    160     if (verticesCount == maxVertices) {
    161         vertices = tempVertices;
    162     } else {
    163         vertices = new TextureVertex[verticesCount];
    164         memcpy(vertices, tempVertices, verticesCount * sizeof(TextureVertex));
    165         delete[] tempVertices;
    166     }
    167 
    168     return vertices;
    169 }
    170 
    171 void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
    172         float y1, float y2, float v1, float v2, float stretchX, float rescaleX,
    173         float width, float bitmapWidth, uint32_t& quadCount) {
    174     float previousStepX = 0.0f;
    175 
    176     float x1 = 0.0f;
    177     float x2 = 0.0f;
    178     float u1 = 0.0f;
    179 
    180     // Generate the row quad by quad
    181     for (uint32_t i = 0; i < xCount; i++) {
    182         float stepX = xDivs[i];
    183         const float segment = stepX - previousStepX;
    184 
    185         if (i & 1) {
    186             x2 = x1 + floorf(segment * stretchX + 0.5f);
    187         } else {
    188             x2 = x1 + segment * rescaleX;
    189         }
    190 
    191         float uOffset = x1 == x2 ? 0.0f : 0.5 - (0.5 * segment / (x2 - x1));
    192         float u2 = fmax(0.0f, stepX - uOffset) / bitmapWidth;
    193         u1 += uOffset / bitmapWidth;
    194 
    195         if (stepX > 0.0f) {
    196             generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount);
    197         }
    198 
    199         x1 = x2;
    200         u1 = stepX / bitmapWidth;
    201 
    202         previousStepX = stepX;
    203     }
    204 
    205     if (previousStepX != bitmapWidth) {
    206         x2 = width;
    207         generateQuad(vertex, x1, y1, x2, y2, u1, v1, 1.0f, v2, quadCount);
    208     }
    209 }
    210 
    211 void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
    212             float u1, float v1, float u2, float v2, uint32_t& quadCount) {
    213     const uint32_t oldQuadCount = quadCount;
    214     quadCount++;
    215 
    216     if (x1 < 0.0f) x1 = 0.0f;
    217     if (x2 < 0.0f) x2 = 0.0f;
    218     if (y1 < 0.0f) y1 = 0.0f;
    219     if (y2 < 0.0f) y2 = 0.0f;
    220 
    221     // Skip degenerate and transparent (empty) quads
    222     if ((mColors[oldQuadCount] == 0) || x1 >= x2 || y1 >= y2) {
    223 #if DEBUG_PATCHES_EMPTY_VERTICES
    224         PATCH_LOGD("    quad %d (empty)", oldQuadCount);
    225         PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.8f, %.8f", x1, y1, u1, v1);
    226         PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.8f, %.8f", x2, y2, u2, v2);
    227 #endif
    228         return;
    229     }
    230 
    231     // Record all non empty quads
    232     if (hasEmptyQuads) {
    233         Rect bounds(x1, y1, x2, y2);
    234         quads.add(bounds);
    235     }
    236 
    237     mUvMapper.map(u1, v1, u2, v2);
    238 
    239     TextureVertex::set(vertex++, x1, y1, u1, v1);
    240     TextureVertex::set(vertex++, x2, y1, u2, v1);
    241     TextureVertex::set(vertex++, x1, y2, u1, v2);
    242     TextureVertex::set(vertex++, x2, y2, u2, v2);
    243 
    244     verticesCount += 4;
    245     indexCount += 6;
    246 
    247 #if DEBUG_PATCHES_VERTICES
    248     PATCH_LOGD("    quad %d", oldQuadCount);
    249     PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.8f, %.8f", x1, y1, u1, v1);
    250     PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.8f, %.8f", x2, y2, u2, v2);
    251 #endif
    252 }
    253 
    254 }; // namespace uirenderer
    255 }; // namespace android
    256