2022-04-29 06:17:49 +00:00
//! Example how to use pure `egui_glow`.
2021-10-18 21:13:32 +00:00
2021-12-30 21:43:53 +00:00
#![ cfg_attr(not(debug_assertions), windows_subsystem = " windows " ) ] // hide console window on Windows in release
2022-03-21 20:48:35 +00:00
#![ allow(unsafe_code) ]
2021-12-30 21:43:53 +00:00
2022-12-06 09:02:20 +00:00
use egui_winit ::winit ;
/// The majority of `GlutinWindowContext` is taken from `eframe`
struct GlutinWindowContext {
window : winit ::window ::Window ,
gl_context : glutin ::context ::PossiblyCurrentContext ,
gl_display : glutin ::display ::Display ,
gl_surface : glutin ::surface ::Surface < glutin ::surface ::WindowSurface > ,
}
impl GlutinWindowContext {
// refactor this function to use `glutin-winit` crate eventually.
// preferably add android support at the same time.
#[ allow(unsafe_code) ]
2023-02-08 13:28:42 +00:00
unsafe fn new ( event_loop : & winit ::event_loop ::EventLoopWindowTarget < ( ) > ) -> Self {
use egui ::NumExt ;
use glutin ::context ::NotCurrentGlContextSurfaceAccessor ;
use glutin ::display ::GetGlDisplay ;
use glutin ::display ::GlDisplay ;
use glutin ::prelude ::GlSurface ;
use raw_window_handle ::HasRawWindowHandle ;
let winit_window_builder = winit ::window ::WindowBuilder ::new ( )
. with_resizable ( true )
. with_inner_size ( winit ::dpi ::LogicalSize {
width : 800.0 ,
height : 600.0 ,
} )
. with_title ( " egui_glow example " ) // Keep hidden until we've painted something. See https://github.com/emilk/egui/pull/2279
. with_visible ( false ) ;
let config_template_builder = glutin ::config ::ConfigTemplateBuilder ::new ( )
2022-12-06 09:02:20 +00:00
. prefer_hardware_accelerated ( None )
. with_depth_size ( 0 )
. with_stencil_size ( 0 )
2023-02-08 13:28:42 +00:00
. with_transparency ( false ) ;
2022-12-06 09:02:20 +00:00
2023-02-08 13:28:42 +00:00
tracing ::debug! ( " trying to get gl_config " ) ;
let ( mut window , gl_config ) =
glutin_winit ::DisplayBuilder ::new ( ) // let glutin-winit helper crate handle the complex parts of opengl context creation
. with_preference ( glutin_winit ::ApiPrefence ::FallbackEgl ) // https://github.com/emilk/egui/issues/2520#issuecomment-1367841150
. with_window_builder ( Some ( winit_window_builder . clone ( ) ) )
. build (
event_loop ,
config_template_builder ,
| mut config_iterator | {
config_iterator . next ( ) . expect (
" failed to find a matching configuration for creating glutin config " ,
)
} ,
)
. expect ( " failed to create gl_config " ) ;
let gl_display = gl_config . display ( ) ;
tracing ::debug! ( " found gl_config: {:?} " , & gl_config ) ;
let raw_window_handle = window . as_ref ( ) . map ( | w | w . raw_window_handle ( ) ) ;
tracing ::debug! ( " raw window handle: {:?} " , raw_window_handle ) ;
2022-12-06 09:02:20 +00:00
let context_attributes =
2023-02-08 13:28:42 +00:00
glutin ::context ::ContextAttributesBuilder ::new ( ) . build ( raw_window_handle ) ;
// by default, glutin will try to create a core opengl context. but, if it is not available, try to create a gl-es context using this fallback attributes
let fallback_context_attributes = glutin ::context ::ContextAttributesBuilder ::new ( )
. with_context_api ( glutin ::context ::ContextApi ::Gles ( None ) )
. build ( raw_window_handle ) ;
let not_current_gl_context = unsafe {
gl_display
. create_context ( & gl_config , & context_attributes )
. unwrap_or_else ( | _ | {
tracing ::debug! ( " failed to create gl_context with attributes: {:?}. retrying with fallback context attributes: {:?} " ,
& context_attributes ,
& fallback_context_attributes ) ;
gl_config
. display ( )
. create_context ( & gl_config , & fallback_context_attributes )
. expect ( " failed to create context even with fallback attributes " )
} )
} ;
// this is where the window is created, if it has not been created while searching for suitable gl_config
let window = window . take ( ) . unwrap_or_else ( | | {
tracing ::debug! ( " window doesn't exist yet. creating one now with finalize_window " ) ;
glutin_winit ::finalize_window ( event_loop , winit_window_builder . clone ( ) , & gl_config )
. expect ( " failed to finalize glutin window " )
} ) ;
let ( width , height ) : ( u32 , u32 ) = window . inner_size ( ) . into ( ) ;
let width = std ::num ::NonZeroU32 ::new ( width . at_least ( 1 ) ) . unwrap ( ) ;
let height = std ::num ::NonZeroU32 ::new ( height . at_least ( 1 ) ) . unwrap ( ) ;
2022-12-06 09:02:20 +00:00
let surface_attributes =
glutin ::surface ::SurfaceAttributesBuilder ::< glutin ::surface ::WindowSurface > ::new ( )
2023-02-08 13:28:42 +00:00
. build ( window . raw_window_handle ( ) , width , height ) ;
tracing ::debug! (
" creating surface with attributes: {:?} " ,
& surface_attributes
) ;
let gl_surface = unsafe {
gl_display
. create_window_surface ( & gl_config , & surface_attributes )
. unwrap ( )
} ;
tracing ::debug! ( " surface created successfully: {gl_surface:?}.making context current " ) ;
let gl_context = not_current_gl_context . make_current ( & gl_surface ) . unwrap ( ) ;
2022-12-06 09:02:20 +00:00
gl_surface
. set_swap_interval (
& gl_context ,
glutin ::surface ::SwapInterval ::Wait ( std ::num ::NonZeroU32 ::new ( 1 ) . unwrap ( ) ) ,
)
. unwrap ( ) ;
GlutinWindowContext {
2023-02-08 13:28:42 +00:00
window ,
2022-12-06 09:02:20 +00:00
gl_context ,
gl_display ,
gl_surface ,
}
}
fn window ( & self ) -> & winit ::window ::Window {
& self . window
}
fn resize ( & self , physical_size : winit ::dpi ::PhysicalSize < u32 > ) {
use glutin ::surface ::GlSurface ;
self . gl_surface . resize (
& self . gl_context ,
physical_size . width . try_into ( ) . unwrap ( ) ,
physical_size . height . try_into ( ) . unwrap ( ) ,
) ;
}
fn swap_buffers ( & self ) -> glutin ::error ::Result < ( ) > {
use glutin ::surface ::GlSurface ;
self . gl_surface . swap_buffers ( & self . gl_context )
}
fn get_proc_address ( & self , addr : & std ::ffi ::CStr ) -> * const std ::ffi ::c_void {
use glutin ::display ::GlDisplay ;
self . gl_display . get_proc_address ( addr )
}
}
2021-10-18 21:13:32 +00:00
fn main ( ) {
2021-11-27 10:44:23 +00:00
let mut clear_color = [ 0.1 , 0.1 , 0.1 ] ;
2022-12-06 09:02:20 +00:00
let event_loop = winit ::event_loop ::EventLoopBuilder ::with_user_event ( ) . build ( ) ;
2021-10-18 21:13:32 +00:00
let ( gl_window , gl ) = create_display ( & event_loop ) ;
2022-05-22 15:43:30 +00:00
let gl = std ::sync ::Arc ::new ( gl ) ;
2021-10-18 21:13:32 +00:00
2022-09-06 08:08:16 +00:00
let mut egui_glow = egui_glow ::EguiGlow ::new ( & event_loop , gl . clone ( ) , None ) ;
2021-10-18 21:13:32 +00:00
event_loop . run ( move | event , _ , control_flow | {
let mut redraw = | | {
let mut quit = false ;
2022-06-22 11:19:13 +00:00
let repaint_after = egui_glow . run ( gl_window . window ( ) , | egui_ctx | {
2021-11-03 12:45:51 +00:00
egui ::SidePanel ::left ( " my_side_panel " ) . show ( egui_ctx , | ui | {
ui . heading ( " Hello World! " ) ;
if ui . button ( " Quit " ) . clicked ( ) {
quit = true ;
}
2021-11-27 10:44:23 +00:00
ui . color_edit_button_rgb ( & mut clear_color ) ;
2021-11-03 12:45:51 +00:00
} ) ;
2021-10-18 21:13:32 +00:00
} ) ;
* control_flow = if quit {
2022-12-06 09:02:20 +00:00
winit ::event_loop ::ControlFlow ::Exit
2022-06-22 11:19:13 +00:00
} else if repaint_after . is_zero ( ) {
2021-10-18 21:13:32 +00:00
gl_window . window ( ) . request_redraw ( ) ;
2022-12-06 09:02:20 +00:00
winit ::event_loop ::ControlFlow ::Poll
2022-06-22 11:19:13 +00:00
} else if let Some ( repaint_after_instant ) =
std ::time ::Instant ::now ( ) . checked_add ( repaint_after )
{
2022-12-06 09:02:20 +00:00
winit ::event_loop ::ControlFlow ::WaitUntil ( repaint_after_instant )
2021-10-18 21:13:32 +00:00
} else {
2022-12-06 09:02:20 +00:00
winit ::event_loop ::ControlFlow ::Wait
2021-10-18 21:13:32 +00:00
} ;
{
unsafe {
2021-10-19 19:40:55 +00:00
use glow ::HasContext as _ ;
2021-11-27 10:44:23 +00:00
gl . clear_color ( clear_color [ 0 ] , clear_color [ 1 ] , clear_color [ 2 ] , 1.0 ) ;
2021-10-18 21:13:32 +00:00
gl . clear ( glow ::COLOR_BUFFER_BIT ) ;
}
// draw things behind egui here
2022-03-14 12:25:11 +00:00
egui_glow . paint ( gl_window . window ( ) ) ;
2021-10-18 21:13:32 +00:00
// draw things on top of egui here
gl_window . swap_buffers ( ) . unwrap ( ) ;
2022-11-29 14:04:17 +00:00
gl_window . window ( ) . set_visible ( true ) ;
2021-10-18 21:13:32 +00:00
}
} ;
match event {
// Platform-dependent event handlers to workaround a winit bug
// See: https://github.com/rust-windowing/winit/issues/987
// See: https://github.com/rust-windowing/winit/issues/1619
2022-12-06 09:02:20 +00:00
winit ::event ::Event ::RedrawEventsCleared if cfg! ( windows ) = > redraw ( ) ,
winit ::event ::Event ::RedrawRequested ( _ ) if ! cfg! ( windows ) = > redraw ( ) ,
2021-10-18 21:13:32 +00:00
2022-12-06 09:02:20 +00:00
winit ::event ::Event ::WindowEvent { event , .. } = > {
use winit ::event ::WindowEvent ;
2021-11-07 19:58:02 +00:00
if matches! ( event , WindowEvent ::CloseRequested | WindowEvent ::Destroyed ) {
2022-12-06 09:02:20 +00:00
* control_flow = winit ::event_loop ::ControlFlow ::Exit ;
2021-10-18 21:13:32 +00:00
}
2022-12-06 09:02:20 +00:00
if let winit ::event ::WindowEvent ::Resized ( physical_size ) = & event {
2022-04-03 08:20:49 +00:00
gl_window . resize ( * physical_size ) ;
2022-12-06 09:02:20 +00:00
} else if let winit ::event ::WindowEvent ::ScaleFactorChanged {
new_inner_size , ..
2022-04-03 08:20:49 +00:00
} = & event
{
gl_window . resize ( * * new_inner_size ) ;
2021-10-18 21:13:32 +00:00
}
2022-08-29 09:20:19 +00:00
let event_response = egui_glow . on_event ( & event ) ;
2021-10-18 21:13:32 +00:00
2022-08-29 09:20:19 +00:00
if event_response . repaint {
gl_window . window ( ) . request_redraw ( ) ;
}
2021-10-18 21:13:32 +00:00
}
2022-12-06 09:02:20 +00:00
winit ::event ::Event ::LoopDestroyed = > {
2022-03-14 12:25:11 +00:00
egui_glow . destroy ( ) ;
2021-10-18 21:13:32 +00:00
}
2022-12-06 09:02:20 +00:00
winit ::event ::Event ::NewEvents ( winit ::event ::StartCause ::ResumeTimeReached {
2022-06-22 11:19:13 +00:00
..
} ) = > {
gl_window . window ( ) . request_redraw ( ) ;
}
2021-10-18 21:13:32 +00:00
_ = > ( ) ,
}
} ) ;
}
2022-03-16 14:39:48 +00:00
fn create_display (
2022-12-06 09:02:20 +00:00
event_loop : & winit ::event_loop ::EventLoopWindowTarget < ( ) > ,
) -> ( GlutinWindowContext , glow ::Context ) {
2023-02-08 13:28:42 +00:00
let glutin_window_context = unsafe { GlutinWindowContext ::new ( event_loop ) } ;
2022-12-06 09:02:20 +00:00
let gl = unsafe {
glow ::Context ::from_loader_function ( | s | {
let s = std ::ffi ::CString ::new ( s )
. expect ( " failed to construct C string from string for gl proc address " ) ;
glutin_window_context . get_proc_address ( & s )
} )
2022-03-16 14:39:48 +00:00
} ;
2022-12-06 09:02:20 +00:00
( glutin_window_context , gl )
2022-03-16 14:39:48 +00:00
}