1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Data Visualization module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 or (at your option) any later version |
20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by |
21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #include "scatterpointbufferhelper_p.h" |
31 | #include <QtGui/QVector2D> |
32 | |
33 | QT_BEGIN_NAMESPACE_DATAVISUALIZATION |
34 | |
35 | const QVector3D hiddenPos(-1000.0f, -1000.0f, -1000.0f); |
36 | |
37 | ScatterPointBufferHelper::ScatterPointBufferHelper() |
38 | : m_pointbuffer(0), |
39 | m_oldRemoveIndex(-1) |
40 | { |
41 | } |
42 | |
43 | ScatterPointBufferHelper::~ScatterPointBufferHelper() |
44 | { |
45 | if (QOpenGLContext::currentContext()) |
46 | glDeleteBuffers(n: 1, buffers: &m_pointbuffer); |
47 | } |
48 | |
49 | GLuint ScatterPointBufferHelper::pointBuf() |
50 | { |
51 | if (!m_meshDataLoaded) |
52 | qFatal(msg: "No loaded object" ); |
53 | return m_pointbuffer; |
54 | } |
55 | |
56 | void ScatterPointBufferHelper::pushPoint(uint pointIndex) |
57 | { |
58 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_pointbuffer); |
59 | |
60 | // Pop the previous point if it is still pushed |
61 | if (m_oldRemoveIndex >= 0) { |
62 | glBufferSubData(GL_ARRAY_BUFFER, offset: m_oldRemoveIndex * sizeof(QVector3D), |
63 | size: sizeof(QVector3D), data: &m_bufferedPoints.at(i: m_oldRemoveIndex)); |
64 | } |
65 | |
66 | glBufferSubData(GL_ARRAY_BUFFER, offset: pointIndex * sizeof(QVector3D), |
67 | size: sizeof(QVector3D), |
68 | data: &hiddenPos); |
69 | |
70 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
71 | |
72 | m_oldRemoveIndex = pointIndex; |
73 | } |
74 | |
75 | void ScatterPointBufferHelper::popPoint() |
76 | { |
77 | if (m_oldRemoveIndex >= 0) { |
78 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_pointbuffer); |
79 | glBufferSubData(GL_ARRAY_BUFFER, offset: m_oldRemoveIndex * sizeof(QVector3D), |
80 | size: sizeof(QVector3D), data: &m_bufferedPoints.at(i: m_oldRemoveIndex)); |
81 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
82 | } |
83 | |
84 | m_oldRemoveIndex = -1; |
85 | } |
86 | |
87 | void ScatterPointBufferHelper::load(ScatterSeriesRenderCache *cache) |
88 | { |
89 | ScatterRenderItemArray &renderArray = cache->renderArray(); |
90 | const int renderArraySize = renderArray.size(); |
91 | m_indexCount = 0; |
92 | |
93 | if (m_meshDataLoaded) { |
94 | // Delete old data |
95 | glDeleteBuffers(n: 1, buffers: &m_pointbuffer); |
96 | glDeleteBuffers(n: 1, buffers: &m_uvbuffer); |
97 | m_bufferedPoints.clear(); |
98 | m_pointbuffer = 0; |
99 | m_uvbuffer = 0; |
100 | m_meshDataLoaded = false; |
101 | } |
102 | |
103 | bool itemsVisible = false; |
104 | m_bufferedPoints.resize(asize: renderArraySize); |
105 | for (int i = 0; i < renderArraySize; i++) { |
106 | const ScatterRenderItem &item = renderArray.at(i); |
107 | if (!item.isVisible()) { |
108 | m_bufferedPoints[i] = hiddenPos; |
109 | } else { |
110 | itemsVisible = true; |
111 | m_bufferedPoints[i] = item.translation(); |
112 | } |
113 | } |
114 | |
115 | QVector<QVector2D> buffered_uvs; |
116 | if (itemsVisible) |
117 | m_indexCount = renderArraySize; |
118 | |
119 | if (m_indexCount > 0) { |
120 | if (cache->colorStyle() == Q3DTheme::ColorStyleRangeGradient) |
121 | createRangeGradientUVs(cache, buffered_uvs); |
122 | |
123 | glGenBuffers(n: 1, buffers: &m_pointbuffer); |
124 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_pointbuffer); |
125 | glBufferData(GL_ARRAY_BUFFER, size: m_bufferedPoints.size() * sizeof(QVector3D), |
126 | data: &m_bufferedPoints.at(i: 0), |
127 | GL_DYNAMIC_DRAW); |
128 | |
129 | if (buffered_uvs.size()) { |
130 | glGenBuffers(n: 1, buffers: &m_uvbuffer); |
131 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_uvbuffer); |
132 | glBufferData(GL_ARRAY_BUFFER, size: buffered_uvs.size() * sizeof(QVector2D), |
133 | data: &buffered_uvs.at(i: 0), GL_STATIC_DRAW); |
134 | } |
135 | |
136 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
137 | |
138 | m_meshDataLoaded = true; |
139 | } |
140 | } |
141 | |
142 | void ScatterPointBufferHelper::update(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 | const ScatterRenderItemArray &renderArray = cache->renderArray(); |
148 | const int updateSize = cache->updateIndices().size(); |
149 | |
150 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_pointbuffer); |
151 | for (int i = 0; i < updateSize; i++) { |
152 | int index = cache->updateIndices().at(i); |
153 | const ScatterRenderItem &item = renderArray.at(i: index); |
154 | if (!item.isVisible()) |
155 | m_bufferedPoints[index] = hiddenPos; |
156 | else |
157 | m_bufferedPoints[index] = item.translation(); |
158 | |
159 | if (index != m_oldRemoveIndex) { |
160 | glBufferSubData(GL_ARRAY_BUFFER, offset: index * sizeof(QVector3D), |
161 | size: sizeof(QVector3D), data: &m_bufferedPoints.at(i: index)); |
162 | } |
163 | } |
164 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
165 | } |
166 | } |
167 | |
168 | void ScatterPointBufferHelper::updateUVs(ScatterSeriesRenderCache *cache) |
169 | { |
170 | // It may be that the buffer hasn't yet been initialized, in case the entire series was |
171 | // hidden items. No need to update in that case. |
172 | if (m_indexCount > 0) { |
173 | QVector<QVector2D> buffered_uvs; |
174 | createRangeGradientUVs(cache, buffered_uvs); |
175 | |
176 | if (buffered_uvs.size()) { |
177 | if (!m_uvbuffer) |
178 | glGenBuffers(n: 1, buffers: &m_uvbuffer); |
179 | |
180 | int updateSize = cache->updateIndices().size(); |
181 | glBindBuffer(GL_ARRAY_BUFFER, buffer: m_uvbuffer); |
182 | if (updateSize) { |
183 | for (int i = 0; i < updateSize; i++) { |
184 | int index = cache->updateIndices().at(i); |
185 | glBufferSubData(GL_ARRAY_BUFFER, offset: index * sizeof(QVector2D), |
186 | size: sizeof(QVector2D), data: &buffered_uvs.at(i)); |
187 | |
188 | } |
189 | } else { |
190 | glBufferData(GL_ARRAY_BUFFER, size: buffered_uvs.size() * sizeof(QVector2D), |
191 | data: &buffered_uvs.at(i: 0), GL_STATIC_DRAW); |
192 | } |
193 | |
194 | glBindBuffer(GL_ARRAY_BUFFER, buffer: 0); |
195 | } |
196 | } |
197 | } |
198 | |
199 | void ScatterPointBufferHelper::createRangeGradientUVs(ScatterSeriesRenderCache *cache, |
200 | QVector<QVector2D> &buffered_uvs) |
201 | { |
202 | const ScatterRenderItemArray &renderArray = cache->renderArray(); |
203 | const bool updateAll = (cache->updateIndices().size() == 0); |
204 | const int updateSize = updateAll ? renderArray.size() : cache->updateIndices().size(); |
205 | buffered_uvs.resize(asize: updateSize); |
206 | |
207 | QVector2D uv; |
208 | uv.setX(0.0f); |
209 | for (int i = 0; i < updateSize; i++) { |
210 | int index = updateAll ? i : cache->updateIndices().at(i); |
211 | const ScatterRenderItem &item = renderArray.at(i: index); |
212 | |
213 | float y = ((item.translation().y() + m_scaleY) * 0.5f) / m_scaleY; |
214 | uv.setY(y); |
215 | buffered_uvs[i] = uv; |
216 | } |
217 | } |
218 | |
219 | QT_END_NAMESPACE_DATAVISUALIZATION |
220 | |