1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "scatterpointbufferhelper_p.h" |
5 | #include <QtGui/QVector2D> |
6 | |
7 | QT_BEGIN_NAMESPACE |
8 | |
9 | const QVector3D hiddenPos(-1000.0f, -1000.0f, -1000.0f); |
10 | |
11 | ScatterPointBufferHelper::ScatterPointBufferHelper() |
12 | : m_pointbuffer(0), |
13 | m_oldRemoveIndex(-1) |
14 | { |
15 | } |
16 | |
17 | ScatterPointBufferHelper::~ScatterPointBufferHelper() |
18 | { |
19 | if (QOpenGLContext::currentContext()) |
20 | glDeleteBuffers(n: 1, buffers: &m_pointbuffer); |
21 | } |
22 | |
23 | GLuint ScatterPointBufferHelper::pointBuf() |
24 | { |
25 | if (!m_meshDataLoaded) |
26 | qFatal(msg: "No loaded object" ); |
27 | return m_pointbuffer; |
28 | } |
29 | |
30 | void ScatterPointBufferHelper::pushPoint(uint pointIndex) |
31 | { |
32 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_pointbuffer); |
33 | |
34 | // Pop the previous point if it is still pushed |
35 | if (m_oldRemoveIndex >= 0) { |
36 | glBufferSubData(GL_ARRAY_BUFFER, offset: m_oldRemoveIndex * sizeof(QVector3D), |
37 | size: sizeof(QVector3D), data: &m_bufferedPoints.at(i: m_oldRemoveIndex)); |
38 | } |
39 | |
40 | glBufferSubData(GL_ARRAY_BUFFER, offset: pointIndex * sizeof(QVector3D), |
41 | size: sizeof(QVector3D), |
42 | data: &hiddenPos); |
43 | |
44 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
45 | |
46 | m_oldRemoveIndex = pointIndex; |
47 | } |
48 | |
49 | void ScatterPointBufferHelper::popPoint() |
50 | { |
51 | if (m_oldRemoveIndex >= 0) { |
52 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_pointbuffer); |
53 | glBufferSubData(GL_ARRAY_BUFFER, offset: m_oldRemoveIndex * sizeof(QVector3D), |
54 | size: sizeof(QVector3D), data: &m_bufferedPoints.at(i: m_oldRemoveIndex)); |
55 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
56 | } |
57 | |
58 | m_oldRemoveIndex = -1; |
59 | } |
60 | |
61 | void ScatterPointBufferHelper::load(ScatterSeriesRenderCache *cache) |
62 | { |
63 | ScatterRenderItemArray &renderArray = cache->renderArray(); |
64 | const int renderArraySize = renderArray.size(); |
65 | m_indexCount = 0; |
66 | |
67 | if (m_meshDataLoaded) { |
68 | // Delete old data |
69 | glDeleteBuffers(n: 1, buffers: &m_pointbuffer); |
70 | glDeleteBuffers(n: 1, buffers: &m_uvbuffer); |
71 | m_bufferedPoints.clear(); |
72 | m_pointbuffer = 0; |
73 | m_uvbuffer = 0; |
74 | m_meshDataLoaded = false; |
75 | } |
76 | |
77 | bool itemsVisible = false; |
78 | m_bufferedPoints.resize(size: renderArraySize); |
79 | for (int i = 0; i < renderArraySize; i++) { |
80 | const ScatterRenderItem &item = renderArray.at(i); |
81 | if (!item.isVisible()) { |
82 | m_bufferedPoints[i] = hiddenPos; |
83 | } else { |
84 | itemsVisible = true; |
85 | m_bufferedPoints[i] = item.translation(); |
86 | } |
87 | } |
88 | |
89 | QList<QVector2D> buffered_uvs; |
90 | if (itemsVisible) |
91 | m_indexCount = renderArraySize; |
92 | |
93 | if (m_indexCount > 0) { |
94 | if (cache->colorStyle() == Q3DTheme::ColorStyleRangeGradient) |
95 | createRangeGradientUVs(cache, buffered_uvs); |
96 | |
97 | glGenBuffers(n: 1, buffers: &m_pointbuffer); |
98 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_pointbuffer); |
99 | glBufferData(GL_ARRAY_BUFFER, size: m_bufferedPoints.size() * sizeof(QVector3D), |
100 | data: &m_bufferedPoints.at(i: 0), |
101 | GL_DYNAMIC_DRAW); |
102 | |
103 | if (buffered_uvs.size()) { |
104 | glGenBuffers(n: 1, buffers: &m_uvbuffer); |
105 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_uvbuffer); |
106 | glBufferData(GL_ARRAY_BUFFER, size: buffered_uvs.size() * sizeof(QVector2D), |
107 | data: &buffered_uvs.at(i: 0), GL_STATIC_DRAW); |
108 | } |
109 | |
110 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
111 | |
112 | m_meshDataLoaded = true; |
113 | } |
114 | } |
115 | |
116 | void ScatterPointBufferHelper::update(ScatterSeriesRenderCache *cache) |
117 | { |
118 | // It may be that the buffer hasn't yet been initialized, in case the entire series was |
119 | // hidden items. No need to update in that case. |
120 | if (m_indexCount > 0) { |
121 | const ScatterRenderItemArray &renderArray = cache->renderArray(); |
122 | const int updateSize = cache->updateIndices().size(); |
123 | |
124 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_pointbuffer); |
125 | for (int i = 0; i < updateSize; i++) { |
126 | int index = cache->updateIndices().at(i); |
127 | const ScatterRenderItem &item = renderArray.at(i: index); |
128 | if (!item.isVisible()) |
129 | m_bufferedPoints[index] = hiddenPos; |
130 | else |
131 | m_bufferedPoints[index] = item.translation(); |
132 | |
133 | if (index != m_oldRemoveIndex) { |
134 | glBufferSubData(GL_ARRAY_BUFFER, offset: index * sizeof(QVector3D), |
135 | size: sizeof(QVector3D), data: &m_bufferedPoints.at(i: index)); |
136 | } |
137 | } |
138 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
139 | } |
140 | } |
141 | |
142 | void ScatterPointBufferHelper::updateUVs(ScatterSeriesRenderCache *cache) |
143 | { |
144 | // It may be that the buffer hasn't yet been initialized, in case the entire series was |
145 | // hidden items. No need to update in that case. |
146 | if (m_indexCount > 0) { |
147 | QList<QVector2D> buffered_uvs; |
148 | createRangeGradientUVs(cache, buffered_uvs); |
149 | |
150 | if (buffered_uvs.size()) { |
151 | if (!m_uvbuffer) |
152 | glGenBuffers(n: 1, buffers: &m_uvbuffer); |
153 | |
154 | int updateSize = cache->updateIndices().size(); |
155 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_uvbuffer); |
156 | if (updateSize) { |
157 | for (int i = 0; i < updateSize; i++) { |
158 | int index = cache->updateIndices().at(i); |
159 | glBufferSubData(GL_ARRAY_BUFFER, offset: index * sizeof(QVector2D), |
160 | size: sizeof(QVector2D), data: &buffered_uvs.at(i)); |
161 | |
162 | } |
163 | } else { |
164 | glBufferData(GL_ARRAY_BUFFER, size: buffered_uvs.size() * sizeof(QVector2D), |
165 | data: &buffered_uvs.at(i: 0), GL_STATIC_DRAW); |
166 | } |
167 | |
168 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
169 | } |
170 | } |
171 | } |
172 | |
173 | void ScatterPointBufferHelper::createRangeGradientUVs(ScatterSeriesRenderCache *cache, |
174 | QList<QVector2D> &buffered_uvs) |
175 | { |
176 | const ScatterRenderItemArray &renderArray = cache->renderArray(); |
177 | const bool updateAll = (cache->updateIndices().size() == 0); |
178 | const int updateSize = updateAll ? renderArray.size() : cache->updateIndices().size(); |
179 | buffered_uvs.resize(size: updateSize); |
180 | |
181 | QVector2D uv; |
182 | uv.setX(0.0f); |
183 | for (int i = 0; i < updateSize; i++) { |
184 | int index = updateAll ? i : cache->updateIndices().at(i); |
185 | const ScatterRenderItem &item = renderArray.at(i: index); |
186 | |
187 | float y = ((item.translation().y() + m_scaleY) * 0.5f) / m_scaleY; |
188 | uv.setY(y); |
189 | buffered_uvs[i] = uv; |
190 | } |
191 | } |
192 | |
193 | QT_END_NAMESPACE |
194 | |