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 if (!vertexShaderFile.open(QIODevice::ReadOnly)) {
77 qDebug() << "Could not open vertex code";
78 return;
79 }
80 QString vertSource = vertexShaderFile.readAll();
81
82 QFile fragShaderFile(QString(":/") + "kis_gl_image_widget.frag");
83 if (!fragShaderFile.open(QIODevice::ReadOnly)) {
84 qDebug() << "Could not open fragment code";
85 return;
86 }
87 QString fragSource = fragShaderFile.readAll();
88
89 if (context()->isOpenGLES()) {
90 const char *versionHelper = "#define USE_OPENGLES\n";
91 vertSource.prepend(versionHelper);
92 fragSource.prepend(versionHelper);
93
94 const char *versionDefinition = "#version 100\n";
95 vertSource.prepend(versionDefinition);
96 fragSource.prepend(versionDefinition);
97 } else {
98#ifdef Q_OS_MACOS
99 const char *versionDefinition = KisOpenGL::supportsLoD() ? "#version 150\n" : "#version 120\n";
100#else
101 const char *versionDefinition = KisOpenGL::supportsLoD() ? "#version 130\n" : "#version 120\n";
102#endif
103 vertSource.prepend(versionDefinition);
104 fragSource.prepend(versionDefinition);
105 }
106
107 if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vertSource)) {
108 qDebug() << "Could not add vertex code";
109 return;
110 }
111
112 if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) {
113 qDebug() << "Could not add fragment code";
114 return;
115 }
116
117 if (!m_shader->link()) {
118 qDebug() << "Could not link";
119 return;
120 }
121
122 if (!m_shader->bind()) {
123 qDebug() << "Could not bind";
124 return;
125 }
126
127 m_shader->release();
128
129
130 m_vao.create();
131 m_vao.bind();
132
133 m_verticesBuffer.create();
134 updateVerticesBuffer(this->rect());
135
136 QVector<QVector2D> textureVertices(6);
137 rectToTexCoords(textureVertices.data(), QRect(0.0, 0.0, 1.0, 1.0));
138
141 m_textureVerticesBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
142 m_textureVerticesBuffer.allocate(2 * 3 * sizeof(QVector2D));
143 m_verticesBuffer.write(0, textureVertices.data(), m_textureVerticesBuffer.size());
144 m_textureVerticesBuffer.release();
145
146 m_vao.release();
147
148
149 if (!m_sourceImage.isNull()) {
151 }
152}
153
155{
156 this->makeCurrent();
157
158 m_shader.reset();
159 m_texture.destroy();
160 m_verticesBuffer.destroy();
161 m_textureVerticesBuffer.destroy();
162 m_vao.destroy();
164
165 this->doneCurrent();
166}
167
169{
170 if (!m_vao.isCreated() || !m_verticesBuffer.isCreated()) return;
171
172 QVector<QVector3D> vertices(6);
173 rectToVertices(vertices.data(), rect);
174
175 m_verticesBuffer.bind();
176 m_verticesBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
177 m_verticesBuffer.allocate(2 * 3 * sizeof(QVector3D));
178 m_verticesBuffer.write(0, vertices.data(), m_verticesBuffer.size());
179 m_verticesBuffer.release();
180}
181
182
184{
185 // TODO: fix conversion to the destination surface space
186 // Fill with bright color as as default for debugging purposes
187 // glClearColor(bgColor.redF(), bgColor.greenF(), bgColor.blueF(), 1.0f);
188 glClearColor(0.3, 0.2, 0.8, 1.0f);
189 glClear(GL_COLOR_BUFFER_BIT);
190
191
192
195
196 if (!m_texture.isCreated() ||
197 m_sourceImage.width() != m_texture.width() ||
198 m_sourceImage.height() != m_texture.height()) {
199
200 if (m_texture.isCreated()) {
201 m_texture.destroy();
202 }
203
204 m_texture.setFormat(QOpenGLTexture::RGBA16F);
206 m_texture.allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::Float16);
207 m_texture.setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
208 m_texture.setMagnificationFilter(QOpenGLTexture::Linear);
209 m_texture.setWrapMode(QOpenGLTexture::ClampToEdge);
210 }
211
212 m_texture.setData(QOpenGLTexture::RGBA, QOpenGLTexture::Float16, m_sourceImage.constData());
213 }
214
215 if (!m_texture.isCreated()) return;
216
217 m_vao.bind();
218 m_shader->bind();
219
220 {
221 QMatrix4x4 projectionMatrix;
222 projectionMatrix.setToIdentity();
223 projectionMatrix.ortho(0, width(), height(), 0, -1, 1);
224 QMatrix4x4 viewProjectionMatrix;
225
226 // use a QTransform to scale, translate, rotate your view
227 QTransform transform; // TODO: noop!
228 viewProjectionMatrix = projectionMatrix * QMatrix4x4(transform);
229
230 m_shader->setUniformValue("viewProjectionMatrix", viewProjectionMatrix);
231 }
232
233 m_shader->enableAttributeArray("vertexPosition");
234 m_verticesBuffer.bind();
235 m_shader->setAttributeBuffer("vertexPosition", GL_FLOAT, 0, 3);
236
237 m_shader->enableAttributeArray("texturePosition");
239 m_shader->setAttributeBuffer("texturePosition", GL_FLOAT, 0, 2);
240
241 glActiveTexture(GL_TEXTURE0);
242 m_texture.bind();
243
244 // draw 2 triangles = 6 vertices starting at offset 0 in the buffer
245 glDrawArrays(GL_TRIANGLES, 0, 6);
246
247 m_verticesBuffer.release();
248 m_textureVerticesBuffer.release();
249 m_texture.release();
250 m_shader->release();
251 m_vao.release();
252}
253
255{
256 if (m_sourceImage != image) {
257 m_sourceImage = image;
258 }
259
261
262
263 updateGeometry();
264 update();
265}
266
267void KisGLImageWidget::paintEvent(QPaintEvent *event)
268{
269 QOpenGLWidget::paintEvent(event);
270}
271
272void KisGLImageWidget::resizeEvent(QResizeEvent *event)
273{
274 updateVerticesBuffer(QRect(QPoint(),event->size()));
275 QOpenGLWidget::resizeEvent(event);
276}
277
279{
280 return m_sourceImage.size();
281}
282
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)