├── .nowignore ├── assets ├── Banner.png ├── Logo.png └── stack_overflow.png ├── .gitignore ├── examples ├── hello_world.rs └── widgets.rs ├── src ├── graphics │ ├── types.rs │ └── renderer.rs ├── graphics.rs ├── error.rs ├── lib.rs ├── config.rs └── event.rs ├── rustfmt.toml ├── .github └── workflows │ ├── engine-macos.yml │ ├── engine-win.yml │ └── engine-linux.yml ├── Cargo.toml ├── LICENSE └── README.md /.nowignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | book/ 3 | examples/ 4 | src/ 5 | target/ -------------------------------------------------------------------------------- /assets/Banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NuroDev/atlas/HEAD/assets/Banner.png -------------------------------------------------------------------------------- /assets/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NuroDev/atlas/HEAD/assets/Logo.png -------------------------------------------------------------------------------- /assets/stack_overflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NuroDev/atlas/HEAD/assets/stack_overflow.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | /target/ 4 | Cargo.lock 5 | **/*.rs.bk 6 | 7 | public/ 8 | book/book/* 9 | 10 | docs/* 11 | !docs/now.json 12 | 13 | .vscode/* 14 | !.vscode/settings.json 15 | !.vscode/tasks.json 16 | !.vscode/launch.json 17 | !.vscode/extensions.json 18 | .history 19 | -------------------------------------------------------------------------------- /examples/hello_world.rs: -------------------------------------------------------------------------------- 1 | use atlas::{Config, Event, Game, Result}; 2 | 3 | struct HelloWorld; 4 | 5 | impl Game for HelloWorld {} 6 | 7 | fn main() -> Result<()> { 8 | env_logger::init(); 9 | 10 | let config: Config = Config::new().title("Hello World".to_owned()); 11 | 12 | Event::new(config, Box::new(HelloWorld)).run() 13 | } 14 | -------------------------------------------------------------------------------- /src/graphics/types.rs: -------------------------------------------------------------------------------- 1 | /// Default graphics device 2 | pub type Device = gfx_device_gl::Device; 3 | 4 | /// Default graphics factory 5 | pub type Factory = gfx_device_gl::Factory; 6 | 7 | /// Default graphics resource(s) 8 | pub type Resources = gfx_device_gl::Resources; 9 | 10 | /// Default color format is RGBA (8-bit) 11 | pub type ColorFormat = gfx::format::Rgba8; 12 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | combine_control_expr = false 2 | fn_single_line = true 3 | format_macro_bodies = false 4 | format_strings = true 5 | hard_tabs = true 6 | imports_indent = "Block" 7 | imports_layout = "HorizontalVertical" 8 | indent_style = "Block" 9 | match_block_trailing_comma = true 10 | merge_imports = true 11 | normalize_comments = true 12 | reorder_impl_items = true 13 | struct_lit_single_line = false 14 | type_punctuation_density = "Compressed" 15 | use_field_init_shorthand = true 16 | where_single_line = true 17 | wrap_comments = true 18 | -------------------------------------------------------------------------------- /.github/workflows/engine-macos.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Engine (macOS) 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | name: Build 8 | runs-on: macos-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | toolchain: [stable, beta, nightly] 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | - name: Toolchain 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | toolchain: ${{ matrix.toolchain }} 20 | override: true 21 | - name: Build 22 | uses: actions-rs/cargo@v1 23 | with: 24 | command: build 25 | args: --verbose --release 26 | -------------------------------------------------------------------------------- /.github/workflows/engine-win.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Engine (Windows) 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | name: Build 8 | runs-on: windows-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | toolchain: [stable, beta, nightly] 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | - name: Toolchain 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | toolchain: ${{ matrix.toolchain }} 20 | override: true 21 | - name: Build 22 | uses: actions-rs/cargo@v1 23 | with: 24 | command: build 25 | args: --verbose --release 26 | -------------------------------------------------------------------------------- /.github/workflows/engine-linux.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Engine (Linux) 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | name: Build 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | toolchain: [stable, beta, nightly] 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | - name: Install libudev 17 | run: sudo apt update && sudo apt install libudev-dev 18 | - name: Toolchain 19 | uses: actions-rs/toolchain@v1 20 | with: 21 | toolchain: ${{ matrix.toolchain }} 22 | override: true 23 | - name: Build 24 | uses: actions-rs/cargo@v1 25 | with: 26 | command: build 27 | args: --verbose --release 28 | -------------------------------------------------------------------------------- /src/graphics.rs: -------------------------------------------------------------------------------- 1 | use crate::Result; 2 | use imgui::Ui; 3 | 4 | /// The interface between the engine and your game. 5 | /// Implement it, and pass your struct to `Window::main_loop`. 6 | pub trait Game { 7 | /// Called every frame to draw/render content 8 | fn draw(&mut self) -> Result { Ok(()) } 9 | /// Called on window close button click 10 | fn exit(&mut self) -> Result { Ok(()) } 11 | /// Called at launch to initialize & load assets 12 | fn load(&mut self) -> Result { Ok(()) } 13 | /// Draw custom UI elements using imgui 14 | fn ui(&mut self, _ui: &mut Ui) -> Result { Ok(()) } 15 | /// Called on every update tick event 16 | fn update(&mut self) -> Result { Ok(()) } 17 | } 18 | 19 | mod renderer; 20 | mod types; 21 | 22 | pub use renderer::AtlasRenderer as Renderer; 23 | pub use types::*; 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "atlas" 3 | description = "🌈 Proof-of-concept game engine built using Rust" 4 | version = "1.1.1" 5 | authors = ["N U R O ™ "] 6 | license = "MIT" 7 | edition = "2018" 8 | readme = "README.md" 9 | repository = "https://github.com/nurodev/atlas" 10 | documentation = "https://docs.atlas.nuro.sh/" 11 | homepage = "https://atlas.nuro.sh/" 12 | exclude = ["example", "target"] 13 | keywords = ["game", "engine", "atlas"] 14 | 15 | [lib] 16 | name = "atlas" 17 | path = "./src/lib.rs" 18 | 19 | [features] 20 | opengl = ["imgui-gfx-renderer/opengl"] 21 | default = ["opengl"] 22 | 23 | [dependencies] 24 | derive-new = "0.5.8" 25 | gfx = "0.18.2" 26 | gfx_device_gl = "0.16.2" 27 | gfx_window_glutin = "0.31" 28 | gilrs = "0.7.4" 29 | glutin = "0.21" 30 | image = "0.23" 31 | imgui = "0.3.0" 32 | imgui-gfx-renderer = "0.3.0" 33 | imgui-winit-support = { version = "0.3.0", default-features = false, features = ["winit-19"] } 34 | log = "0.4.8" 35 | nalgebra = "0.19" 36 | quick-error = "1.2.3" 37 | 38 | [dev-dependencies] 39 | env_logger = "0.7.1" 40 | -------------------------------------------------------------------------------- /examples/widgets.rs: -------------------------------------------------------------------------------- 1 | use atlas::{ 2 | ui::{im_str, Condition, Ui, Window, WindowFlags}, 3 | Config, 4 | Event, 5 | Game, 6 | Result, 7 | }; 8 | 9 | const RESOLUTION: (f64, f64) = (1280.0, 720.0); 10 | struct Widgets; 11 | 12 | impl Game for Widgets { 13 | fn ui(&mut self, ui: &mut Ui) -> Result<()> { 14 | let offset: f32 = 10.0; 15 | let size: (f32, f32) = (150.0, 25.0); 16 | 17 | Window::new(im_str!("Metrics")) 18 | .size([size.0, size.1], Condition::Always) 19 | .flags(WindowFlags::NO_MOVE) 20 | .flags(WindowFlags::NO_DECORATION) 21 | .position( 22 | [(RESOLUTION.0 as f32) - size.0 - offset, offset], 23 | Condition::Always, 24 | ) 25 | .build(ui, || { 26 | ui.text(im_str!("FPS: {}", ui.io().framerate)); 27 | }); 28 | 29 | ui.show_demo_window(&mut true); 30 | 31 | Ok(()) 32 | } 33 | } 34 | 35 | fn main() -> Result<()> { 36 | env_logger::init(); 37 | 38 | let config = Config::new() 39 | .title("Widgets".to_string()) 40 | .resolution(RESOLUTION.0, RESOLUTION.1); 41 | 42 | Event::new(config, Box::new(Widgets)).run() 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 N U R O ™ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use quick_error::quick_error; 2 | 3 | quick_error! { 4 | #[derive(Debug)] 5 | pub enum AtlasError { 6 | /// TODO: Documentation 7 | Audio(message: String) { 8 | description("Audio Error") 9 | display("Audio Error: {}", message) 10 | } 11 | /// TODO: Documentation 12 | Config(message: String) { 13 | description("Config Error") 14 | display("Config Error: {}", message) 15 | } 16 | /// TODO: Documentation 17 | Event(message: String) { 18 | description("Event Error") 19 | display("Event Error: {}", message) 20 | } 21 | /// TODO: Documentation 22 | Font(message: String) { 23 | description("Font Error") 24 | display("Font Error: {}", message) 25 | } 26 | /// TODO: Documentation 27 | Graphics(message: String) { 28 | description("Graphics Error") 29 | display("Graphics Error: {}", message) 30 | } 31 | /// TODO: Documentation 32 | Input(message: String) { 33 | description("Input Error") 34 | display("Input Error: {}", message) 35 | } 36 | /// TODO: Documentation 37 | Resource(message: String) { 38 | description("Resource Error") 39 | display("Resource Error: {}", message) 40 | } 41 | /// TODO: Documentation 42 | Window(message: String) { 43 | description("Window Error") 44 | display("Window Error: {}", message) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [![](https://raw.githubusercontent.com/NuroDev/atlas/master/book/src/assets/Banner.png)](https://github.com/nurodev/atlas) 2 | //! 3 | //! ## Features: 4 | //! * Coming Soon 5 | //! 6 | //! ## Disclaimer: 7 | //! Atlas is still a work-in-progress project and is not recommended for 8 | //! production use. 9 | //! 10 | //! ## Installation: 11 | //! You can install Atlas by adding Atlas as a dependency to you `Cargo.toml` 12 | //! file. 13 | //! ```toml 14 | //! [dependencies] 15 | //! atlas = { git = "https://github.com/nurodev/atlas" } 16 | //! ``` 17 | //! 18 | //! ## Example: 19 | //! ```rust 20 | //! use atlas::{ 21 | //! ui::{im_str, Condition, Ui, Window, WindowFlags}, 22 | //! Config, 23 | //! Event, 24 | //! Game, 25 | //! Result, 26 | //! }; 27 | //! 28 | //! struct MyGame; 29 | //! 30 | //! fn main() -> Result<()> { 31 | //! // Create a new application config 32 | //! let config = Config::new().title("My Game".to_string()); 33 | //! 34 | //! // Run the application 35 | //! Event::new(config, Box::new(Widgets)).run() 36 | //! } 37 | 38 | #![crate_name = "atlas"] 39 | #![doc( 40 | html_logo_url = "https://raw.githubusercontent.com/NuroDev/atlas/master/book/src/assets/Logo.png" 41 | )] 42 | #![warn(dead_code)] 43 | 44 | /// TODO: Documentation 45 | pub type Result = std::result::Result; 46 | 47 | mod config; 48 | mod error; 49 | mod event; 50 | mod graphics; 51 | 52 | pub use config::Config; 53 | pub use error::AtlasError as Error; 54 | pub use event::AtlasEvent as Event; 55 | pub use graphics::Game; 56 | 57 | pub extern crate imgui as ui; 58 | pub extern crate nalgebra as math; 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | Atlas 5 | 6 | 7 | [![Build-Windows]()](https://github.com/NuroDev/atlas/actions?query=workflow%3A%22%F0%9F%9A%80+Engine+%28Windows%29%22) 8 | [![Build - macOS]()](https://github.com/NuroDev/atlas/actions?query=workflow%3A%22%F0%9F%9A%80+Engine+%28macOS%29%22) 9 | [![Build - Linux]()](https://github.com/NuroDev/atlas/actions?query=workflow%3A%22%F0%9F%9A%80+Engine+%28Linux%29%22) 10 | 11 | 14 | 15 |
16 |
17 | 18 | ## 👨‍💻 Development 19 | 20 | ### Requirements 21 | 22 | To use this project you will need the following tools installed on your system: 23 | 24 | - [Rust](https://rustup.rs/) 25 | - [rustfmt](https://github.com/rust-lang/rustfmt) 26 | 27 | ### Clone 28 | 29 | To fetch the repository, use the following command: 30 | 31 | ```zsh 32 | git clone https://github.com/nurodev/atlas.git 33 | ``` 34 | 35 | ### Build 36 | 37 | To build the project with your desired target platform, use the following command & replacing the `--features` parameter with your desired backend target: 38 | 39 | ```zsh 40 | cargo build --features [dx11|dx12|metal|vulkan] 41 | ``` 42 | 43 | ### Run 44 | 45 | Similarly to run the applicatio, use the following command: 46 | 47 | ```zsh 48 | cargo run --features [dx11|dx12|metal|vulkan] 49 | ``` 50 | 51 | ## 🔑 License 52 | 53 | MIT © [Ben Dixon](https://github.com/NuroDev/atlas/blob/main/LICENSE) 54 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use derive_new::new; 2 | 3 | /// TODO: Documentation 4 | #[derive(Clone, Debug)] 5 | pub enum WindowMode { 6 | /// Free floating window 7 | Borderless, 8 | /// Complete fullscreen window 9 | Fullscreen, 10 | /// Fake fullscreen (Plays better with alt tabbing/Multiple monitors) window 11 | Windowed, 12 | } 13 | 14 | impl Default for WindowMode { 15 | fn default() -> WindowMode { WindowMode::Windowed } 16 | } 17 | 18 | /// TODO: Documentation 19 | #[derive(Clone, Debug)] 20 | pub struct Resolution { 21 | /// TODO: Documentation 22 | pub width: f64, 23 | /// TODO: Documentation 24 | pub height: f64, 25 | } 26 | 27 | impl Default for Resolution { 28 | fn default() -> Resolution { 29 | Resolution { 30 | width: 1024f64, 31 | height: 768f64, 32 | } 33 | } 34 | } 35 | 36 | /// TODO: Documentation 37 | #[derive(Clone, Debug, new)] 38 | pub struct Config { 39 | /// If the window resizable 40 | #[new(default)] 41 | pub resizable: bool, 42 | 43 | /// Window resolution (Width x Height) 44 | #[new(default)] 45 | pub resolution: Resolution, 46 | 47 | /// Window title 48 | #[new(default)] 49 | pub title: String, 50 | 51 | /// Whether to enable v-sync or not 52 | #[new(default)] 53 | pub vsync: bool, 54 | 55 | /// Window mode 56 | #[new(default)] 57 | pub window_mode: WindowMode, 58 | } 59 | 60 | impl Default for Config { 61 | fn default() -> Config { 62 | Config { 63 | resizable: false, 64 | resolution: Resolution::default(), 65 | title: "Atlas".to_owned(), 66 | vsync: true, 67 | window_mode: WindowMode::Windowed, 68 | } 69 | } 70 | } 71 | 72 | impl Config { 73 | /// Set whether the window is resizable 74 | pub fn resizable(mut self, resizable: bool) -> Self { 75 | self.resizable = resizable; 76 | self 77 | } 78 | 79 | /// Set the window resolution (width/height) 80 | pub fn resolution(mut self, width: f64, height: f64) -> Self { 81 | self.resolution = Resolution { 82 | width, 83 | height, 84 | }; 85 | self 86 | } 87 | 88 | /// Set the window title 89 | pub fn title(mut self, title: String) -> Self { 90 | self.title = title; 91 | self 92 | } 93 | 94 | /// Set whether to use V-sync or not 95 | pub fn vsync(mut self, vsync: bool) -> Self { 96 | self.vsync = vsync; 97 | self 98 | } 99 | 100 | /// Set the window mode 101 | pub fn window_mode(mut self, window_mode: WindowMode) -> Self { 102 | self.window_mode = window_mode; 103 | self 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/graphics/renderer.rs: -------------------------------------------------------------------------------- 1 | use crate::graphics::types::{ColorFormat, Device, Factory, Resources}; 2 | use glutin::{ 3 | dpi::LogicalSize, 4 | ContextBuilder, 5 | EventsLoop, 6 | PossiblyCurrent, 7 | Window, 8 | WindowBuilder, 9 | WindowedContext, 10 | }; 11 | use imgui::Context; 12 | use imgui_gfx_renderer::{Renderer, Shaders}; 13 | 14 | pub struct AtlasRenderer { 15 | /// TODO: Documentation 16 | pub renderer: Renderer, 17 | /// TODO: Documentation 18 | pub windowed_context: WindowedContext, 19 | /// TODO: Documentation 20 | pub device: Device, 21 | /// TODO: Documentation 22 | pub factory: Factory, 23 | /// TODO: Documentation 24 | pub main_color: Option>, 25 | /// TODO: Documentation 26 | pub main_depth: gfx::handle::DepthStencilView, 27 | } 28 | 29 | impl AtlasRenderer { 30 | /// TODO: Documentation 31 | pub fn new( 32 | imgui: &mut Context, 33 | builder: WindowBuilder, 34 | events_loop: &EventsLoop, 35 | ) -> AtlasRenderer 36 | { 37 | { 38 | // Fix incorrect colors with sRGB framebuffer 39 | let style = imgui.style_mut(); 40 | for col in 0..style.colors.len() { 41 | let color = style.colors[col]; 42 | style.colors[col] = [ 43 | color[0].powf(2.2), 44 | color[1].powf(2.2), 45 | color[2].powf(2.2), 46 | 1.0 - (1.0 - color[3]).powf(2.2), 47 | ]; 48 | } 49 | } 50 | 51 | let context = ContextBuilder::new().with_vsync(true); 52 | 53 | let (windowed_context, device, mut factory, main_color, main_depth) = 54 | gfx_window_glutin::init(builder, context, &events_loop) 55 | .expect("Failed to initialize graphics"); 56 | 57 | let shaders = { 58 | let version = device.get_info().shading_language; 59 | if version.is_embedded { 60 | if version.major >= 3 { 61 | Shaders::GlSlEs300 62 | } else { 63 | Shaders::GlSlEs100 64 | } 65 | } else if version.major >= 4 { 66 | Shaders::GlSl400 67 | } else if version.major >= 3 { 68 | if version.minor >= 2 { 69 | Shaders::GlSl150 70 | } else { 71 | Shaders::GlSl130 72 | } 73 | } else { 74 | Shaders::GlSl110 75 | } 76 | }; 77 | 78 | let renderer = 79 | Renderer::init(imgui, &mut factory, shaders).expect("Failed to initialize renderer"); 80 | 81 | AtlasRenderer { 82 | renderer, 83 | windowed_context, 84 | device, 85 | factory, 86 | main_color: Some(main_color), 87 | main_depth, 88 | } 89 | } 90 | 91 | /// TODO: Documentation 92 | pub fn swap_buffers(&mut self) { self.windowed_context.swap_buffers().unwrap(); } 93 | 94 | /// TODO: Documentation 95 | pub fn update_views(&mut self, _: LogicalSize) { 96 | if let Some(main_color) = self.main_color.as_mut() { 97 | gfx_window_glutin::update_views( 98 | &self.windowed_context, 99 | main_color, 100 | &mut self.main_depth, 101 | ); 102 | } 103 | } 104 | 105 | /// TODO: Documentation 106 | pub fn window(&self) -> &Window { self.windowed_context.window() } 107 | } 108 | -------------------------------------------------------------------------------- /src/event.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | config::Config, 3 | graphics::{Game, Renderer}, 4 | Result, 5 | }; 6 | use derive_new::new; 7 | use gfx::Encoder; 8 | use glutin::{dpi::LogicalSize, Event, EventsLoop, WindowBuilder, WindowEvent}; 9 | use imgui::{Context, DrawData, Io, Ui}; 10 | use imgui_winit_support::{HiDpiMode, WinitPlatform}; 11 | use log::info; 12 | use std::time::Instant; 13 | 14 | #[derive(new)] 15 | pub struct AtlasEvent { 16 | /// TODO: Documentation 17 | pub config: Config, 18 | /// TODO: Documentation 19 | pub game: Box, 20 | } 21 | 22 | impl AtlasEvent { 23 | pub fn run(&mut self) -> Result<()> { 24 | info!("Starting event loop..."); 25 | 26 | // Create primary app event loop 27 | let mut events_loop: EventsLoop = EventsLoop::new(); 28 | 29 | // Create app window builder 30 | let builder: WindowBuilder = WindowBuilder::new() 31 | .with_title(&self.config.title) 32 | .with_dimensions(LogicalSize::new( 33 | self.config.resolution.width, 34 | self.config.resolution.height, 35 | )); 36 | 37 | // Create device context 38 | let mut context = Context::create(); 39 | context.set_ini_filename(None); 40 | 41 | // Initialize window platform using winit 42 | let mut platform: WinitPlatform = WinitPlatform::init(&mut context); 43 | 44 | // Get current DPI factor from winit 45 | let hidpi_factor: f64 = platform.hidpi_factor(); 46 | 47 | // Set global font size based on dpi factor 48 | context.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32; 49 | 50 | // Create renderer instance using previously created context, window builder 51 | // and primary event loop 52 | let mut renderer_sys: Renderer = Renderer::new(&mut context, builder, &events_loop); 53 | platform.attach_window(context.io_mut(), renderer_sys.window(), HiDpiMode::Rounded); 54 | 55 | let mut encoder: Encoder<_, _> = renderer_sys.factory.create_command_buffer().into(); 56 | 57 | let mut last_frame: Instant = Instant::now(); 58 | let mut is_running: bool = true; 59 | 60 | while is_running { 61 | // Window event handler 62 | events_loop.poll_events(|event| { 63 | platform.handle_event(context.io_mut(), renderer_sys.window(), &event); 64 | 65 | if let Event::WindowEvent { 66 | event, .. 67 | } = event 68 | { 69 | match event { 70 | WindowEvent::Resized(size) => renderer_sys.update_views(size), 71 | WindowEvent::CloseRequested => is_running = false, 72 | _ => (), 73 | } 74 | } 75 | }); 76 | 77 | let io: &mut Io = context.io_mut(); 78 | platform 79 | .prepare_frame(io, renderer_sys.window()) 80 | .expect("Failed to start frame"); 81 | last_frame = io.update_delta_time(last_frame); 82 | let mut ui: Ui = context.frame(); 83 | 84 | self.game.update()?; 85 | self.game.draw()?; 86 | self.game.ui(&mut ui)?; 87 | 88 | if let Some(main_color) = renderer_sys.main_color.as_mut() { 89 | encoder.clear(main_color, [0.0, 0.0, 0.0, 0.0]); 90 | } 91 | platform.prepare_render(&ui, renderer_sys.window()); 92 | let draw_data: &DrawData = ui.render(); 93 | if let Some(main_color) = renderer_sys.main_color.as_mut() { 94 | renderer_sys 95 | .renderer 96 | .render( 97 | &mut renderer_sys.factory, 98 | &mut encoder, 99 | main_color, 100 | draw_data, 101 | ) 102 | .expect("Rendering failed"); 103 | } 104 | 105 | encoder.flush(&mut renderer_sys.device); 106 | renderer_sys.swap_buffers(); 107 | 108 | // TODO 109 | // renderer_sys.device.cleanup(); 110 | } 111 | 112 | Ok(()) 113 | } 114 | } 115 | --------------------------------------------------------------------------------