Patch.cpp revision 41d35aef06c2a570a45474a01ca95a6cb9c29d9e
1fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy/*
2fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy * Copyright (C) 2010 The Android Open Source Project
3fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy *
4fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy * you may not use this file except in compliance with the License.
6fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy * You may obtain a copy of the License at
7fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy *
8fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy *
10fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy * Unless required by applicable law or agreed to in writing, software
11fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy * See the License for the specific language governing permissions and
14fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy * limitations under the License.
15fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy */
16fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
17fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy#define LOG_TAG "OpenGLRenderer"
18fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
196820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy#include <cmath>
20fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
214bb942083a0d4db746adf95349108dd8ef842e32Romain Guy#include <utils/Log.h>
224bb942083a0d4db746adf95349108dd8ef842e32Romain Guy
23fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy#include "Patch.h"
2403750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy#include "Caches.h"
25a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy#include "Properties.h"
26fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
27fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guynamespace android {
28fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guynamespace uirenderer {
29fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
30fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy///////////////////////////////////////////////////////////////////////////////
31fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy// Constructors/destructor
32fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy///////////////////////////////////////////////////////////////////////////////
33fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
346f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain GuyPatch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads):
35a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy        mXCount(xCount), mYCount(yCount), mEmptyQuads(emptyQuads) {
36a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    // Initialized with the maximum number of vertices we will need
37fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy    // 2 triangles per patch, 3 vertices per triangle
388ab4079ca27e36e5c584495bcd71b573598ac021Romain Guy    uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
39a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    mVertices = new TextureVertex[maxVertices];
406f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    mUploaded = false;
416f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy
42a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    verticesCount = 0;
43a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    hasEmptyQuads = emptyQuads > 0;
44a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy
456f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    mColorKey = 0;
466f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    mXDivs = new int32_t[mXCount];
476f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    mYDivs = new int32_t[mYCount];
4803750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy
49a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    PATCH_LOGD("    patch: xCount = %d, yCount = %d, emptyQuads = %d, max vertices = %d",
50a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy            xCount, yCount, emptyQuads, maxVertices);
51bd41a11078e94b755c8b6f78e1e4242c715fccd4Romain Guy
5203750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy    glGenBuffers(1, &meshBuffer);
53fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy}
54fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
55fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain GuyPatch::~Patch() {
5603750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy    delete[] mVertices;
576f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    delete[] mXDivs;
586f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    delete[] mYDivs;
5903750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy    glDeleteBuffers(1, &meshBuffer);
60fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy}
61fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
62fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy///////////////////////////////////////////////////////////////////////////////
636f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy// Patch management
646f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy///////////////////////////////////////////////////////////////////////////////
656f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy
666f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guyvoid Patch::copy(const int32_t* xDivs, const int32_t* yDivs) {
676f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    memcpy(mXDivs, xDivs, mXCount * sizeof(int32_t));
686f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t));
696f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy}
706f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy
716f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guyvoid Patch::copy(const int32_t* yDivs) {
726f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t));
736f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy}
746f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy
756f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guyvoid Patch::updateColorKey(const uint32_t colorKey) {
766f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    mColorKey = colorKey;
776f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy}
786f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy
796f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guybool Patch::matches(const int32_t* xDivs, const int32_t* yDivs, const uint32_t colorKey) {
806f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    if (mColorKey != colorKey) {
816f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        updateColorKey(colorKey);
826f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        copy(xDivs, yDivs);
836f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        return false;
846f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    }
856f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy
866f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    for (uint32_t i = 0; i < mXCount; i++) {
876f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        if (mXDivs[i] != xDivs[i]) {
886f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy            // The Y divs may or may not match, copy everything
896f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy            copy(xDivs, yDivs);
906f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy            return false;
916f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        }
926f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    }
936f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy
946f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    for (uint32_t i = 0; i < mYCount; i++) {
956f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        if (mYDivs[i] != yDivs[i]) {
966f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy            // We know all the X divs match, copy only Y divs
976f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy            copy(yDivs);
986f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy            return false;
996f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        }
1006f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    }
1016f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy
1026f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    return true;
1036f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy}
1046f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy
1056f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy///////////////////////////////////////////////////////////////////////////////
106fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy// Vertices management
107fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy///////////////////////////////////////////////////////////////////////////////
108fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
109759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guyvoid Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
1106f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        float left, float top, float right, float bottom) {
1115b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    if (hasEmptyQuads) quads.clear();
112a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy
113a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    // Reset the vertices count here, we will count exactly how many
114a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    // vertices we actually need when generating the quads
115a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    verticesCount = 0;
1165b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
1176f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    const uint32_t xStretchCount = (mXCount + 1) >> 1;
1186f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    const uint32_t yStretchCount = (mYCount + 1) >> 1;
119fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
1206820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    float stretchX = 0.0f;
12141d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy    float stretchY = 0.0f;
12241d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy
12341d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy    float rescaleX = 1.0f;
12441d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy    float rescaleY = 1.0f;
125fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
126fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy    const float meshWidth = right - left;
127fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
128fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy    if (xStretchCount > 0) {
129fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy        uint32_t stretchSize = 0;
1306f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        for (uint32_t i = 1; i < mXCount; i += 2) {
1316f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy            stretchSize += mXDivs[i] - mXDivs[i - 1];
132fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy        }
1336820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        const float xStretchTex = stretchSize;
134fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy        const float fixed = bitmapWidth - stretchSize;
13541d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy        const float xStretch = fmaxf(right - left - fixed, 0.0f);
1366820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        stretchX = xStretch / xStretchTex;
13741d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy        rescaleX = fminf(fmaxf(right - left, 0.0f) / fixed, 1.0f);
138fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy    }
139fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
140fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy    if (yStretchCount > 0) {
141fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy        uint32_t stretchSize = 0;
1426f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        for (uint32_t i = 1; i < mYCount; i += 2) {
1436f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy            stretchSize += mYDivs[i] - mYDivs[i - 1];
144fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy        }
1456820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        const float yStretchTex = stretchSize;
146fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy        const float fixed = bitmapHeight - stretchSize;
14741d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy        const float yStretch = fmaxf(bottom - top - fixed, 0.0f);
1486820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        stretchY = yStretch / yStretchTex;
14941d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy        rescaleY = fminf(fmaxf(bottom - top, 0.0f) / fixed, 1.0f);
150fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy    }
151fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
15203750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy    TextureVertex* vertex = mVertices;
1534bb942083a0d4db746adf95349108dd8ef842e32Romain Guy    uint32_t quadCount = 0;
154fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
1556820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    float previousStepY = 0.0f;
156fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
1576820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    float y1 = 0.0f;
158f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy    float y2 = 0.0f;
1596820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    float v1 = 0.0f;
1606820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy
161eb6a4a17a07f1aa41bd58d418b2982cddb97685aRomain Guy    for (uint32_t i = 0; i < mYCount; i++) {
1626f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        float stepY = mYDivs[i];
1635e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        const float segment = stepY - previousStepY;
1646820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy
1656820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        if (i & 1) {
1668ab4079ca27e36e5c584495bcd71b573598ac021Romain Guy            y2 = y1 + floorf(segment * stretchY + 0.5f);
167fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy        } else {
16841d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy            y2 = y1 + segment * rescaleY;
169fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy        }
1705e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy
1715e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        float vOffset = y1 == y2 ? 0.0f : 0.5 - (0.5 * segment / (y2 - y1));
1725e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        float v2 = fmax(0.0f, stepY - vOffset) / bitmapHeight;
1735e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        v1 += vOffset / bitmapHeight;
1746820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy
175eb6a4a17a07f1aa41bd58d418b2982cddb97685aRomain Guy        if (stepY > 0.0f) {
176f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#if DEBUG_EXPLODE_PATCHES
177f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy            y1 += i * EXPLODE_GAP;
178f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy            y2 += i * EXPLODE_GAP;
179f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#endif
18041d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy            generateRow(vertex, y1, y2, v1, v2, stretchX, rescaleX, right - left,
181eb6a4a17a07f1aa41bd58d418b2982cddb97685aRomain Guy                    bitmapWidth, quadCount);
182f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#if DEBUG_EXPLODE_PATCHES
183f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy            y2 -= i * EXPLODE_GAP;
184f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#endif
185eb6a4a17a07f1aa41bd58d418b2982cddb97685aRomain Guy        }
1866820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy
1876820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        y1 = y2;
1885e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        v1 = stepY / bitmapHeight;
1896820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy
1906820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        previousStepY = stepY;
191fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy    }
192fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
193fdbec3e4828f93bfa5cde758ad0e77b89c5c2ecdRomain Guy    if (previousStepY != bitmapHeight) {
194f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy        y2 = bottom - top;
195f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#if DEBUG_EXPLODE_PATCHES
196f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy        y1 += mYCount * EXPLODE_GAP;
197f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy        y2 += mYCount * EXPLODE_GAP;
198f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#endif
19941d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy        generateRow(vertex, y1, y2, v1, 1.0f, stretchX, rescaleX, right - left,
20041d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy                bitmapWidth, quadCount);
201fdbec3e4828f93bfa5cde758ad0e77b89c5c2ecdRomain Guy    }
20203750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy
203a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    if (verticesCount > 0) {
204f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy        Caches& caches = Caches::getInstance();
205f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy        caches.bindMeshBuffer(meshBuffer);
206a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy        if (!mUploaded) {
207a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy            glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
208a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy                    mVertices, GL_DYNAMIC_DRAW);
209a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy            mUploaded = true;
210a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy        } else {
211a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy            glBufferSubData(GL_ARRAY_BUFFER, 0,
212a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy                    sizeof(TextureVertex) * verticesCount, mVertices);
213a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy        }
214f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy        caches.resetVertexPointers();
2156f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy    }
216a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy
217a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    PATCH_LOGD("    patch: new vertices count = %d", verticesCount);
218fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy}
219fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
2205b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guyvoid Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
22141d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy        float stretchX, float rescaleX, float width, float bitmapWidth, uint32_t& quadCount) {
2226820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    float previousStepX = 0.0f;
2236820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy
2246820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    float x1 = 0.0f;
225f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy    float x2 = 0.0f;
2266820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    float u1 = 0.0f;
227fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
2286820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    // Generate the row quad by quad
229eb6a4a17a07f1aa41bd58d418b2982cddb97685aRomain Guy    for (uint32_t i = 0; i < mXCount; i++) {
2306f72bebe92a4db7b5dc83f4ac5b5fd02e3b4e2cdRomain Guy        float stepX = mXDivs[i];
2315e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        const float segment = stepX - previousStepX;
232fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
2336820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        if (i & 1) {
2348ab4079ca27e36e5c584495bcd71b573598ac021Romain Guy            x2 = x1 + floorf(segment * stretchX + 0.5f);
235fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy        } else {
23641d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy            x2 = x1 + segment * rescaleX;
237fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy        }
2385e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy
2395e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        float uOffset = x1 == x2 ? 0.0f : 0.5 - (0.5 * segment / (x2 - x1));
2405e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        float u2 = fmax(0.0f, stepX - uOffset) / bitmapWidth;
2415e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        u1 += uOffset / bitmapWidth;
242fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
243eb6a4a17a07f1aa41bd58d418b2982cddb97685aRomain Guy        if (stepX > 0.0f) {
244f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#if DEBUG_EXPLODE_PATCHES
245f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy            x1 += i * EXPLODE_GAP;
246f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy            x2 += i * EXPLODE_GAP;
247f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#endif
248eb6a4a17a07f1aa41bd58d418b2982cddb97685aRomain Guy            generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount);
249f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#if DEBUG_EXPLODE_PATCHES
250f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy            x2 -= i * EXPLODE_GAP;
251f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#endif
252eb6a4a17a07f1aa41bd58d418b2982cddb97685aRomain Guy        }
2536820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy
2546820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        x1 = x2;
2555e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        u1 = stepX / bitmapWidth;
2566820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy
2576820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        previousStepX = stepX;
258fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy    }
259fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
260fdbec3e4828f93bfa5cde758ad0e77b89c5c2ecdRomain Guy    if (previousStepX != bitmapWidth) {
261f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy        x2 = width;
262f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#if DEBUG_EXPLODE_PATCHES
263f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy        x1 += mXCount * EXPLODE_GAP;
264f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy        x2 += mXCount * EXPLODE_GAP;
265f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy#endif
266f504a2fa144504ca1efd39a4ef9208e3d4d336c5Romain Guy        generateQuad(vertex, x1, y1, x2, y2, u1, v1, 1.0f, v2, quadCount);
267fdbec3e4828f93bfa5cde758ad0e77b89c5c2ecdRomain Guy    }
268fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy}
269fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
2707444da512680df0c52af39ea521e35adbe0c167dRomain Guyvoid Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
271eb6a4a17a07f1aa41bd58d418b2982cddb97685aRomain Guy            float u1, float v1, float u2, float v2, uint32_t& quadCount) {
272a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    const uint32_t oldQuadCount = quadCount;
273eb6a4a17a07f1aa41bd58d418b2982cddb97685aRomain Guy    quadCount++;
274bd41a11078e94b755c8b6f78e1e4242c715fccd4Romain Guy
27570561df470c31513056df181571632851fd0d081Romain Guy    if (x1 < 0.0f) x1 = 0.0f;
27670561df470c31513056df181571632851fd0d081Romain Guy    if (x2 < 0.0f) x2 = 0.0f;
27770561df470c31513056df181571632851fd0d081Romain Guy    if (y1 < 0.0f) y1 = 0.0f;
27870561df470c31513056df181571632851fd0d081Romain Guy    if (y2 < 0.0f) y2 = 0.0f;
27970561df470c31513056df181571632851fd0d081Romain Guy
280a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    // Skip degenerate and transparent (empty) quads
28141d35aef06c2a570a45474a01ca95a6cb9c29d9eRomain Guy    if (((mColorKey >> oldQuadCount) & 0x1) || x1 >= x2 || y1 >= y2) {
282fb13abd800cd610c7f46815848545feff83e5748Romain Guy#if DEBUG_PATCHES_EMPTY_VERTICES
283fb13abd800cd610c7f46815848545feff83e5748Romain Guy        PATCH_LOGD("    quad %d (empty)", oldQuadCount);
2845e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.4f, %.4f", x1, y1, u1, v1);
2855e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy        PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.4f, %.4f", x2, y2, u2, v2);
286fb13abd800cd610c7f46815848545feff83e5748Romain Guy#endif
2877444da512680df0c52af39ea521e35adbe0c167dRomain Guy        return;
2884bb942083a0d4db746adf95349108dd8ef842e32Romain Guy    }
2894bb942083a0d4db746adf95349108dd8ef842e32Romain Guy
290a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    // Record all non empty quads
2915b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    if (hasEmptyQuads) {
2925b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        Rect bounds(x1, y1, x2, y2);
2935b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        quads.add(bounds);
2945b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
2955b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
2966820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    // Left triangle
2976820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    TextureVertex::set(vertex++, x1, y1, u1, v1);
2986820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    TextureVertex::set(vertex++, x2, y1, u2, v1);
2996820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    TextureVertex::set(vertex++, x1, y2, u1, v2);
3006820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy
3016820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    // Right triangle
3026820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    TextureVertex::set(vertex++, x1, y2, u1, v2);
3036820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    TextureVertex::set(vertex++, x2, y1, u2, v1);
3046820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    TextureVertex::set(vertex++, x2, y2, u2, v2);
305a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy
306a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    // A quad is made of 2 triangles, 6 vertices
307a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    verticesCount += 6;
308a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy
309a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy#if DEBUG_PATCHES_VERTICES
310a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy    PATCH_LOGD("    quad %d", oldQuadCount);
3115e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy    PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.4f, %.4f", x1, y1, u1, v1);
3125e7c469c7a3039af7696789a797f8d91a45227ebRomain Guy    PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.4f, %.4f", x2, y2, u2, v2);
313a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy#endif
314fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy}
315fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy
316fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy}; // namespace uirenderer
317fb5e23c327cd5f8f93d1eaa7c10f34d6fd3efb6cRomain Guy}; // namespace android
318