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