circle.rs
1 //! Simple circle scene. 2 //! 3 //! # Controls 4 //! - Scroll: increase / decrease number of sides 5 6 use glam::Vec2; 7 use let_engine::prelude::*; 8 9 use gpu::{VulkanTypes, model::ModelId}; 10 11 // Limit of corners 12 const MAX_SIDES: usize = 1000; 13 14 fn main() { 15 // Log messages 16 simple_logger::SimpleLogger::new() 17 .with_level(log::LevelFilter::Debug) 18 .init() 19 .unwrap(); 20 21 // First you make a builder containing the description of the window. 22 let window_builder = WindowBuilder::new() 23 .inner_size(uvec2(1280, 720)) 24 .title(env!("CARGO_CRATE_NAME")); 25 26 // Now we run the engine 27 let_engine::start( 28 EngineSettings::default() 29 .window(window_builder) 30 .gpu(gpu::GpuSettings { 31 present_mode: gpu::PresentMode::Fifo, 32 ..Default::default() 33 }), 34 Game::new, 35 ) 36 .unwrap(); 37 } 38 39 /// Makes a game struct containing 40 struct Game { 41 model: ModelId<Vec2>, 42 sides: u32, 43 } 44 45 impl Game { 46 /// Constructor for this scene. 47 pub fn new(context: EngineContext) -> Result<Self, ()> { 48 { 49 let root_view = context.scene.root_view_mut(); 50 51 // next we set the view of the game scene zoomed out and not stretchy. 52 root_view.transform = Transform::with_size(Vec3::splat(2.0)); 53 root_view.scaling = CameraScaling::Circle; 54 } 55 56 // First we get the root layer where the scene will be simulated on. 57 let root_layer = context.scene.root_layer(); 58 59 // Create a "circle" model with a default amount of sides. 60 let sides = 15; 61 let mut circle_model = circle!(sides, BufferAccess::Pinned(PreferOperation::Write)); 62 63 // Raise maximum vertices and indices for growable model 64 65 // 1 vertex per side including `+ 1` for the center vertex 66 circle_model.set_max_vertices(MAX_SIDES + 1); 67 // Each side is 1 vertex, so 3 corners. 68 circle_model.set_max_indices(MAX_SIDES * 3); 69 70 // Load circle model to the GPU. 71 let circle_model = context.gpu.load_model(&circle_model).unwrap(); 72 73 let default_material = context 74 .gpu 75 .load_material::<Vec2>(&Material::new_default()) 76 .unwrap(); 77 78 let color_buffer = context 79 .gpu 80 .load_buffer(&Buffer::from_data( 81 buffer::BufferUsage::Uniform, 82 BufferAccess::Fixed, 83 Color::from_rgb(1.0, 0.3, 0.5), 84 )) 85 .unwrap(); 86 87 let circle_appearance = AppearanceBuilder::<VulkanTypes, Vec2>::default() 88 .model(circle_model) 89 .material(default_material) 90 .descriptors(&[ 91 (Location::new(0, 0), Descriptor::Mvp), 92 (Location::new(1, 0), Descriptor::buffer(color_buffer)), 93 ]) 94 .build(&context.gpu) 95 .unwrap(); 96 97 // Makes the circle in the middle. 98 let circle = ObjectBuilder::with_appearance(circle_appearance); 99 100 // Initializes the object to the layer 101 context.scene.add_object(root_layer.id(), circle).unwrap(); 102 103 Ok(Self { 104 model: circle_model, 105 sides, 106 }) 107 } 108 } 109 110 /// Implement the Game trait into the Game struct. 111 impl let_engine::Game for Game { 112 // Exit when the X button on the window is pressed. 113 fn window(&mut self, context: EngineContext, event: WindowEvent) -> Result<(), ()> { 114 match event { 115 WindowEvent::CloseRequested => context.exit(), 116 WindowEvent::MouseWheel(ScrollDelta::LineDelta(delta)) => { 117 // Add or subtract side depending on the delta of the scroll 118 if delta.y > 0.0 { 119 if self.sides < MAX_SIDES as u32 { 120 self.sides += 1; 121 log::info!("(+) Corners: {}", self.sides); 122 } 123 } else if self.sides > 2 { 124 self.sides -= 1; 125 log::info!("(-) Corners: {}", self.sides); 126 } 127 128 // Generate new circle model and write it to the GPU 129 let new_model = circle!(self.sides); 130 // Index model from backend index implementation directly 131 context.gpu[self.model].write_model(&new_model).unwrap(); 132 } 133 _ => (), 134 } 135 Ok(()) 136 } 137 138 // Exit when the escape key is pressed. 139 fn input(&mut self, context: EngineContext, event: InputEvent) -> Result<(), ()> { 140 if let InputEvent::KeyboardInput { input } = event 141 && let ElementState::Pressed = input.state 142 && let Key::Named(NamedKey::Escape) = input.key 143 { 144 context.exit(); 145 } 146 Ok(()) 147 } 148 }