Patch.cpp revision bd41a11078e94b755c8b6f78e1e4242c715fccd4
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 "Patch.h" 24#include "Caches.h" 25 26namespace android { 27namespace uirenderer { 28 29/////////////////////////////////////////////////////////////////////////////// 30// Constructors/destructor 31/////////////////////////////////////////////////////////////////////////////// 32 33Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads): 34 mXCount(xCount), mYCount(yCount) { 35 // 2 triangles per patch, 3 vertices per triangle 36 verticesCount = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3; 37 mVertices = new TextureVertex[verticesCount]; 38 hasEmptyQuads = emptyQuads > 0; 39 mUploaded = false; 40 41 mColorKey = 0; 42 mXDivs = new int32_t[mXCount]; 43 mYDivs = new int32_t[mYCount]; 44 45 PATCH_LOGD(" patch: xCount = %d, yCount = %d, emptyQuads = %d, vertices = %d", 46 xCount, yCount, emptyQuads, verticesCount); 47 48 glGenBuffers(1, &meshBuffer); 49} 50 51Patch::~Patch() { 52 delete[] mVertices; 53 delete[] mXDivs; 54 delete[] mYDivs; 55 glDeleteBuffers(1, &meshBuffer); 56} 57 58/////////////////////////////////////////////////////////////////////////////// 59// Patch management 60/////////////////////////////////////////////////////////////////////////////// 61 62void Patch::copy(const int32_t* xDivs, const int32_t* yDivs) { 63 memcpy(mXDivs, xDivs, mXCount * sizeof(int32_t)); 64 memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t)); 65} 66 67void Patch::copy(const int32_t* yDivs) { 68 memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t)); 69} 70 71void Patch::updateColorKey(const uint32_t colorKey) { 72 mColorKey = colorKey; 73} 74 75bool Patch::matches(const int32_t* xDivs, const int32_t* yDivs, const uint32_t colorKey) { 76 if (mColorKey != colorKey) { 77 updateColorKey(colorKey); 78 copy(xDivs, yDivs); 79 return false; 80 } 81 82 for (uint32_t i = 0; i < mXCount; i++) { 83 if (mXDivs[i] != xDivs[i]) { 84 // The Y divs may or may not match, copy everything 85 copy(xDivs, yDivs); 86 return false; 87 } 88 } 89 90 for (uint32_t i = 0; i < mYCount; i++) { 91 if (mYDivs[i] != yDivs[i]) { 92 // We know all the X divs match, copy only Y divs 93 copy(yDivs); 94 return false; 95 } 96 } 97 98 return true; 99} 100 101/////////////////////////////////////////////////////////////////////////////// 102// Vertices management 103/////////////////////////////////////////////////////////////////////////////// 104 105void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight, 106 float left, float top, float right, float bottom) { 107 if (hasEmptyQuads) quads.clear(); 108 109 const uint32_t xStretchCount = (mXCount + 1) >> 1; 110 const uint32_t yStretchCount = (mYCount + 1) >> 1; 111 112 float stretchX = 0.0f; 113 float stretchY = 0.0; 114 115 const float meshWidth = right - left; 116 117 if (xStretchCount > 0) { 118 uint32_t stretchSize = 0; 119 for (uint32_t i = 1; i < mXCount; i += 2) { 120 stretchSize += mXDivs[i] - mXDivs[i - 1]; 121 } 122 const float xStretchTex = stretchSize; 123 const float fixed = bitmapWidth - stretchSize; 124 const float xStretch = right - left - fixed; 125 stretchX = xStretch / xStretchTex; 126 } 127 128 if (yStretchCount > 0) { 129 uint32_t stretchSize = 0; 130 for (uint32_t i = 1; i < mYCount; i += 2) { 131 stretchSize += mYDivs[i] - mYDivs[i - 1]; 132 } 133 const float yStretchTex = stretchSize; 134 const float fixed = bitmapHeight - stretchSize; 135 const float yStretch = bottom - top - fixed; 136 stretchY = yStretch / yStretchTex; 137 } 138 139 TextureVertex* vertex = mVertices; 140 uint32_t quadCount = 0; 141 142 float previousStepY = 0.0f; 143 144 float y1 = 0.0f; 145 float v1 = 0.0f; 146 147 for (uint32_t i = 0; i < mYCount; i++) { 148 float stepY = mYDivs[i]; 149 150 float y2 = 0.0f; 151 if (i & 1) { 152 const float segment = stepY - previousStepY; 153 y2 = y1 + segment * stretchY; 154 } else { 155 y2 = y1 + stepY - previousStepY; 156 } 157 float v2 = fmax(0.0f, stepY - 0.5f) / bitmapHeight; 158 159 generateRow(vertex, y1, y2, v1, v2, stretchX, right - left, bitmapWidth, quadCount); 160 161 y1 = y2; 162 v1 = (stepY + 0.5f) / bitmapHeight; 163 164 previousStepY = stepY; 165 } 166 167 generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left, 168 bitmapWidth, quadCount); 169 170 Caches::getInstance().bindMeshBuffer(meshBuffer); 171 if (!mUploaded) { 172 glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount, 173 mVertices, GL_DYNAMIC_DRAW); 174 mUploaded = true; 175 } else { 176 glBufferSubData(GL_ARRAY_BUFFER, 0, 177 sizeof(TextureVertex) * verticesCount, mVertices); 178 } 179} 180 181void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2, 182 float stretchX, float width, float bitmapWidth, uint32_t& quadCount) { 183 float previousStepX = 0.0f; 184 185 float x1 = 0.0f; 186 float u1 = 0.0f; 187 188 // Generate the row quad by quad 189 for (uint32_t i = 0; i < mXCount; i++) { 190 float stepX = mXDivs[i]; 191 192 float x2 = 0.0f; 193 if (i & 1) { 194 const float segment = stepX - previousStepX; 195 x2 = x1 + segment * stretchX; 196 } else { 197 x2 = x1 + stepX - previousStepX; 198 } 199 float u2 = fmax(0.0f, stepX - 0.5f) / bitmapWidth; 200 201 generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount); 202 203 x1 = x2; 204 u1 = (stepX + 0.5f) / bitmapWidth; 205 206 previousStepX = stepX; 207 } 208 209 generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount); 210} 211 212void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, 213 float u1, float v1, float u2, float v2, uint32_t& quadCount) { 214 uint32_t oldQuadCount = quadCount; 215 216 // Degenerate quads are an artifact of our implementation and should not 217 // be taken into account when checking for transparent quads 218 if (x2 - x1 > 0.999f && y2 - y1 > 0.999f) { 219 quadCount++; 220 } 221 222 if (((mColorKey >> oldQuadCount) & 0x1) == 1) { 223 return; 224 } 225 226 if (hasEmptyQuads) { 227 Rect bounds(x1, y1, x2, y2); 228 quads.add(bounds); 229 } 230 231 // Left triangle 232 TextureVertex::set(vertex++, x1, y1, u1, v1); 233 TextureVertex::set(vertex++, x2, y1, u2, v1); 234 TextureVertex::set(vertex++, x1, y2, u1, v2); 235 236 // Right triangle 237 TextureVertex::set(vertex++, x1, y2, u1, v2); 238 TextureVertex::set(vertex++, x2, y1, u2, v1); 239 TextureVertex::set(vertex++, x2, y2, u2, v2); 240} 241 242}; // namespace uirenderer 243}; // namespace android 244