#gtk #gfx #opengl #epoxy #glarea

gfx-gtk

Integration helper for embedding GFX rendering in a gtk::GlArea

4 releases (breaking)

Uses old Rust 2015

0.4.0 Feb 22, 2019
0.3.0 Oct 13, 2018
0.2.0 Oct 13, 2018
0.1.0 Sep 29, 2018

#524 in Graphics APIs

Apache-2.0

44KB
693 lines

gfx-gtk

Simple bridge library to render into a gtk-rs GLArea using the Gfx (pre-ll) library.

Uses [epoxy] for Gl loading, and as such it doesn't require a Gl window/loading management such as glutin or winit

Here's a short broken-down list to get the integration up and running:

Add the Cargo dependencies

[dependencies]
gfx_gtk = "0.3"

Import crate and packages

extern crate gfx_gtk;

use gfx_gtk::formats;
use gfx_gtk::GlRenderContext;

Choose some render formats and AA mode

const MSAA: gfx::texture::AaMode = formats::MSAA_4X;
type RenderColorFormat = formats::DefaultRenderColorFormat;
type RenderDepthFormat = formats::DefaultRenderDepthFormat;

Write a render callback

You need to implement [GlRenderCallback] and [GlPostprocessCallback] traits (the latter can be made to use the default implementation)

struct SimpleRenderCallback {
	...
}

impl gfx_gtk::GlRenderCallback<RenderColorFormat, RenderDepthFormat> for SimpleRenderCallback {
	fn render(
		&mut self,
		gfx_context: &mut gfx_gtk::GlGfxContext,
		viewport: &gfx_gtk::Viewport,
		frame_buffer: &gfx_gtk::GlFrameBuffer<RenderColorFormat>,
		depth_buffer: &gfx_gtk::GlDepthBuffer<RenderDepthFormat>,
	) -> gfx_gtk::Result<gfx_gtk::GlRenderCallbackStatus> {
		gfx_context.encoder.draw(...);
		Ok(gfx_gtk::GlRenderCallbackStatus::Continue)
	}
}

impl gfx_gtk::GlPostprocessCallback<RenderColorFormat, RenderDepthFormat> for SimpleRenderCallback {}

Load Gl functions

gfx_gtk::load();

Connect the widget's signals

The rendering needs to be driven by a GlArea widget because of its ability to create a Gl context.

The realize, resize and render signals need to be connected. The [GlRenderContext] and [GlRenderCallback] must be created in the closure that gets attached to GlArea::connect_realize() after the make_current() call (otherwise it won't be possible to "bind" to the current GlArea Gl context

let gfx_context: Rc<RefCell<Option<GlRenderContext<RenderColorFormat, RenderDepthFormat>>>> = Rc::new(RefCell::new(None));

let render_callback: Rc<RefCell<Option<SimpleRenderCallback>>> = Rc::new(RefCell::new(None));

let glarea = gtk::GLArea::new();

glarea.connect_realize({
	let gfx_context = gfx_context.clone();
	let render_callback = render_callback.clone();

	move |widget| {
		if widget.get_realized() {
			widget.make_current();
		}

		let allocation = widget.get_allocation();

		let mut new_context =
			gfx_gtk::GlRenderContext::new(
			MSAA,
			allocation.width,
			allocation.height,
			None).ok();
		if let Some(ref mut new_context) = new_context {
			let ref vp = new_context.viewport();
			let ref mut ctx = new_context.gfx_context_mut();
			*render_callback.borrow_mut() = SimpleRenderCallback::new(ctx, vp).ok();
		}
		*gfx_context.borrow_mut() = new_context;
	}
});

glarea.connect_resize({
	let gfx_context = gfx_context.clone();
	let render_callback = render_callback.clone();

	move |_widget, width, height| {
		if let Some(ref mut context) = *gfx_context.borrow_mut() {
			if let Some(ref mut render_callback) = *render_callback.borrow_mut() {
				context.resize(width, height, Some(render_callback)).ok();
			}
		}
	}
});

glarea.connect_render({
	let gfx_context = gfx_context.clone();
	let render_callback = render_callback.clone();

	move |_widget, _gl_context| {
		if let Some(ref mut context) = *gfx_context.borrow_mut() {
			if let Some(ref mut render_callback) = *render_callback.borrow_mut() {
				context.with_gfx(render_callback);
			}
		}

		Inhibit(false)
	}
});

After this, every time Gtk refreshes the GlArea content, it will invoke the render_callback to paint itself.

See examples/setup.rs for a simple interactive rendering example. On running it with cargo run --example setup, it should look like this:

Screenshot 1

© 2018 Nico Orru https://www.itadinanta.net

Dependencies

~13MB
~326K SLoC