1/*
2 * Copyright (C) 2012 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#ifndef ANDROID_HWUI_VERTEX_BUFFER_H
18#define ANDROID_HWUI_VERTEX_BUFFER_H
19
20#include <algorithm>
21
22namespace android {
23namespace uirenderer {
24
25class VertexBuffer {
26public:
27    enum MeshFeatureFlags {
28        kNone = 0,
29        kAlpha = 1 << 0,
30        kIndices = 1 << 1,
31    };
32
33    VertexBuffer()
34            : mBuffer(nullptr)
35            , mIndices(nullptr)
36            , mVertexCount(0)
37            , mIndexCount(0)
38            , mAllocatedVertexCount(0)
39            , mAllocatedIndexCount(0)
40            , mByteCount(0)
41            , mMeshFeatureFlags(kNone)
42            , mReallocBuffer(nullptr)
43            , mCleanupMethod(nullptr)
44            , mCleanupIndexMethod(nullptr) {}
45
46    ~VertexBuffer() {
47        if (mCleanupMethod) mCleanupMethod(mBuffer);
48        if (mCleanupIndexMethod) mCleanupIndexMethod(mIndices);
49    }
50
51    /**
52       This should be the only method used by the Tessellator. Subsequent calls to
53       alloc will allocate space within the first allocation (useful if you want to
54       eventually allocate multiple regions within a single VertexBuffer, such as
55       with PathTessellator::tessellateLines())
56     */
57    template <class TYPE>
58    TYPE* alloc(int vertexCount) {
59        if (mVertexCount) {
60            TYPE* reallocBuffer = (TYPE*)mReallocBuffer;
61            // already have allocated the buffer, re-allocate space within
62            if (mReallocBuffer != mBuffer) {
63                // not first re-allocation, leave space for degenerate triangles to separate strips
64                reallocBuffer += 2;
65            }
66            mReallocBuffer = reallocBuffer + vertexCount;
67            return reallocBuffer;
68        }
69        mAllocatedVertexCount = vertexCount;
70        mVertexCount = vertexCount;
71        mByteCount = mVertexCount * sizeof(TYPE);
72        mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount];
73
74        mCleanupMethod = &(cleanup<TYPE>);
75
76        return (TYPE*)mBuffer;
77    }
78
79    template <class TYPE>
80    TYPE* allocIndices(int indexCount) {
81        mAllocatedIndexCount = indexCount;
82        mIndexCount = indexCount;
83        mIndices = (void*)new TYPE[indexCount];
84
85        mCleanupIndexMethod = &(cleanup<TYPE>);
86
87        return (TYPE*)mIndices;
88    }
89
90    template <class TYPE>
91    void copyInto(const VertexBuffer& srcBuffer, float xOffset, float yOffset) {
92        int verticesToCopy = srcBuffer.getVertexCount();
93
94        TYPE* dst = alloc<TYPE>(verticesToCopy);
95        TYPE* src = (TYPE*)srcBuffer.getBuffer();
96
97        for (int i = 0; i < verticesToCopy; i++) {
98            TYPE::copyWithOffset(&dst[i], src[i], xOffset, yOffset);
99        }
100    }
101
102    /**
103     * Brute force bounds computation, used only if the producer of this
104     * vertex buffer can't determine bounds more simply/efficiently
105     */
106    template <class TYPE>
107    void computeBounds(int vertexCount = 0) {
108        if (!mVertexCount) {
109            mBounds.setEmpty();
110            return;
111        }
112
113        // default: compute over every vertex
114        if (vertexCount == 0) vertexCount = mVertexCount;
115
116        TYPE* current = (TYPE*)mBuffer;
117        TYPE* end = current + vertexCount;
118        mBounds.set(current->x, current->y, current->x, current->y);
119        for (; current < end; current++) {
120            mBounds.expandToCover(current->x, current->y);
121        }
122    }
123
124    const void* getBuffer() const { return mBuffer; }
125    const void* getIndices() const { return mIndices; }
126    const Rect& getBounds() const { return mBounds; }
127    unsigned int getVertexCount() const { return mVertexCount; }
128    unsigned int getSize() const { return mByteCount; }
129    unsigned int getIndexCount() const { return mIndexCount; }
130    void updateIndexCount(unsigned int newCount) {
131        mIndexCount = std::min(newCount, mAllocatedIndexCount);
132    }
133    void updateVertexCount(unsigned int newCount) {
134        mVertexCount = std::min(newCount, mAllocatedVertexCount);
135    }
136    MeshFeatureFlags getMeshFeatureFlags() const { return mMeshFeatureFlags; }
137    void setMeshFeatureFlags(int flags) {
138        mMeshFeatureFlags = static_cast<MeshFeatureFlags>(flags);
139    }
140
141    void setBounds(Rect bounds) { mBounds = bounds; }
142
143    template <class TYPE>
144    void createDegenerateSeparators(int allocSize) {
145        TYPE* end = (TYPE*)mBuffer + mVertexCount;
146        for (TYPE* degen = (TYPE*)mBuffer + allocSize; degen < end; degen += 2 + allocSize) {
147            memcpy(degen, degen - 1, sizeof(TYPE));
148            memcpy(degen + 1, degen + 2, sizeof(TYPE));
149        }
150    }
151
152private:
153    template <class TYPE>
154    static void cleanup(void* buffer) {
155        delete[](TYPE*) buffer;
156    }
157
158    Rect mBounds;
159
160    void* mBuffer;
161    void* mIndices;
162
163    unsigned int mVertexCount;
164    unsigned int mIndexCount;
165    unsigned int mAllocatedVertexCount;
166    unsigned int mAllocatedIndexCount;
167    unsigned int mByteCount;
168
169    MeshFeatureFlags mMeshFeatureFlags;
170
171    void* mReallocBuffer;  // used for multi-allocation
172
173    void (*mCleanupMethod)(void*);
174    void (*mCleanupIndexMethod)(void*);
175};
176
177};  // namespace uirenderer
178};  // namespace android
179
180#endif  // ANDROID_HWUI_VERTEX_BUFFER_H
181