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