| 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 | |