Krita Source Code Documentation
Loading...
Searching...
No Matches
KisGLImageWidget.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2019 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "KisGLImageWidget.h"
8
9#include <QPainter>
10#include <QFile>
11#include <QResizeEvent>
12#include <QVector3D>
13#include "kis_debug.h"
14#include <config-hdr.h>
15#include <opengl/kis_opengl.h>
16
17#include "KisGLImageF16.h"
18
19namespace {
20inline void rectToVertices(QVector3D* vertices, const QRectF &rc)
21{
22 vertices[0] = QVector3D(rc.left(), rc.bottom(), 0.f);
23 vertices[1] = QVector3D(rc.left(), rc.top(), 0.f);
24 vertices[2] = QVector3D(rc.right(), rc.bottom(), 0.f);
25 vertices[3] = QVector3D(rc.left(), rc.top(), 0.f);
26 vertices[4] = QVector3D(rc.right(), rc.top(), 0.f);
27 vertices[5] = QVector3D(rc.right(), rc.bottom(), 0.f);
28}
29
30inline void rectToTexCoords(QVector2D* texCoords, const QRectF &rc)
31{
32 texCoords[0] = QVector2D(rc.left(), rc.bottom());
33 texCoords[1] = QVector2D(rc.left(), rc.top());
34 texCoords[2] = QVector2D(rc.right(), rc.bottom());
35 texCoords[3] = QVector2D(rc.left(), rc.top());
36 texCoords[4] = QVector2D(rc.right(), rc.top());
37 texCoords[5] = QVector2D(rc.right(), rc.bottom());
38}
39}
40
42 : KisGLImageWidget(KisSurfaceColorSpaceWrapper::sRGBColorSpace, parent)
43{
44}
45
47 QWidget *parent)
48 : QOpenGLWidget(parent),
49 m_texture(QOpenGLTexture::Target2D)
50{
51 Q_UNUSED(colorSpace);
52
53 setTextureFormat(GL_RGBA16F);
54
55#ifdef HAVE_HDR
56 setTextureColorSpace(colorSpace);
57#endif
58
59 setUpdateBehavior(QOpenGLWidget::NoPartialUpdate);
60}
61
63{
64 // force releasing the resources on destruction
66}
67
69{
70 initializeOpenGLFunctions();
71
72 connect(context(), SIGNAL(aboutToBeDestroyed()), SLOT(slotOpenGLContextDestroyed()));
73 m_shader.reset(new QOpenGLShaderProgram);
74
75 QFile vertexShaderFile(QString(":/") + "kis_gl_image_widget.vert");
76 vertexShaderFile.open(QIODevice::ReadOnly);
77 QString vertSource = vertexShaderFile.readAll();
78
79 QFile fragShaderFile(QString(":/") + "kis_gl_image_widget.frag");
80 fragShaderFile.open(QIODevice::ReadOnly);
81 QString fragSource = fragShaderFile.readAll();
82
83 if (context()->isOpenGLES()) {
84 const char *versionHelper = "#define USE_OPENGLES\n";
85 vertSource.prepend(versionHelper);
86 fragSource.prepend(versionHelper);
87
88 const char *versionDefinition = "#version 100\n";
89 vertSource.prepend(versionDefinition);
90 fragSource.prepend(versionDefinition);
91 } else {
92#ifdef Q_OS_MACOS
93 const char *versionDefinition = KisOpenGL::supportsLoD() ? "#version 150\n" : "#version 120\n";
94#else
95 const char *versionDefinition = KisOpenGL::supportsLoD() ? "#version 130\n" : "#version 120\n";
96#endif
97 vertSource.prepend(versionDefinition);
98 fragSource.prepend(versionDefinition);
99 }
100
101 if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vertSource)) {
102 qDebug() << "Could not add vertex code";
103 return;
104 }
105
106 if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) {
107 qDebug() << "Could not add fragment code";
108 return;
109 }
110
111 if (!m_shader->link()) {
112 qDebug() << "Could not link";
113 return;
114 }
115
116 if (!m_shader->bind()) {
117 qDebug() << "Could not bind";
118 return;
119 }
120
121 m_shader->release();
122
123
124 m_vao.create();
125 m_vao.bind();
126
127 m_verticesBuffer.create();
128 updateVerticesBuffer(this->rect());
129
130 QVector<QVector2D> textureVertices(6);
131 rectToTexCoords(textureVertices.data(), QRect(0.0, 0.0, 1.0, 1.0));
132
135 m_textureVerticesBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
136 m_textureVerticesBuffer.allocate(2 * 3 * sizeof(QVector2D));
137 m_verticesBuffer.write(0, textureVertices.data(), m_textureVerticesBuffer.size());
138 m_textureVerticesBuffer.release();
139
140 m_vao.release();
141
142
143 if (!m_sourceImage.isNull()) {
145 }
146}
147
149{
150 this->makeCurrent();
151
152 m_shader.reset();
153 m_texture.destroy();
154 m_verticesBuffer.destroy();
155 m_textureVerticesBuffer.destroy();
156 m_vao.destroy();
158
159 this->doneCurrent();
160}
161
163{
164 if (!m_vao.isCreated() || !m_verticesBuffer.isCreated()) return;
165
166 QVector<QVector3D> vertices(6);
167 rectToVertices(vertices.data(), rect);
168
169 m_verticesBuffer.bind();
170 m_verticesBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
171 m_verticesBuffer.allocate(2 * 3 * sizeof(QVector3D));
172 m_verticesBuffer.write(0, vertices.data(), m_verticesBuffer.size());
173 m_verticesBuffer.release();
174}
175
176
178{
179 // TODO: fix conversion to the destination surface space
180 // Fill with bright color as as default for debugging purposes
181 // glClearColor(bgColor.redF(), bgColor.greenF(), bgColor.blueF(), 1.0f);
182 glClearColor(0.3, 0.2, 0.8, 1.0f);
183 glClear(GL_COLOR_BUFFER_BIT);
184
185
186
189
190 if (!m_texture.isCreated() ||
191 m_sourceImage.width() != m_texture.width() ||
192 m_sourceImage.height() != m_texture.height()) {
193
194 if (m_texture.isCreated()) {
195 m_texture.destroy();
196 }
197
198 m_texture.setFormat(QOpenGLTexture::RGBA16F);
200 m_texture.allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::Float16);
201 m_texture.setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
202 m_texture.setMagnificationFilter(QOpenGLTexture::Linear);
203 m_texture.setWrapMode(QOpenGLTexture::ClampToEdge);
204 }
205
206 m_texture.setData(QOpenGLTexture::RGBA, QOpenGLTexture::Float16, m_sourceImage.constData());
207 }
208
209 if (!m_texture.isCreated()) return;
210
211 m_vao.bind();
212 m_shader->bind();
213
214 {
215 QMatrix4x4 projectionMatrix;
216 projectionMatrix.setToIdentity();
217 projectionMatrix.ortho(0, width(), height(), 0, -1, 1);
218 QMatrix4x4 viewProjectionMatrix;
219
220 // use a QTransform to scale, translate, rotate your view
221 QTransform transform; // TODO: noop!
222 viewProjectionMatrix = projectionMatrix * QMatrix4x4(transform);
223
224 m_shader->setUniformValue("viewProjectionMatrix", viewProjectionMatrix);
225 }
226
227 m_shader->enableAttributeArray("vertexPosition");
228 m_verticesBuffer.bind();
229 m_shader->setAttributeBuffer("vertexPosition", GL_FLOAT, 0, 3);
230
231 m_shader->enableAttributeArray("texturePosition");
233 m_shader->setAttributeBuffer("texturePosition", GL_FLOAT, 0, 2);
234
235 glActiveTexture(GL_TEXTURE0);
236 m_texture.bind();
237
238 // draw 2 triangles = 6 vertices starting at offset 0 in the buffer
239 glDrawArrays(GL_TRIANGLES, 0, 6);
240
241 m_verticesBuffer.release();
242 m_textureVerticesBuffer.release();
243 m_texture.release();
244 m_shader->release();
245 m_vao.release();
246}
247
249{
250 if (m_sourceImage != image) {
251 m_sourceImage = image;
252 }
253
255
256
257 updateGeometry();
258 update();
259}
260
261void KisGLImageWidget::paintEvent(QPaintEvent *event)
262{
263 QOpenGLWidget::paintEvent(event);
264}
265
266void KisGLImageWidget::resizeEvent(QResizeEvent *event)
267{
268 updateVerticesBuffer(QRect(QPoint(),event->size()));
269 QOpenGLWidget::resizeEvent(event);
270}
271
273{
274 return m_sourceImage.size();
275}
276
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
int height() const
QSize size() const
bool isNull() const
const half * constData() const
int width() const
QOpenGLBuffer m_verticesBuffer
QOpenGLVertexArrayObject m_vao
QOpenGLBuffer m_textureVerticesBuffer
KisGLImageF16 m_sourceImage
KisGLImageWidget(QWidget *parent=nullptr)
void updateVerticesBuffer(const QRect &rect)
QOpenGLTexture m_texture
void loadImage(const KisGLImageF16 &image)
QSize sizeHint() const override
void resizeEvent(QResizeEvent *event) override
QScopedPointer< QOpenGLShaderProgram > m_shader
void paintGL() override
void initializeGL() override
void paintEvent(QPaintEvent *event) override
static bool supportsLoD()
void rectToTexCoords(QVector2D *texCoords, const QRectF &rc)
void rectToVertices(QVector3D *vertices, const QRectF &rc)