Struct thyme::GLRenderer
source · pub struct GLRenderer { /* private fields */ }
Expand description
A Thyme Renderer
for raw OpenGL
.
This adapter registers image and font data as OpenGL textures using gl-rs, and renders each frame.
After the UI has been built, the Frame
should be passed to the renderer
for drawing.
Fonts are prerendered to a texture on the GPU, based on the ttf font data and the theme specified size.
Data is structured to minimize number of draw calls, with one to three draw calls per render group
(created with WidgetBuilder.new_render_group
)
being typical. Unless you need UI groups where different widgets may overlap and change draw
ordering frame-by-frame, a single render group will usually be enough for most of your UI.
Widget clipping is handled using gl::CLIP_DISTANCE0
to gl::CLIP_DISTANCE3
, again to minimize draw calls. Since the data to send
to the GPU is constructed each frame in the immediate mode UI model, the amount of data is minimized
by sending only a single Vertex
for each Image, with the vertex components including the rectangular position and
texture coordinates. The actual individual on-screen vertices are then constructed with a Geometry shader.
Implementations§
source§impl GLRenderer
impl GLRenderer
sourcepub fn new() -> GLRenderer
pub fn new() -> GLRenderer
Creates a GLRenderer
Examples found in repository?
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
fn main() -> Result<(), Box<dyn std::error::Error>> {
// initialize our very basic logger so error messages go to stdout
thyme::log::init(log::Level::Warn).unwrap();
// create glium display
let event_loop = glutin::event_loop::EventLoop::new();
let window_builder = glutin::window::WindowBuilder::new()
.with_title("Hello world!")
.with_inner_size(glutin::dpi::LogicalSize::new(1280.0, 720.0));
let windowed_context = glutin::ContextBuilder::new()
.with_gl(glutin::GlRequest::Specific(
glutin::Api::OpenGl,
(OPENGL_MAJOR_VERSION, OPENGL_MINOR_VERSION),
))
.build_windowed(window_builder, &event_loop)?;
let windowed_context = unsafe {
windowed_context
.make_current().map_err(|(_context, e)| e)?
};
{
let gl_context = windowed_context.context();
gl::load_with(|ptr| gl_context.get_proc_address(ptr) as *const _)
}
// create thyme backend
let mut renderer = thyme::GLRenderer::new();
let mut context_builder = thyme::ContextBuilder::with_defaults();
demo::register_assets(&mut context_builder);
let window_size = [1280.0, 720.0];
let mut io = thyme::WinitIo::new(&event_loop, window_size.into())?;
let mut context = context_builder.build(&mut renderer, &mut io)?;
let mut party = demo::Party::default();
let mut last_frame = std::time::Instant::now();
let frame_time = std::time::Duration::from_millis(16);
// run main loop
event_loop.run(move |event, _, control_flow| match event {
Event::MainEventsCleared => {
if std::time::Instant::now() > last_frame + frame_time {
windowed_context.window().request_redraw();
}
*control_flow = ControlFlow::WaitUntil(last_frame + frame_time);
}
Event::RedrawRequested(_) => {
last_frame = std::time::Instant::now();
party.check_context_changes(&mut context, &mut renderer);
renderer.clear_color(0.5, 0.5, 0.5, 1.0);
bench::run("thyme", || {
windowed_context.window().set_cursor_visible(!party.theme_has_mouse_cursor());
let mut ui = context.create_frame();
bench::run("frame", || {
demo::build_ui(&mut ui, &mut party);
});
bench::run("draw", || {
renderer.draw_frame(ui);
});
});
windowed_context.swap_buffers().unwrap();
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
event => {
io.handle_event(&mut context, &event);
}
})
}
sourcepub fn clear_color(&self, r: f32, g: f32, b: f32, a: f32)
pub fn clear_color(&self, r: f32, g: f32, b: f32, a: f32)
Clears the screen with this color.
Examples found in repository?
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
fn main() -> Result<(), Box<dyn std::error::Error>> {
// initialize our very basic logger so error messages go to stdout
thyme::log::init(log::Level::Warn).unwrap();
// create glium display
let event_loop = glutin::event_loop::EventLoop::new();
let window_builder = glutin::window::WindowBuilder::new()
.with_title("Hello world!")
.with_inner_size(glutin::dpi::LogicalSize::new(1280.0, 720.0));
let windowed_context = glutin::ContextBuilder::new()
.with_gl(glutin::GlRequest::Specific(
glutin::Api::OpenGl,
(OPENGL_MAJOR_VERSION, OPENGL_MINOR_VERSION),
))
.build_windowed(window_builder, &event_loop)?;
let windowed_context = unsafe {
windowed_context
.make_current().map_err(|(_context, e)| e)?
};
{
let gl_context = windowed_context.context();
gl::load_with(|ptr| gl_context.get_proc_address(ptr) as *const _)
}
// create thyme backend
let mut renderer = thyme::GLRenderer::new();
let mut context_builder = thyme::ContextBuilder::with_defaults();
demo::register_assets(&mut context_builder);
let window_size = [1280.0, 720.0];
let mut io = thyme::WinitIo::new(&event_loop, window_size.into())?;
let mut context = context_builder.build(&mut renderer, &mut io)?;
let mut party = demo::Party::default();
let mut last_frame = std::time::Instant::now();
let frame_time = std::time::Duration::from_millis(16);
// run main loop
event_loop.run(move |event, _, control_flow| match event {
Event::MainEventsCleared => {
if std::time::Instant::now() > last_frame + frame_time {
windowed_context.window().request_redraw();
}
*control_flow = ControlFlow::WaitUntil(last_frame + frame_time);
}
Event::RedrawRequested(_) => {
last_frame = std::time::Instant::now();
party.check_context_changes(&mut context, &mut renderer);
renderer.clear_color(0.5, 0.5, 0.5, 1.0);
bench::run("thyme", || {
windowed_context.window().set_cursor_visible(!party.theme_has_mouse_cursor());
let mut ui = context.create_frame();
bench::run("frame", || {
demo::build_ui(&mut ui, &mut party);
});
bench::run("draw", || {
renderer.draw_frame(ui);
});
});
windowed_context.swap_buffers().unwrap();
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
event => {
io.handle_event(&mut context, &event);
}
})
}
sourcepub fn draw_frame(&mut self, frame: Frame)
pub fn draw_frame(&mut self, frame: Frame)
Draws the specified Frame
to the Glium surface, usually the Glium Frame.
Examples found in repository?
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
fn main() -> Result<(), Box<dyn std::error::Error>> {
// initialize our very basic logger so error messages go to stdout
thyme::log::init(log::Level::Warn).unwrap();
// create glium display
let event_loop = glutin::event_loop::EventLoop::new();
let window_builder = glutin::window::WindowBuilder::new()
.with_title("Hello world!")
.with_inner_size(glutin::dpi::LogicalSize::new(1280.0, 720.0));
let windowed_context = glutin::ContextBuilder::new()
.with_gl(glutin::GlRequest::Specific(
glutin::Api::OpenGl,
(OPENGL_MAJOR_VERSION, OPENGL_MINOR_VERSION),
))
.build_windowed(window_builder, &event_loop)?;
let windowed_context = unsafe {
windowed_context
.make_current().map_err(|(_context, e)| e)?
};
{
let gl_context = windowed_context.context();
gl::load_with(|ptr| gl_context.get_proc_address(ptr) as *const _)
}
// create thyme backend
let mut renderer = thyme::GLRenderer::new();
let mut context_builder = thyme::ContextBuilder::with_defaults();
demo::register_assets(&mut context_builder);
let window_size = [1280.0, 720.0];
let mut io = thyme::WinitIo::new(&event_loop, window_size.into())?;
let mut context = context_builder.build(&mut renderer, &mut io)?;
let mut party = demo::Party::default();
let mut last_frame = std::time::Instant::now();
let frame_time = std::time::Duration::from_millis(16);
// run main loop
event_loop.run(move |event, _, control_flow| match event {
Event::MainEventsCleared => {
if std::time::Instant::now() > last_frame + frame_time {
windowed_context.window().request_redraw();
}
*control_flow = ControlFlow::WaitUntil(last_frame + frame_time);
}
Event::RedrawRequested(_) => {
last_frame = std::time::Instant::now();
party.check_context_changes(&mut context, &mut renderer);
renderer.clear_color(0.5, 0.5, 0.5, 1.0);
bench::run("thyme", || {
windowed_context.window().set_cursor_visible(!party.theme_has_mouse_cursor());
let mut ui = context.create_frame();
bench::run("frame", || {
demo::build_ui(&mut ui, &mut party);
});
bench::run("draw", || {
renderer.draw_frame(ui);
});
});
windowed_context.swap_buffers().unwrap();
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
event => {
io.handle_event(&mut context, &event);
}
})
}
Trait Implementations§
source§impl Default for GLRenderer
impl Default for GLRenderer
source§impl Renderer for GLRenderer
impl Renderer for GLRenderer
source§fn register_texture(
&mut self,
handle: TextureHandle,
image_data: &[u8],
dimensions: (u32, u32)
) -> Result<TextureData, Error>
fn register_texture( &mut self, handle: TextureHandle, image_data: &[u8], dimensions: (u32, u32) ) -> Result<TextureData, Error>
ContextBuilder
.source§fn register_font(
&mut self,
handle: FontHandle,
source: &FontSource,
ranges: &[CharacterRange],
size: f32,
scale: f32
) -> Result<Font, Error>
fn register_font( &mut self, handle: FontHandle, source: &FontSource, ranges: &[CharacterRange], size: f32, scale: f32 ) -> Result<Font, Error>
ContextBuilder
.