• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Patch()35 Patch::Patch(): vertices(NULL), verticesCount(0), indexCount(0), hasEmptyQuads(false) {
36 }
37 
~Patch()38 Patch::~Patch() {
39     delete[] vertices;
40 }
41 
42 ///////////////////////////////////////////////////////////////////////////////
43 // Vertices management
44 ///////////////////////////////////////////////////////////////////////////////
45 
getSize() const46 uint32_t Patch::getSize() const {
47     return verticesCount * sizeof(TextureVertex);
48 }
49 
createMesh(const float bitmapWidth,const float bitmapHeight,float width,float height,const Res_png_9patch * patch)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 
createMesh(const float bitmapWidth,const float bitmapHeight,float width,float height,const UvMapper & mapper,const Res_png_9patch * patch)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 
generateRow(const int32_t * xDivs,uint32_t xCount,TextureVertex * & vertex,float y1,float y2,float v1,float v2,float stretchX,float rescaleX,float width,float bitmapWidth,uint32_t & quadCount)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 
generateQuad(TextureVertex * & vertex,float x1,float y1,float x2,float y2,float u1,float v1,float u2,float v2,uint32_t & quadCount)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