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