7#include <gdkmm/glcontext.h>
8#include <gdkmm/gltexture.h>
9#include <gdkmm/gltexturebuilder.h>
10#include <gtkmm/snapshot.h>
26std::weak_ptr<T> weakify(std::shared_ptr<T>
const &p)
33auto share_lambda(F &&f)
35 using Fd = std::decay_t<F>;
39 auto operator()() { (*f)(); }
40 std::shared_ptr<Fd> f;
43 return Result{std::make_shared<Fd>(std::move(f))};
48struct OptGLArea::GLState
50 std::shared_ptr<Gdk::GLContext>
const context;
52 GLuint
const framebuffer = create_buffer<glGenFramebuffers>();
53 GLuint
const stencilbuffer = create_buffer<glGenRenderbuffers>();
55 Glib::RefPtr<Gdk::GLTextureBuilder>
const builder = Gdk::GLTextureBuilder::create();
57 std::optional<Geom::IntPoint>
size;
59 Texture current_texture;
60 std::vector<Texture> spare_textures;
62 GLState(Glib::RefPtr<Gdk::GLContext> &&context_)
63 : context{
std::move(context_)}
66 builder->set_format(Gdk::MemoryFormat::B8G8R8A8_PREMULTIPLIED);
71 glDeleteRenderbuffers(1, &stencilbuffer);
72 glDeleteFramebuffers (1, &framebuffer);
81 Gtk::Widget::on_realize();
88 Gtk::Widget::on_unrealize();
106 context->make_current();
107 gl = std::make_shared<GLState>(std::move(context));
108 Gdk::GLContext::clear_current();
113 gl->context->make_current();
115 Gdk::GLContext::clear_current();
121 gl->context->make_current();
127 assert(
gl->current_texture);
129 glBindFramebuffer(GL_FRAMEBUFFER,
gl->framebuffer);
130 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
gl->current_texture.id(), 0);
131 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
gl->stencilbuffer);
139 if (
size.x() == 0 ||
size.y() == 0) {
143 gl->context->make_current();
150 glBindRenderbuffer(GL_RENDERBUFFER,
gl->stencilbuffer);
151 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
size.x(),
size.y());
154 gl->builder->set_width(
size.x());
155 gl->builder->set_height(
size.y());
159 std::erase_if(
gl->spare_textures, [&] (
auto &tex) { return tex.size() != size; });
163 assert(!
gl->current_texture);
164 if (!
gl->spare_textures.empty()) {
166 gl->current_texture = std::move(
gl->spare_textures.back());
167 gl->spare_textures.pop_back();
177 gl->builder->set_id(
gl->current_texture.id());
178 auto gdktexture = std::static_pointer_cast<Gdk::GLTexture>(
gl->builder->build(
179 share_lambda([texture = std::move(
gl->current_texture),
180 context =
gl->context,
181 gl_weak = weakify(
gl)] ()
mutable
183 if (
auto gl = gl_weak.lock()) {
185 gl->spare_textures.emplace_back(std::move(texture));
188 context->make_current();
190 Gdk::GLContext::clear_current();
198 snapshot->translate({ 0.0f, (float)get_height() });
199 snapshot->scale(1, -1);
200 snapshot->append_texture(std::move(gdktexture), Gdk::Graphene::Rect(0, 0, get_width(), get_height()).gobj());
203 auto const cr = snapshot->append_cairo(Gdk::Graphene::Rect(0, 0, get_width(), get_height()).gobj());
Two-dimensional point with integer coordinates.
Cartesian point / 2D vector with integer coordinates.
Glib::RefPtr< Gtk::Builder > builder