Developer documentation
Version 3.0.3-105-gd3941f44
gl.h
Go to the documentation of this file.
1/* Copyright (c) 2008-2022 the MRtrix3 contributors.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 *
7 * Covered Software is provided under this License on an "as is"
8 * basis, without warranty of any kind, either expressed, implied, or
9 * statutory, including, without limitation, warranties that the
10 * Covered Software is free of defects, merchantable, fit for a
11 * particular purpose or non-infringing.
12 * See the Mozilla Public License v. 2.0 for more details.
13 *
14 * For more details, see http://www.mrtrix.org/.
15 */
16
17#ifndef __gui_opengl_gl_h__
18#define __gui_opengl_gl_h__
19
20#include "mrtrix.h"
21#include "debug.h"
22
23#include <QtGlobal>
24#if QT_VERSION >= 0x050000
25#include <QtWidgets>
26#else
27#include <QtGui>
28#endif
29#include <QGLWidget>
30#include "gui/opengl/gl_core_3_3.h"
31
32// necessary to avoid conflict with Qt4's macros:
33#ifdef Complex
34# undef Complex
35#endif
36#ifdef foreach
37# undef foreach
38#endif
39
40// uncomment to trace texture/VAO/VBO/FBO operations:
41//#define GL_SHOW_DEBUG_MESSAGE
42
43#ifdef GL_SHOW_DEBUG_MESSAGE
44# define GL_DEBUG(msg) DEBUG(msg)
45#else
46# define GL_DEBUG(msg) (void)0
47#endif
48
49#ifdef NDEBUG
50# define GL_CHECK_ERROR
51#else
52# define GL_CHECK_ERROR ::MR::GUI::GL::check_error (__FILE__, __LINE__)
53#endif
54
55
56#define GLGETBOOL(x,n) { GLboolean __v[n]; gl::GetBooleanv (x, __v); std::cerr << #x " = "; for (auto i : __v) std::cerr << int(i) << " "; std::cerr << "\n"; }
57#define GLGETINT(x,n) { GLint __v[n]; gl::GetIntegerv (x, __v); std::cerr << #x " = "; for (auto i : __v) std::cerr << int(i) << " "; std::cerr << "\n"; }
58
59namespace MR
60{
61 namespace GUI
62 {
63 namespace GL
64 {
65
66
67
68#if QT_VERSION >= 0x050400
69
70 using Area = QOpenGLWidget;
71 using Format = QSurfaceFormat;
72
73#else
74 class Area : public QGLWidget { NOMEMALIGN
75 public:
76 using QGLWidget::QGLWidget;
77 QImage grabFramebuffer () { return QGLWidget::grabFrameBuffer(); }
78 };
79
80 using Format = QGLFormat;
81#endif
82
83 void init ();
85
86 const char* ErrorString (GLenum errorcode);
87
88 inline void check_error (const char* filename, int line) {
89 GLenum err = gl::GetError();
90 while (err) {
91 FAIL (std::string ("[") + filename + ": " + str(line) + "] OpenGL error: " + ErrorString (err));
92 err = gl::GetError();
93 }
94 }
95
96
97
98#ifndef NDEBUG
99 void __assert_context_is_current (QWidget* glarea);
100 inline void assert_context_is_current(QWidget* glarea = nullptr) { __assert_context_is_current (glarea); }
101#else
102 inline void assert_context_is_current(QWidget* = nullptr) { }
103#endif
104
105 extern Area* glwidget;
106
107
108 namespace Context
109 {
110#if QT_VERSION >= 0x050400
111 inline std::pair<QOpenGLContext*,QSurface*> current() {
112 QOpenGLContext* context = QOpenGLContext::currentContext();
113 QSurface* surface = context ? context->surface() : nullptr;
114 return { context, surface };
115 }
116
117 inline std::pair<QOpenGLContext*,QSurface*> get (QWidget* window) {
118 QOpenGLContext* context = reinterpret_cast<QOpenGLWidget*> (window)->context();
119 QSurface* surface = context ? context->surface() : nullptr;
120 return { context, surface };
121 }
122
123 inline std::pair<QOpenGLContext*,QSurface*> makeCurrent (QWidget* window) {
124 auto previous_context = current();
125 if (window)
126 reinterpret_cast<QOpenGLWidget*> (window)->makeCurrent();
127 return previous_context;
128 }
129
130 inline void restore (std::pair<QOpenGLContext*,QSurface*> previous_context) {
131 if (previous_context.first)
132 previous_context.first->makeCurrent (previous_context.second);
133 }
134#else
135 inline std::pair<int,int> current() { return { 0, 0 }; }
136 inline std::pair<int,int> get (QWidget*) { return { 0, 0 }; }
137 inline std::pair<int,int> makeCurrent (QWidget*) { return { 0, 0 }; }
138 inline void restore (std::pair<int,int>) { }
139#endif
140
143 Grab (QWidget* window = nullptr) : previous_context (makeCurrent (window ? window : GL::glwidget)) {
145 }
147 };
148
149#ifndef NDEBUG
152 void set () { original_context = current(); }
153 void operator() () const { assert (current() == original_context); }
154 };
155#else
156 struct Checker { NOMEMALIGN
157 void set () { }
158 void operator() () const { }
159 };
160#endif
161 }
162
163
164
166 public:
167 Texture () : id (0), tex_type (0) { }
168 ~Texture () { clear(); }
169 Texture (const Texture&) : id (0), tex_type (0) { }
170 Texture (Texture&& t) : id (t.id), tex_type (t.tex_type) { t.id = t.tex_type = 0; }
171 Texture& operator= (Texture&& t) { clear(); id = t.id; tex_type = t.tex_type; t.id = t.tex_type = 0; return *this; }
172 void cache_copy(const Texture& t) { id = t.id; tex_type = t.tex_type; }
173 operator GLuint () const { return id; }
174 void gen (GLenum target, GLint interp_type = gl::LINEAR) {
175 if (!id) {
177 tex_type = target;
178 gl::GenTextures (1, &id);
179 GL_DEBUG ("created OpenGL texture ID " + str(id));
180 bind();
181 gl::TexParameteri (tex_type, gl::TEXTURE_BASE_LEVEL, 0);
182 gl::TexParameteri (tex_type, gl::TEXTURE_MAX_LEVEL, 0);
183 gl::TexParameteri (tex_type, gl::TEXTURE_MAG_FILTER, interp_type);
184 gl::TexParameteri (tex_type, gl::TEXTURE_MIN_FILTER, interp_type);
185 gl::TexParameteri (tex_type, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
186 gl::TexParameteri (tex_type, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
187 if (tex_type == gl::TEXTURE_3D)
188 gl::TexParameteri (tex_type, gl::TEXTURE_WRAP_R, gl::CLAMP_TO_EDGE);
189 }
190 }
191 GLenum type () const { return tex_type; }
192 void clear () {
193 if (id) {
195 GL_DEBUG ("deleting OpenGL texture ID " + str(id));
196 gl::DeleteTextures (1, &id);
197 }
198 id = 0;
199 tex_type = 0;
200 }
201 void bind () const {
202 assert (id);
204 GL_DEBUG ("binding OpenGL texture ID " + str(id));
205 gl::BindTexture (tex_type, id);
206 }
207 void set_interp (GLint type) const {
208 bind();
209 gl::TexParameteri (tex_type, gl::TEXTURE_MAG_FILTER, type);
210 gl::TexParameteri (tex_type, gl::TEXTURE_MIN_FILTER, type);
211 }
212 void set_interp_on (bool interpolate) const { set_interp (interpolate ? gl::LINEAR : gl::NEAREST); }
213 protected:
215 GLuint id;
216 GLenum tex_type;
217 };
218
219
221 public:
222 VertexBuffer () : id (0) { }
224 VertexBuffer (const VertexBuffer&) : id (0) { }
225 VertexBuffer (VertexBuffer&& t) : id (t.id) { t.id = 0; }
226 VertexBuffer& operator= (VertexBuffer&& t) { clear(); id = t.id; t.id = 0; return *this; }
227 operator GLuint () const { return id; }
228 void gen () {
229 if (!id) {
231 gl::GenBuffers (1, &id);
232 GL_DEBUG ("created OpenGL vertex buffer ID " + str(id));
233 }
234 }
235 void clear () {
236 if (id) {
238 GL_DEBUG ("deleting OpenGL vertex buffer ID " + str(id));
239 gl::DeleteBuffers (1, &id);
240 id = 0;
241 }
242 }
243 void bind (GLenum target) const {
244 assert (id);
246 GL_DEBUG ("binding OpenGL vertex buffer ID " + str(id));
247 gl::BindBuffer (target, id);
248 }
249 protected:
251 GLuint id;
252 };
253
254
256 public:
260 VertexArrayObject (VertexArrayObject&& t) : id (t.id) { t.id = 0; }
261 VertexArrayObject& operator= (VertexArrayObject&& t) { clear(); id = t.id; t.id = 0; return *this; }
262 operator GLuint () const { return id; }
263 void gen () {
264 if (!id) {
266 gl::GenVertexArrays (1, &id);
267 GL_DEBUG ("created OpenGL vertex array ID " + str(id));
268 }
269 }
270 void clear () {
271 if (id) {
273 GL_DEBUG ("deleting OpenGL vertex array ID " + str(id));
274 gl::DeleteVertexArrays (1, &id); id = 0;
275 }
276 }
277 void bind () const {
278 assert (id);
280 GL_DEBUG ("binding OpenGL vertex array ID " + str(id));
281 gl::BindVertexArray (id);
282 }
283 protected:
285 GLuint id;
286 };
287
288
290 public:
291 IndexBuffer () : id (0) { }
293 IndexBuffer (const IndexBuffer&) : id (0) { }
294 IndexBuffer (IndexBuffer&& t) : id (t.id) { t.id = 0; }
295 IndexBuffer& operator= (IndexBuffer&& t) { clear(); id = t.id; t.id = 0; return *this; }
296 operator GLuint () const { return id; }
297 void gen () {
298 if (!id) {
300 gl::GenBuffers (1, &id);
301 GL_DEBUG ("created OpenGL index buffer ID " + str(id));
302 }
303 }
304 void clear () {
305 if (id) {
307 GL_DEBUG ("deleting OpenGL index buffer ID " + str(id));
308 gl::DeleteBuffers (1, &id);
309 id = 0;
310 }
311 }
312 void bind () const {
313 assert (id);
315 GL_DEBUG ("binding OpenGL index buffer ID " + str(id));
316 gl::BindBuffer (gl::ELEMENT_ARRAY_BUFFER, id);
317 }
318 protected:
320 GLuint id;
321 };
322
323
324
326 public:
327 FrameBuffer () : id (0) { }
329 FrameBuffer (const FrameBuffer&) : id (0) { }
330 FrameBuffer (FrameBuffer&& t) : id (t.id) { t.id = 0; }
331 FrameBuffer& operator= (FrameBuffer&& t) { clear(); id = t.id; t.id = 0; return *this; }
332 operator GLuint () const { return id; }
333 void gen () {
334 if (!id) {
336 gl::GenFramebuffers (1, &id);
337 GL_DEBUG ("created OpenGL framebuffer ID " + str(id));
338 }
339 }
340 void clear () {
341 if (id) {
343 GL_DEBUG ("deleting OpenGL framebuffer ID " + str(id));
344 gl::DeleteFramebuffers (1, &id);
345 unbind();
346 }
347 id = 0;
348 }
349 void bind () const {
350 assert (id);
352 GL_DEBUG ("binding OpenGL framebuffer ID " + str(id));
353 gl::BindFramebuffer (gl::FRAMEBUFFER, id);
354 }
355 void unbind () const {
357 GL_DEBUG ("binding default OpenGL framebuffer");
358#if QT_VERSION >= 0x050400
359 gl::BindFramebuffer (gl::FRAMEBUFFER, QOpenGLContext::currentContext()->defaultFramebufferObject());
360#else
361 gl::BindFramebuffer (gl::FRAMEBUFFER, 0);
362#endif
363 }
364
365
366 void attach_color (Texture& tex, size_t attachment) const {
367 assert (tex);
368 bind();
369 GL_DEBUG ("texture ID " + str (tex) + " attached to framebuffer ID " + str(id) + " at color attachement " + str(attachment));
370 gl::FramebufferTexture (gl::FRAMEBUFFER, GLenum (size_t (gl::COLOR_ATTACHMENT0) + attachment), tex, 0);
371 }
372 void draw_buffers (size_t first) const {
374 GLenum list[1] = { GLenum (size_t (gl::COLOR_ATTACHMENT0) + first) };
375 gl::DrawBuffers (1 , list);
376 }
377 void draw_buffers (size_t first, size_t second) const {
379 GLenum list[2] = { GLenum (size_t(gl::COLOR_ATTACHMENT0) + first), GLenum (size_t (gl::COLOR_ATTACHMENT0) + second) };
380 gl::DrawBuffers (2 , list);
381 }
382
383 void check() const {
385 if (gl::CheckFramebufferStatus (gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE)
386 throw Exception ("FIXME: framebuffer is not complete");
387 }
388 protected:
390 GLuint id;
391 };
392
393
394
395 }
396 }
397}
398
399
400
401#endif
402
QImage grabFramebuffer()
Definition: gl.h:77
void unbind() const
Definition: gl.h:355
FrameBuffer & operator=(FrameBuffer &&t)
Definition: gl.h:331
void attach_color(Texture &tex, size_t attachment) const
Definition: gl.h:366
FrameBuffer(const FrameBuffer &)
Definition: gl.h:329
Context::Checker check_context
Definition: gl.h:389
void draw_buffers(size_t first, size_t second) const
Definition: gl.h:377
void bind() const
Definition: gl.h:349
void draw_buffers(size_t first) const
Definition: gl.h:372
void check() const
Definition: gl.h:383
FrameBuffer(FrameBuffer &&t)
Definition: gl.h:330
IndexBuffer(const IndexBuffer &)
Definition: gl.h:293
void bind() const
Definition: gl.h:312
Context::Checker check_context
Definition: gl.h:319
IndexBuffer & operator=(IndexBuffer &&t)
Definition: gl.h:295
IndexBuffer(IndexBuffer &&t)
Definition: gl.h:294
GLenum type() const
Definition: gl.h:191
void set_interp(GLint type) const
Definition: gl.h:207
void set_interp_on(bool interpolate) const
Definition: gl.h:212
Texture(const Texture &)
Definition: gl.h:169
void gen(GLenum target, GLint interp_type=gl::LINEAR)
Definition: gl.h:174
void bind() const
Definition: gl.h:201
void clear()
Definition: gl.h:192
GLenum tex_type
Definition: gl.h:216
void cache_copy(const Texture &t)
Definition: gl.h:172
Context::Checker check_context
Definition: gl.h:214
Texture(Texture &&t)
Definition: gl.h:170
Texture & operator=(Texture &&t)
Definition: gl.h:171
VertexArrayObject(VertexArrayObject &&t)
Definition: gl.h:260
Context::Checker check_context
Definition: gl.h:284
VertexArrayObject(const VertexArrayObject &)
Definition: gl.h:259
VertexArrayObject & operator=(VertexArrayObject &&t)
Definition: gl.h:261
Context::Checker check_context
Definition: gl.h:250
void bind(GLenum target) const
Definition: gl.h:243
VertexBuffer & operator=(VertexBuffer &&t)
Definition: gl.h:226
VertexBuffer(const VertexBuffer &)
Definition: gl.h:224
VertexBuffer(VertexBuffer &&t)
Definition: gl.h:225
#define FAIL(msg)
Definition: exception.h:72
#define GL_DEBUG(msg)
Definition: gl.h:46
#define NOMEMALIGN
Definition: memory.h:22
std::pair< int, int > get(QWidget *)
Definition: gl.h:136
std::pair< int, int > current()
Definition: gl.h:135
std::pair< int, int > makeCurrent(QWidget *)
Definition: gl.h:137
void restore(std::pair< int, int >)
Definition: gl.h:138
const char * ErrorString(GLenum errorcode)
Area * glwidget
void __assert_context_is_current(QWidget *glarea)
void assert_context_is_current(QWidget *glarea=nullptr)
Definition: gl.h:100
void set_default_context()
QGLFormat Format
Definition: gl.h:80
void check_error(const char *filename, int line)
Definition: gl.h:88
Definition: base.h:24
std::string str(const T &value, int precision=0)
Definition: mrtrix.h:247
void operator()() const
Definition: gl.h:153
NOMEMALIGN decltype(current()) original_context
Definition: gl.h:151
Grab(QWidget *window=nullptr)
Definition: gl.h:143
NOMEMALIGN decltype(current()) previous_context
Definition: gl.h:142