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#include "utils/MathUtils.h" 28 29namespace android { 30namespace uirenderer { 31 32/////////////////////////////////////////////////////////////////////////////// 33// Vertices management 34/////////////////////////////////////////////////////////////////////////////// 35 36uint32_t Patch::getSize() const { 37 return verticesCount * sizeof(TextureVertex); 38} 39 40Patch::Patch(const float bitmapWidth, const float bitmapHeight, 41 float width, float height, const UvMapper& mapper, const Res_png_9patch* patch) 42 : mColors(patch->getColors()) { 43 44 int8_t emptyQuads = 0; 45 const int8_t numColors = patch->numColors; 46 if (uint8_t(numColors) < sizeof(uint32_t) * 4) { 47 for (int8_t i = 0; i < numColors; i++) { 48 if (mColors[i] == 0x0) { 49 emptyQuads++; 50 } 51 } 52 } 53 54 hasEmptyQuads = emptyQuads > 0; 55 56 uint32_t xCount = patch->numXDivs; 57 uint32_t yCount = patch->numYDivs; 58 59 uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 4; 60 if (maxVertices == 0) return; 61 62 vertices.reset(new TextureVertex[maxVertices]); 63 TextureVertex* vertex = vertices.get(); 64 65 const int32_t* xDivs = patch->getXDivs(); 66 const int32_t* yDivs = patch->getYDivs(); 67 68 const uint32_t xStretchCount = (xCount + 1) >> 1; 69 const uint32_t yStretchCount = (yCount + 1) >> 1; 70 71 float stretchX = 0.0f; 72 float stretchY = 0.0f; 73 74 float rescaleX = 1.0f; 75 float rescaleY = 1.0f; 76 77 if (xStretchCount > 0) { 78 uint32_t stretchSize = 0; 79 for (uint32_t i = 1; i < xCount; i += 2) { 80 stretchSize += xDivs[i] - xDivs[i - 1]; 81 } 82 const float xStretchTex = stretchSize; 83 const float fixed = bitmapWidth - stretchSize; 84 const float xStretch = std::max(width - fixed, 0.0f); 85 stretchX = xStretch / xStretchTex; 86 rescaleX = fixed == 0.0f ? 0.0f : std::min(std::max(width, 0.0f) / fixed, 1.0f); 87 } 88 89 if (yStretchCount > 0) { 90 uint32_t stretchSize = 0; 91 for (uint32_t i = 1; i < yCount; i += 2) { 92 stretchSize += yDivs[i] - yDivs[i - 1]; 93 } 94 const float yStretchTex = stretchSize; 95 const float fixed = bitmapHeight - stretchSize; 96 const float yStretch = std::max(height - fixed, 0.0f); 97 stretchY = yStretch / yStretchTex; 98 rescaleY = fixed == 0.0f ? 0.0f : std::min(std::max(height, 0.0f) / fixed, 1.0f); 99 } 100 101 uint32_t quadCount = 0; 102 103 float previousStepY = 0.0f; 104 105 float y1 = 0.0f; 106 float y2 = 0.0f; 107 float v1 = 0.0f; 108 109 mUvMapper = mapper; 110 111 for (uint32_t i = 0; i < yCount; i++) { 112 float stepY = yDivs[i]; 113 const float segment = stepY - previousStepY; 114 115 if (i & 1) { 116 y2 = y1 + floorf(segment * stretchY + 0.5f); 117 } else { 118 y2 = y1 + segment * rescaleY; 119 } 120 121 float vOffset = y1 == y2 ? 0.0f : 0.5 - (0.5 * segment / (y2 - y1)); 122 float v2 = std::max(0.0f, stepY - vOffset) / bitmapHeight; 123 v1 += vOffset / bitmapHeight; 124 125 if (stepY > 0.0f) { 126 generateRow(xDivs, xCount, vertex, y1, y2, v1, v2, stretchX, rescaleX, 127 width, bitmapWidth, quadCount); 128 } 129 130 y1 = y2; 131 v1 = stepY / bitmapHeight; 132 133 previousStepY = stepY; 134 } 135 136 if (previousStepY != bitmapHeight) { 137 y2 = height; 138 generateRow(xDivs, xCount, vertex, y1, y2, v1, 1.0f, stretchX, rescaleX, 139 width, bitmapWidth, quadCount); 140 } 141 142 if (verticesCount != maxVertices) { 143 std::unique_ptr<TextureVertex[]> reducedVertices(new TextureVertex[verticesCount]); 144 memcpy(reducedVertices.get(), vertices.get(), verticesCount * sizeof(TextureVertex)); 145 vertices = std::move(reducedVertices); 146 } 147} 148 149void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, 150 float y1, float y2, float v1, float v2, float stretchX, float rescaleX, 151 float width, float bitmapWidth, uint32_t& quadCount) { 152 float previousStepX = 0.0f; 153 154 float x1 = 0.0f; 155 float x2 = 0.0f; 156 float u1 = 0.0f; 157 158 // Generate the row quad by quad 159 for (uint32_t i = 0; i < xCount; i++) { 160 float stepX = xDivs[i]; 161 const float segment = stepX - previousStepX; 162 163 if (i & 1) { 164 x2 = x1 + floorf(segment * stretchX + 0.5f); 165 } else { 166 x2 = x1 + segment * rescaleX; 167 } 168 169 float uOffset = x1 == x2 ? 0.0f : 0.5 - (0.5 * segment / (x2 - x1)); 170 float u2 = std::max(0.0f, stepX - uOffset) / bitmapWidth; 171 u1 += uOffset / bitmapWidth; 172 173 if (stepX > 0.0f) { 174 generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount); 175 } 176 177 x1 = x2; 178 u1 = stepX / bitmapWidth; 179 180 previousStepX = stepX; 181 } 182 183 if (previousStepX != bitmapWidth) { 184 x2 = width; 185 generateQuad(vertex, x1, y1, x2, y2, u1, v1, 1.0f, v2, quadCount); 186 } 187} 188 189void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, 190 float u1, float v1, float u2, float v2, uint32_t& quadCount) { 191 const uint32_t oldQuadCount = quadCount; 192 quadCount++; 193 194 x1 = MathUtils::max(x1, 0.0f); 195 x2 = MathUtils::max(x2, 0.0f); 196 y1 = MathUtils::max(y1, 0.0f); 197 y2 = MathUtils::max(y2, 0.0f); 198 199 // Skip degenerate and transparent (empty) quads 200 if ((mColors[oldQuadCount] == 0) || x1 >= x2 || y1 >= y2) { 201#if DEBUG_PATCHES_EMPTY_VERTICES 202 PATCH_LOGD(" quad %d (empty)", oldQuadCount); 203 PATCH_LOGD(" left, top = %.2f, %.2f\t\tu1, v1 = %.8f, %.8f", x1, y1, u1, v1); 204 PATCH_LOGD(" right, bottom = %.2f, %.2f\t\tu2, v2 = %.8f, %.8f", x2, y2, u2, v2); 205#endif 206 return; 207 } 208 209 // Record all non empty quads 210 if (hasEmptyQuads) { 211 Rect bounds(x1, y1, x2, y2); 212 quads.add(bounds); 213 } 214 215 mUvMapper.map(u1, v1, u2, v2); 216 217 TextureVertex::set(vertex++, x1, y1, u1, v1); 218 TextureVertex::set(vertex++, x2, y1, u2, v1); 219 TextureVertex::set(vertex++, x1, y2, u1, v2); 220 TextureVertex::set(vertex++, x2, y2, u2, v2); 221 222 verticesCount += 4; 223 indexCount += 6; 224 225#if DEBUG_PATCHES_VERTICES 226 PATCH_LOGD(" quad %d", oldQuadCount); 227 PATCH_LOGD(" left, top = %.2f, %.2f\t\tu1, v1 = %.8f, %.8f", x1, y1, u1, v1); 228 PATCH_LOGD(" right, bottom = %.2f, %.2f\t\tu2, v2 = %.8f, %.8f", x2, y2, u2, v2); 229#endif 230} 231 232}; // namespace uirenderer 233}; // namespace android 234