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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//! The application structure and supporting traits.
//!
//! # Example
//!
//! ```rust,no_run
//! use agents::app::{App, State};
//! use anyhow::{Context, Result};
//! use draw2d::graphics::{
//!     Graphics,
//!     layer::{LayerHandle, Batch},
//!     texture_atlas::TextureHandle,
//!     vertex::Vertex2d
//! };
//! use glfw::Window;
//! use std::time::Duration;
//!
//! /// Every binary will have a structure of some sort.
//! struct Example {
//!   layer: LayerHandle
//! }
//!
//! /// The structure can have whatever implementation functions it needs.
//! impl Example {
//!
//!   /// The constructor has access to both the window and graphics.
//!   pub fn create(
//!     window: &mut glfw::Window,
//!     graphics: &mut Graphics
//!   ) -> Result<Self> {
//!     Ok(Self {
//!       layer: graphics.add_layer_to_top()
//!     })
//!   }
//! }
//!
//! /// The example must implement State to be used with an application.
//! /// All methods have defaults, so none are *required* for a bare minimum
//! /// working example.
//! impl State for Example {
//!   fn update(
//!     &mut self,
//!     _: &mut Window,
//!     g: &mut Graphics,
//!     _dt: Duration
//!   ) -> Result<()> {
//!     let mut batch = Batch::empty();
//!     batch.vertices.extend_from_slice(&[
//!         Vertex2d {
//!             pos: [-100.0, -100.0],
//!             ..Default::default()
//!         },
//!         Vertex2d {
//!             pos: [100.0, -100.0],
//!             ..Default::default()
//!         },
//!         Vertex2d {
//!             pos: [0.0, 100.0],
//!             rgba: [0.1, 0.2, 0.8, 1.0],
//!             ..Default::default()
//!         },
//!     ]);
//!     g.get_layer_mut(&self.layer).push_batch(batch);
//!     Ok(())
//!   }
//! }
//!
//! /// Finally, start the application and let it run until the user quits.
//! fn main() -> Result<()> {
//!   App::new(Example::create)?.main_loop()
//! }
//! ```

mod app;
mod update_timer;

use anyhow::Result;
use draw2d::{graphics::Graphics, GlfwWindow};
use glfw::{Action, Key, WindowEvent};
use std::time::{Duration, Instant};

/// Each application maintains an instance of State which controls the actual
/// behavior and rendering.
pub trait State {
    /// Invoked by the application once just before the first update/render.
    ///
    /// This can be useful if any initialization needs to be done before
    /// rendering but *after* constructing the instance for some reason. Or if
    /// the application has need to setup some visuals which never
    /// change.
    #[allow(unused)]
    fn init(
        &mut self,
        window: &mut glfw::Window,
        graphics: &mut Graphics,
    ) -> Result<()> {
        Ok(())
    }

    /// Called once each frame before presenting the framebuffer.
    #[allow(unused)]
    fn update(
        &mut self,
        window: &mut glfw::Window,
        graphics: &mut Graphics,
        update_duration: Duration,
    ) -> Result<()> {
        Ok(())
    }

    /// Handle a glfw window event.
    ///
    /// The application can be stopped by calling `window.set_should_close`.
    /// By default, the application will close when `esc` is pressed.
    #[allow(unused)]
    fn handle_event(
        &mut self,
        window_event: &glfw::WindowEvent,
        window: &mut glfw::Window,
        graphics: &mut Graphics,
    ) -> Result<()> {
        match window_event {
            WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
                window.set_should_close(true);
                Ok(())
            }
            _ => Ok(()),
        }
    }
}

/// The main application.
///
/// This struct owns the window, the graphics subsystem, and the state. It is
/// responsible for the main application loop, rebuilding the swapchain, and
/// invoking functions on the State.
pub struct App<S: State> {
    graphics: Graphics,
    window_surface: GlfwWindow,
    update_timer: UpdateTimer,
    state: S,
}

/// The timer is used to compute the time to update and the average update
/// duration.
///
/// The timer prints the average update duration to the terminal. It only does
/// this every few seconds to prevent terminal IO from becoming a bottleneck.
pub struct UpdateTimer {
    /// The timer's display name
    display_name: String,

    /// The timestamp recorded for the last update.
    last_update: Instant,

    /// The timestamp recorded last time the average update duration was
    /// checkpointed.
    last_checkpoint: Instant,

    /// The number of updates since the last checkpoint.
    updates_since_checkpoint: i32,
}