Files
a0_basic_app
a1_vehicle
a2_async_sim
ab_glyph
ab_glyph_rasterizer
adler
adler32
agents
aho_corasick
anyhow
approx
aquamarine
ash
atty
bitflags
bytemuck
byteorder
cache_padded
cfg_if
chrono
color_quant
crc32fast
crossbeam_channel
crossbeam_deque
crossbeam_epoch
crossbeam_utils
deflate
draw2d
either
flexi_logger
generic_array
gif
glfw
glfw_sys
glob
image
indoc
itertools
jpeg_decoder
lazy_static
libc
libloading
log
matrixmultiply
memchr
memoffset
miniz_oxide
nalgebra
base
geometry
linalg
third_party
num_complex
num_cpus
num_integer
num_iter
num_rational
num_traits
owned_ttf_parser
paste
png
proc_macro2
proc_macro_error
proc_macro_error_attr
quote
raw_window_handle
rawpointer
rayon
rayon_core
regex
regex_syntax
scoped_threadpool
scopeguard
semver
semver_parser
serde
serde_derive
simba
smawk
spin_sleep
syn
terminal_size
textwrap
thiserror
thiserror_impl
tiff
time
triple_buffer
ttf_parser
typenum
unicode_width
unicode_xid
unindent
vk_sys
weezl
yansi
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 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
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
use crate::app::UpdateTimer;

use super::{App, State};

use anyhow::Result;
use draw2d::{graphics::Graphics, GlfwWindow};
use flexi_logger::{DeferredNow, Logger, Record};
use glfw::WindowEvent;
use std::fmt::Write as FmtWrite;
use textwrap::{termwidth, Options};

impl<S: State> App<S> {
    /// Build a new instance of the application.
    ///
    /// `build_state` is a function which constructs an instance of the
    /// application's state type.
    ///
    pub fn new(
        build_state: fn(&mut glfw::Window, &mut Graphics) -> Result<S>,
    ) -> Result<Self> {
        Logger::with_env_or_str("info")
            .format(multiline_format)
            .start()?;

        log::info!("adjust log level by setting the RUST_LOG='info'");

        let mut window_surface = GlfwWindow::windowed("Agents", 1366, 768)?;
        let mut graphics = Graphics::new(&window_surface)?;
        window_surface.window.set_resizable(true);
        window_surface.window.set_key_polling(true);
        window_surface.window.set_size_polling(true);
        window_surface.window.set_scroll_polling(true);

        let state = build_state(&mut window_surface.window, &mut graphics)?;

        Ok(Self {
            graphics,
            window_surface,
            update_timer: UpdateTimer::new("Render Duration"),
            state,
        })
    }

    /// The application's main loop.
    ///
    /// This method will block until the user kills the application or until
    /// the State implementation calls `window.set_should_close(true)`.
    pub fn main_loop(mut self) -> Result<()> {
        // initialize the app's state
        self.state
            .init(&mut self.window_surface.window, &mut self.graphics)?;

        while !self.window_surface.window.should_close() {
            for (_, event) in self.window_surface.poll_events() {
                self.handle_event(event)?;
            }
            let duration = self.update_timer.tick();
            self.state.update(
                &mut self.window_surface.window,
                &mut self.graphics,
                duration,
            )?;
            self.graphics.render(&self.window_surface)?;
        }
        Ok(())
    }

    /// Handle window events and update the application state as needed.
    fn handle_event(&mut self, event: glfw::WindowEvent) -> Result<()> {
        match event {
            WindowEvent::FramebufferSize(_, _) => {
                self.graphics.rebuild_swapchain(&self.window_surface)?;
            }
            _ => {}
        }
        self.state.handle_event(
            &event,
            &mut self.window_surface.window,
            &mut self.graphics,
        )
    }
}

fn multiline_format(
    w: &mut dyn std::io::Write,
    now: &mut DeferredNow,
    record: &Record,
) -> Result<(), std::io::Error> {
    let size = termwidth().min(74);
    let wrap_options = Options::new(size)
        .initial_indent("┏ ")
        .subsequent_indent("┃ ");

    let mut full_line = String::new();
    writeln!(
        full_line,
        "{} [{}] [{}:{}]",
        record.level(),
        now.now().format("%H:%M:%S%.6f"),
        record.file().unwrap_or("<unnamed>"),
        record.line().unwrap_or(0),
    )
    .expect("unable to format first log line");

    write!(&mut full_line, "{}", &record.args())
        .expect("unable to format log!");

    writeln!(w, "{}", textwrap::fill(&full_line, wrap_options))
}