Changeset View
Changeset View
Standalone View
Standalone View
plugins/dockers/smallcolorselector/KisGLImageWidget.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * Copyright (c) 2019 Dmitry Kazakov <dimula73@gmail.com> | ||||
3 | * | ||||
4 | * This program is free software; you can redistribute it and/or modify | ||||
5 | * it under the terms of the GNU General Public License as published by | ||||
6 | * the Free Software Foundation; either version 2 of the License, or | ||||
7 | * (at your option) any later version. | ||||
8 | * | ||||
9 | * This program is distributed in the hope that it will be useful, | ||||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
12 | * GNU General Public License for more details. | ||||
13 | * | ||||
14 | * You should have received a copy of the GNU General Public License | ||||
15 | * along with this program; if not, write to the Free Software | ||||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
17 | */ | ||||
18 | | ||||
19 | #include "KisGLImageWidget.h" | ||||
20 | | ||||
21 | #include <QPainter> | ||||
22 | #include <QFile> | ||||
23 | #include <QResizeEvent> | ||||
24 | #include "kis_debug.h" | ||||
25 | #include <config-hdr.h> | ||||
26 | | ||||
27 | #include "KisGLImageF16.h" | ||||
28 | | ||||
29 | namespace { | ||||
30 | inline void rectToVertices(QVector3D* vertices, const QRectF &rc) | ||||
31 | { | ||||
32 | vertices[0] = QVector3D(rc.left(), rc.bottom(), 0.f); | ||||
33 | vertices[1] = QVector3D(rc.left(), rc.top(), 0.f); | ||||
34 | vertices[2] = QVector3D(rc.right(), rc.bottom(), 0.f); | ||||
35 | vertices[3] = QVector3D(rc.left(), rc.top(), 0.f); | ||||
36 | vertices[4] = QVector3D(rc.right(), rc.top(), 0.f); | ||||
37 | vertices[5] = QVector3D(rc.right(), rc.bottom(), 0.f); | ||||
38 | } | ||||
39 | | ||||
40 | inline void rectToTexCoords(QVector2D* texCoords, const QRectF &rc) | ||||
41 | { | ||||
42 | texCoords[0] = QVector2D(rc.left(), rc.bottom()); | ||||
43 | texCoords[1] = QVector2D(rc.left(), rc.top()); | ||||
44 | texCoords[2] = QVector2D(rc.right(), rc.bottom()); | ||||
45 | texCoords[3] = QVector2D(rc.left(), rc.top()); | ||||
46 | texCoords[4] = QVector2D(rc.right(), rc.top()); | ||||
47 | texCoords[5] = QVector2D(rc.right(), rc.bottom()); | ||||
48 | } | ||||
49 | } | ||||
50 | | ||||
51 | KisGLImageWidget::KisGLImageWidget(QWidget *parent) | ||||
52 | : KisGLImageWidget(QSurfaceFormat::sRGBColorSpace, parent) | ||||
53 | { | ||||
54 | } | ||||
55 | | ||||
56 | KisGLImageWidget::KisGLImageWidget(QSurfaceFormat::ColorSpace colorSpace, | ||||
57 | QWidget *parent) | ||||
58 | : QOpenGLWidget(parent), | ||||
59 | m_texture(QOpenGLTexture::Target2D) | ||||
60 | { | ||||
61 | setTextureFormat(GL_RGBA16F); | ||||
62 | | ||||
63 | #ifdef HAVE_HDR | ||||
64 | setTextureColorSpace(colorSpace); | ||||
65 | #endif | ||||
66 | | ||||
67 | setUpdateBehavior(QOpenGLWidget::NoPartialUpdate); | ||||
68 | } | ||||
69 | | ||||
70 | void KisGLImageWidget::initializeGL() | ||||
71 | { | ||||
72 | initializeOpenGLFunctions(); | ||||
73 | | ||||
74 | connect(context(), SIGNAL(aboutToBeDestroyed()), SLOT(slotOpenGLContextDestroyed())); | ||||
75 | m_shader.reset(new QOpenGLShaderProgram); | ||||
76 | | ||||
77 | QFile vertexShaderFile(QString(":/") + "kis_gl_image_widget.vert"); | ||||
78 | vertexShaderFile.open(QIODevice::ReadOnly); | ||||
79 | QString vertSource = vertexShaderFile.readAll(); | ||||
80 | | ||||
81 | QFile fragShaderFile(QString(":/") + "kis_gl_image_widget.frag"); | ||||
82 | fragShaderFile.open(QIODevice::ReadOnly); | ||||
83 | QString fragSource = fragShaderFile.readAll(); | ||||
84 | | ||||
85 | if (context()->isOpenGLES()) { | ||||
86 | const char *versionHelper = "#define USE_OPENGLES\n"; | ||||
87 | vertSource.prepend(versionHelper); | ||||
88 | fragSource.prepend(versionHelper); | ||||
89 | | ||||
90 | const char *versionDefinition = "#version 100\n"; | ||||
91 | vertSource.prepend(versionDefinition); | ||||
92 | fragSource.prepend(versionDefinition); | ||||
93 | } else { | ||||
94 | const char *versionDefinition = "#version 330 core\n"; | ||||
95 | vertSource.prepend(versionDefinition); | ||||
96 | fragSource.prepend(versionDefinition); | ||||
97 | } | ||||
98 | | ||||
99 | if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vertSource)) { | ||||
100 | qDebug() << "Could not add vertex code"; | ||||
101 | return; | ||||
102 | } | ||||
103 | | ||||
104 | if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) { | ||||
105 | qDebug() << "Could not add fragment code"; | ||||
106 | return; | ||||
107 | } | ||||
108 | | ||||
109 | if (!m_shader->link()) { | ||||
110 | qDebug() << "Could not link"; | ||||
111 | return; | ||||
112 | } | ||||
113 | | ||||
114 | if (!m_shader->bind()) { | ||||
115 | qDebug() << "Could not bind"; | ||||
116 | return; | ||||
117 | } | ||||
118 | | ||||
119 | m_shader->release(); | ||||
120 | | ||||
121 | | ||||
122 | m_vao.create(); | ||||
123 | m_vao.bind(); | ||||
124 | | ||||
125 | m_verticesBuffer.create(); | ||||
126 | updateVerticesBuffer(this->rect()); | ||||
127 | | ||||
128 | QVector<QVector2D> textureVertices(6); | ||||
129 | rectToTexCoords(textureVertices.data(), QRect(0.0, 0.0, 1.0, 1.0)); | ||||
130 | | ||||
131 | m_textureVerticesBuffer.create(); | ||||
132 | m_textureVerticesBuffer.bind(); | ||||
133 | m_textureVerticesBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); | ||||
134 | m_textureVerticesBuffer.allocate(2 * 3 * sizeof(QVector2D)); | ||||
135 | m_verticesBuffer.write(0, textureVertices.data(), m_textureVerticesBuffer.size()); | ||||
136 | m_textureVerticesBuffer.release(); | ||||
137 | | ||||
138 | m_vao.release(); | ||||
139 | | ||||
140 | | ||||
141 | if (!m_sourceImage.isNull()) { | ||||
142 | loadImage(m_sourceImage); | ||||
143 | } | ||||
144 | } | ||||
145 | | ||||
146 | void KisGLImageWidget::slotOpenGLContextDestroyed() | ||||
147 | { | ||||
148 | this->makeCurrent(); | ||||
149 | | ||||
150 | m_shader.reset(); | ||||
151 | m_texture.destroy(); | ||||
152 | m_verticesBuffer.destroy(); | ||||
153 | m_textureVerticesBuffer.destroy(); | ||||
154 | m_vao.destroy(); | ||||
155 | m_havePendingTextureUpdate = false; | ||||
156 | | ||||
157 | this->doneCurrent(); | ||||
158 | } | ||||
159 | | ||||
160 | void KisGLImageWidget::updateVerticesBuffer(const QRect &rect) | ||||
161 | { | ||||
162 | if (!m_vao.isCreated() || !m_verticesBuffer.isCreated()) return; | ||||
163 | | ||||
164 | QVector<QVector3D> vertices(6); | ||||
165 | rectToVertices(vertices.data(), rect); | ||||
166 | | ||||
167 | m_verticesBuffer.bind(); | ||||
168 | m_verticesBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); | ||||
169 | m_verticesBuffer.allocate(2 * 3 * sizeof(QVector3D)); | ||||
170 | m_verticesBuffer.write(0, vertices.data(), m_verticesBuffer.size()); | ||||
171 | m_verticesBuffer.release(); | ||||
172 | } | ||||
173 | | ||||
174 | | ||||
175 | void KisGLImageWidget::paintGL() | ||||
176 | { | ||||
177 | const QColor bgColor = palette().background().color(); | ||||
178 | // TODO: fix conversion to the destination surface space | ||||
179 | //glClearColor(bgColor.redF(), bgColor.greenF(), bgColor.blueF(), 1.0f); | ||||
180 | glClearColor(0.3, 0.2, 0.8, 1.0f); | ||||
181 | glClear(GL_COLOR_BUFFER_BIT); | ||||
182 | | ||||
183 | | ||||
184 | | ||||
185 | if (m_havePendingTextureUpdate) { | ||||
186 | m_havePendingTextureUpdate = false; | ||||
187 | | ||||
188 | if (!m_texture.isCreated() || | ||||
189 | m_sourceImage.width() != m_texture.width() || | ||||
190 | m_sourceImage.height() != m_texture.height()) { | ||||
191 | | ||||
192 | if (m_texture.isCreated()) { | ||||
193 | m_texture.destroy(); | ||||
194 | } | ||||
195 | | ||||
196 | m_texture.setFormat(QOpenGLTexture::RGBA16F); | ||||
197 | m_texture.setSize(m_sourceImage.width(), m_sourceImage.height()); | ||||
198 | m_texture.allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::Float16); | ||||
199 | m_texture.setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); | ||||
200 | m_texture.setMagnificationFilter(QOpenGLTexture::Linear); | ||||
201 | m_texture.setWrapMode(QOpenGLTexture::ClampToEdge); | ||||
202 | } | ||||
203 | | ||||
204 | m_texture.setData(QOpenGLTexture::RGBA, QOpenGLTexture::Float16, m_sourceImage.constData()); | ||||
205 | } | ||||
206 | | ||||
207 | if (!m_texture.isCreated()) return; | ||||
208 | | ||||
209 | m_vao.bind(); | ||||
210 | m_shader->bind(); | ||||
211 | | ||||
212 | { | ||||
213 | QMatrix4x4 projectionMatrix; | ||||
214 | projectionMatrix.setToIdentity(); | ||||
215 | projectionMatrix.ortho(0, width(), height(), 0, -1, 1); | ||||
216 | QMatrix4x4 viewProjectionMatrix; | ||||
217 | | ||||
218 | // use a QTransform to scale, translate, rotate your view | ||||
219 | QTransform transform; // TODO: noop! | ||||
220 | viewProjectionMatrix = projectionMatrix * QMatrix4x4(transform); | ||||
221 | | ||||
222 | m_shader->setUniformValue("viewProjectionMatrix", viewProjectionMatrix); | ||||
223 | } | ||||
224 | | ||||
225 | m_shader->enableAttributeArray("vertexPosition"); | ||||
226 | m_verticesBuffer.bind(); | ||||
227 | m_shader->setAttributeBuffer("vertexPosition", GL_FLOAT, 0, 3); | ||||
228 | | ||||
229 | m_shader->enableAttributeArray("texturePosition"); | ||||
230 | m_textureVerticesBuffer.bind(); | ||||
231 | m_shader->setAttributeBuffer("texturePosition", GL_FLOAT, 0, 2); | ||||
232 | | ||||
233 | glActiveTexture(GL_TEXTURE0); | ||||
234 | m_texture.bind(); | ||||
235 | | ||||
236 | // draw 2 triangles = 6 vertices starting at offset 0 in the buffer | ||||
237 | glDrawArrays(GL_TRIANGLES, 0, 6); | ||||
238 | | ||||
239 | m_verticesBuffer.release(); | ||||
240 | m_textureVerticesBuffer.release(); | ||||
241 | m_texture.release(); | ||||
242 | m_shader->release(); | ||||
243 | m_vao.release(); | ||||
244 | } | ||||
245 | | ||||
246 | void KisGLImageWidget::loadImage(const KisGLImageF16 &image) | ||||
247 | { | ||||
248 | if (m_sourceImage != image) { | ||||
249 | m_sourceImage = image; | ||||
250 | } | ||||
251 | | ||||
252 | m_havePendingTextureUpdate = true; | ||||
253 | | ||||
254 | | ||||
255 | updateGeometry(); | ||||
256 | update(); | ||||
257 | } | ||||
258 | | ||||
259 | void KisGLImageWidget::paintEvent(QPaintEvent *event) | ||||
260 | { | ||||
261 | QOpenGLWidget::paintEvent(event); | ||||
262 | } | ||||
263 | | ||||
264 | void KisGLImageWidget::resizeEvent(QResizeEvent *event) | ||||
265 | { | ||||
266 | updateVerticesBuffer(QRect(QPoint(),event->size())); | ||||
267 | QOpenGLWidget::resizeEvent(event); | ||||
268 | } | ||||
269 | | ||||
270 | QSize KisGLImageWidget::sizeHint() const | ||||
271 | { | ||||
272 | return m_sourceImage.size(); | ||||
273 | } | ||||
274 | |