summaryrefslogtreecommitdiffstats
path: root/src/ui/widget/optglarea.cpp
blob: 72ec3628aae8b35d2caadd666d0633b1347c8402 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cassert>
#include "optglarea.h"

namespace Inkscape {
namespace UI {
namespace Widget {

OptGLArea::OptGLArea()
{
    set_app_paintable(true); // No problem for GTK4 port since this whole widget will be deleted.
    opengl_enabled = false;
}

void OptGLArea::on_realize()
{
    Gtk::DrawingArea::on_realize();
    if (opengl_enabled) init_opengl();
}

void OptGLArea::on_unrealize()
{
    if (context) {
        if (framebuffer) {
            context->make_current();
            delete_framebuffer();
        }
        if (context == Gdk::GLContext::get_current()) {
            Gdk::GLContext::clear_current(); // ?
        }
        context.reset();
    }
    Gtk::DrawingArea::on_unrealize();
}

void OptGLArea::on_size_allocate(Gtk::Allocation &allocation)
{
    Gtk::DrawingArea::on_size_allocate(allocation);
    if (get_realized()) need_resize = true;
}

void OptGLArea::set_opengl_enabled(bool enabled)
{
    if (opengl_enabled == enabled) return;
    opengl_enabled = enabled;
    if (opengl_enabled && get_realized()) init_opengl();
}

void OptGLArea::init_opengl()
{
    context = create_context();
    if (!context) opengl_enabled = false;
    framebuffer = 0;
    need_resize = true;
}

void OptGLArea::make_current()
{
    assert(context);
    context->make_current();
}

bool OptGLArea::on_draw(const Cairo::RefPtr<Cairo::Context> &cr)
{
    if (opengl_enabled) {
        context->make_current();

        if (!framebuffer) {
            create_framebuffer();
        }

        if (need_resize) {
            resize_framebuffer();
            need_resize = false;
        }

        paint_widget(cr);

        int s = get_scale_factor();
        int w = get_allocated_width() * s;
        int h = get_allocated_height() * s;
        gdk_cairo_draw_from_gl(cr->cobj(), get_window()->gobj(), renderbuffer, GL_RENDERBUFFER, s, 0, 0, w, h);

        context->make_current(); // ?
    } else {
        paint_widget(cr);
    }

    return true;
}

void OptGLArea::bind_framebuffer() const
{
    assert(context);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilbuffer);
}

void OptGLArea::create_framebuffer()
{
    glGenFramebuffers (1, &framebuffer);
    glGenRenderbuffers(1, &renderbuffer);
    glGenRenderbuffers(1, &stencilbuffer);
}

void OptGLArea::delete_framebuffer()
{
    glDeleteRenderbuffers(1, &renderbuffer);
    glDeleteRenderbuffers(1, &stencilbuffer);
    glDeleteFramebuffers (1, &framebuffer);
}

void OptGLArea::resize_framebuffer() const
{
    int s = get_scale_factor();
    int w = get_allocated_width() * s;
    int h = get_allocated_height() * s;
    glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, w, h);
    glBindRenderbuffer(GL_RENDERBUFFER, stencilbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h);
}

} // namespace Widget
} // namespace UI
} // namespace Inkscape