2023-01-29 20:34:01 -05:00
use glyphon ::{
2024-05-08 09:39:19 -04:00
Attrs , Buffer , Cache , Color , Family , FontSystem , Metrics , Resolution , Shaping , SwashCache ,
2024-05-08 10:17:58 -04:00
TextArea , TextAtlas , TextBounds , TextRenderer , Viewport ,
2023-01-29 20:34:01 -05:00
} ;
2024-05-26 22:34:17 -04:00
use std ::sync ::Arc ;
2022-05-09 08:49:10 -04:00
use wgpu ::{
2024-05-26 22:34:17 -04:00
CommandEncoderDescriptor , CompositeAlphaMode , DeviceDescriptor , Instance , InstanceDescriptor ,
LoadOp , MultisampleState , Operations , PresentMode , RenderPassColorAttachment ,
RenderPassDescriptor , RequestAdapterOptions , SurfaceConfiguration , TextureFormat ,
TextureUsages , TextureViewDescriptor ,
2022-05-09 08:49:10 -04:00
} ;
2024-07-25 14:05:55 -04:00
use winit ::{ dpi ::LogicalSize , event ::WindowEvent , event_loop ::EventLoop , window ::Window } ;
2022-05-09 08:49:10 -04:00
fn main ( ) {
2024-07-25 14:05:55 -04:00
let event_loop = EventLoop ::new ( ) . unwrap ( ) ;
event_loop
. run_app ( & mut Application { window_state : None } )
. unwrap ( ) ;
2022-05-09 08:49:10 -04:00
}
2024-07-25 14:05:55 -04:00
struct WindowState {
device : wgpu ::Device ,
queue : wgpu ::Queue ,
surface : wgpu ::Surface < 'static > ,
surface_config : SurfaceConfiguration ,
font_system : FontSystem ,
swash_cache : SwashCache ,
viewport : glyphon ::Viewport ,
atlas : glyphon ::TextAtlas ,
text_renderer : glyphon ::TextRenderer ,
text_buffer : glyphon ::Buffer ,
// Make sure that the winit window is last in the struct so that
// it is dropped after the wgpu surface is dropped, otherwise the
// program may crash when closed. This is probably a bug in wgpu.
window : Arc < Window > ,
}
impl WindowState {
async fn new ( window : Arc < Window > ) -> Self {
let physical_size = window . inner_size ( ) ;
let scale_factor = window . scale_factor ( ) ;
// Set up surface
2025-01-18 20:59:56 -05:00
let instance = Instance ::new ( & InstanceDescriptor ::default ( ) ) ;
2024-07-25 14:05:55 -04:00
let adapter = instance
. request_adapter ( & RequestAdapterOptions ::default ( ) )
. await
. unwrap ( ) ;
let ( device , queue ) = adapter
. request_device ( & DeviceDescriptor ::default ( ) , None )
. await
. unwrap ( ) ;
let surface = instance
. create_surface ( window . clone ( ) )
. expect ( " Create surface " ) ;
let swapchain_format = TextureFormat ::Bgra8UnormSrgb ;
let surface_config = SurfaceConfiguration {
usage : TextureUsages ::RENDER_ATTACHMENT ,
format : swapchain_format ,
width : physical_size . width ,
height : physical_size . height ,
present_mode : PresentMode ::Fifo ,
alpha_mode : CompositeAlphaMode ::Opaque ,
view_formats : vec ! [ ] ,
desired_maximum_frame_latency : 2 ,
} ;
surface . configure ( & device , & surface_config ) ;
// Set up text renderer
let mut font_system = FontSystem ::new ( ) ;
let swash_cache = SwashCache ::new ( ) ;
let cache = Cache ::new ( & device ) ;
let viewport = Viewport ::new ( & device , & cache ) ;
let mut atlas = TextAtlas ::new ( & device , & queue , & cache , swapchain_format ) ;
let text_renderer =
TextRenderer ::new ( & mut atlas , & device , MultisampleState ::default ( ) , None ) ;
let mut text_buffer = Buffer ::new ( & mut font_system , Metrics ::new ( 30.0 , 42.0 ) ) ;
let physical_width = ( physical_size . width as f64 * scale_factor ) as f32 ;
let physical_height = ( physical_size . height as f64 * scale_factor ) as f32 ;
text_buffer . set_size (
& mut font_system ,
Some ( physical_width ) ,
Some ( physical_height ) ,
) ;
text_buffer . set_text ( & mut font_system , " Hello world! 👋 \n This is rendered with 🦅 glyphon 🦁 \n The text below should be partially clipped. \n a b c d e f g h i j k l m n o p q r s t u v w x y z " , Attrs ::new ( ) . family ( Family ::SansSerif ) , Shaping ::Advanced ) ;
text_buffer . shape_until_scroll ( & mut font_system , false ) ;
Self {
device ,
queue ,
surface ,
surface_config ,
font_system ,
swash_cache ,
viewport ,
atlas ,
text_renderer ,
text_buffer ,
window ,
}
}
}
struct Application {
window_state : Option < WindowState > ,
}
impl winit ::application ::ApplicationHandler for Application {
fn resumed ( & mut self , event_loop : & winit ::event_loop ::ActiveEventLoop ) {
if self . window_state . is_some ( ) {
return ;
}
// Set up window
let ( width , height ) = ( 800 , 600 ) ;
let window_attributes = Window ::default_attributes ( )
2024-04-29 11:31:15 -04:00
. with_inner_size ( LogicalSize ::new ( width as f64 , height as f64 ) )
2024-07-25 14:05:55 -04:00
. with_title ( " glyphon hello world " ) ;
let window = Arc ::new ( event_loop . create_window ( window_attributes ) . unwrap ( ) ) ;
2024-01-17 16:00:02 -05:00
2024-07-25 14:05:55 -04:00
self . window_state = Some ( pollster ::block_on ( WindowState ::new ( window ) ) ) ;
}
2022-05-09 08:49:10 -04:00
2024-07-25 14:05:55 -04:00
fn window_event (
& mut self ,
event_loop : & winit ::event_loop ::ActiveEventLoop ,
_window_id : winit ::window ::WindowId ,
event : WindowEvent ,
) {
let Some ( state ) = & mut self . window_state else {
return ;
} ;
let WindowState {
window ,
device ,
queue ,
surface ,
surface_config ,
font_system ,
swash_cache ,
viewport ,
atlas ,
text_renderer ,
text_buffer ,
..
} = state ;
match event {
WindowEvent ::Resized ( size ) = > {
surface_config . width = size . width ;
surface_config . height = size . height ;
surface . configure ( & device , & surface_config ) ;
window . request_redraw ( ) ;
}
WindowEvent ::RedrawRequested = > {
viewport . update (
& queue ,
Resolution {
width : surface_config . width ,
height : surface_config . height ,
} ,
) ;
text_renderer
. prepare (
device ,
queue ,
font_system ,
atlas ,
viewport ,
[ TextArea {
buffer : text_buffer ,
left : 10.0 ,
top : 10.0 ,
scale : 1.0 ,
bounds : TextBounds {
left : 0 ,
top : 0 ,
right : 600 ,
bottom : 160 ,
} ,
default_color : Color ::rgb ( 255 , 255 , 255 ) ,
2024-09-17 00:57:40 -04:00
custom_glyphs : & [ ] ,
2024-07-25 14:05:55 -04:00
} ] ,
swash_cache ,
)
. unwrap ( ) ;
let frame = surface . get_current_texture ( ) . unwrap ( ) ;
let view = frame . texture . create_view ( & TextureViewDescriptor ::default ( ) ) ;
let mut encoder =
device . create_command_encoder ( & CommandEncoderDescriptor { label : None } ) ;
{
let mut pass = encoder . begin_render_pass ( & RenderPassDescriptor {
label : None ,
color_attachments : & [ Some ( RenderPassColorAttachment {
view : & view ,
resolve_target : None ,
ops : Operations {
load : LoadOp ::Clear ( wgpu ::Color ::BLACK ) ,
store : wgpu ::StoreOp ::Store ,
2024-05-08 10:17:58 -04:00
} ,
2024-07-25 14:05:55 -04:00
} ) ] ,
depth_stencil_attachment : None ,
timestamp_writes : None ,
occlusion_query_set : None ,
} ) ;
text_renderer . render ( & atlas , & viewport , & mut pass ) . unwrap ( ) ;
2024-01-15 14:33:02 -05:00
}
2024-07-25 14:05:55 -04:00
queue . submit ( Some ( encoder . finish ( ) ) ) ;
frame . present ( ) ;
atlas . trim ( ) ;
2022-05-09 08:49:10 -04:00
}
2024-07-25 14:05:55 -04:00
WindowEvent ::CloseRequested = > event_loop . exit ( ) ,
_ = > { }
}
}
2022-05-09 08:49:10 -04:00
}