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
// #![deny(missing_docs)]
//! Terminal game engine
//! ```
//! # use tinybit::events::{events, Event, KeyCode, KeyEvent, EventModel};
//! # use tinybit::{
//! #     term_size, Camera, Renderer, ScreenPos, ScreenSize, StdoutTarget, Viewport,
//! #     WorldPos, WorldSize, Pixel
//! # };
//! 
//! fn main() {
//!     let (width, height) = term_size().expect("Can't get the term size? Can't play the game!");
//! 
//!     // Viewport
//!     let viewport_size = ScreenSize::new(width / 2, height / 2);
//!     let mut viewport = Viewport::new(ScreenPos::new(0, 4), viewport_size);
//! 
//!     // Camera
//!     let (width, height) = (width as f32, height as f32);
//!     let camera_size = WorldSize::new(width / 2.0, height / 2.0); let camera_pos =
//!     WorldPos::new(width, height);
//!     let mut camera = Camera::new(camera_pos, camera_size);
//! 
//!     // Renderer
//!     let stdout_renderer = StdoutTarget::new().expect("Failed to enter raw mode");
//!     let mut renderer = Renderer::new(stdout_renderer);
//! 
//!     // Player
//!     let mut player = ('@', camera_pos);
//! 
//!     for event in events(EventModel::Fps(20)) {
//!         match event {
//!             Event::Tick => {
//!                 let pixel = Pixel::new(player.0, camera.to_screen(player.1), None, None);
//!                 viewport.draw_pixel(pixel);
//!                 let _ = renderer.render(&mut viewport);
//! #               break
//!             }
//!             Event::Key(KeyEvent { code: KeyCode::Esc, ..  }) => break,
//!             Event::Key(KeyEvent { code: kc, .. }) => {
//!                 match kc {
//!                     KeyCode::Left => { player.1.x -= 1.0; }
//!                     KeyCode::Right => { player.1.x += 1.0; }
//!                     KeyCode::Up => { player.1.y -= 1.0; }
//!                     KeyCode::Down => { player.1.y += 1.0; }
//!                     _ => {}
//!                 }
//!             }
//!             Event::Resize(w, h) => {}
//!         }
//!     }
//! }
//! ```

use serde::{Serialize, Deserialize};

mod pixelbuffer;
mod viewport;

pub mod render;
pub mod camera;
pub mod events;
pub mod widgets;

/// A character at a position, with a colour
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)]
pub struct Pixel {
    pub glyph: char,
    pub pos: ScreenPos,
    pub fg_color: Option<Color>,
    pub bg_color: Option<Color>,
}

impl Pixel {
    pub fn new(glyph: char, pos: ScreenPos, fg_color: Option<Color>, bg_color: Option<Color>) -> Self {
        Self {
            glyph,
            pos,
            fg_color,
            bg_color,
        }
    } 

    pub fn white(c: char, pos: ScreenPos) -> Self {
        Self::new(c, pos, None, None)
    }
}

// -----------------------------------------------------------------------------
//     - Reexports -
// -----------------------------------------------------------------------------
pub use camera::Camera;
pub use pixelbuffer::PixelBuffer;
pub use crossterm::terminal::size as term_size;
pub use render::{Renderer, StdoutTarget};
pub use viewport::Viewport;
pub use crossterm::style::{Colored, Color};
pub use crossterm::ErrorKind as CrosstermError;

// -----------------------------------------------------------------------------
//     - Euclid -
// -----------------------------------------------------------------------------
pub type Vec2D<T> = euclid::default::Vector2D<T>;

/// Constraining units to screen space
#[derive(Serialize, Deserialize, Debug)]
pub struct Screen;

/// Constraining units to world space
#[derive(Serialize, Deserialize, Debug)]
pub struct World;

/// A position on screen, where 0,0 is the top left corner
pub type ScreenPos = euclid::Point2D<u16, Screen>;

/// A position in the world
pub type WorldPos = euclid::Point2D<f32, World>;

/// A rect on screen
pub type ScreenRect = euclid::Rect<u16, Screen>;

/// A rect in the world
pub type WorldRect = euclid::Rect<f32, World>;

/// A size on screen
pub type ScreenSize = euclid::Size2D<u16, Screen>;

/// A size in the world
pub type WorldSize = euclid::Size2D<f32, World>;