aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2021-02-07 22:48:48 +0100
committerKatharina Fey <kookie@spacekookie.de>2021-02-07 22:48:48 +0100
commitb53b19ee469801b2aaa02dc7ee244892269550c4 (patch)
treee861a548525fff058070796df83ebfcb16f56041
parentf9d4d7ec0198f192f53e583c259e35350fe9fb62 (diff)
rstnode: implement viewport shifting
A bit of a rant: it's fucking ridiculous how much work it is to subtract two points from each other with mint + nalgebra. I ended up adding a complete `Vector2` implementation in this commit because I got fed up with it. Consider this the unofficial start of librgx (rust graphics x), which will basically become a libgdx in Rust, and the basis for the little game engine. Not to mention that ggez probably won't be maintained past version 0.6.0 unless some other maintainer takes over (I guess that could always happen). Anyway, I'm annoyed!
-rw-r--r--games/rstnode/rst-client/src/graphics/mod.rs4
-rw-r--r--games/rstnode/rst-client/src/graphics/vector2.rs82
-rw-r--r--games/rstnode/rst-client/src/input.rs23
-rw-r--r--games/rstnode/rst-client/src/main.rs9
-rw-r--r--games/rstnode/rst-client/src/state.rs16
-rw-r--r--games/rstnode/rst-client/src/viewport.rs63
6 files changed, 187 insertions, 10 deletions
diff --git a/games/rstnode/rst-client/src/graphics/mod.rs b/games/rstnode/rst-client/src/graphics/mod.rs
index 095e66f1ad1f..a7ba676ecc6b 100644
--- a/games/rstnode/rst-client/src/graphics/mod.rs
+++ b/games/rstnode/rst-client/src/graphics/mod.rs
@@ -8,8 +8,12 @@
pub mod entities;
pub mod ui;
+mod vector2;
+pub use vector2::*;
+
use crate::state::ClientState;
use ggez::{Context, GameResult};
+use std::ops::{Add, Mul, Sub};
/// A utility module to include everything required to implement a
/// graphics entity
diff --git a/games/rstnode/rst-client/src/graphics/vector2.rs b/games/rstnode/rst-client/src/graphics/vector2.rs
new file mode 100644
index 000000000000..5204e77fa443
--- /dev/null
+++ b/games/rstnode/rst-client/src/graphics/vector2.rs
@@ -0,0 +1,82 @@
+use std::fmt::{self, Display, Formatter};
+use std::ops::{Add, Mul, Sub, SubAssign};
+
+/// Just a vector
+#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd)]
+pub struct Vector2 {
+ pub x: f32,
+ pub y: f32,
+}
+
+impl Display for Vector2 {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ write!(f, "[{}, {}]", self.x, self.y)
+ }
+}
+
+impl Vector2 {
+ pub fn new(x: f32, y: f32) -> Self {
+ Self { x, y }
+ }
+
+ pub fn abs(self) -> Self {
+ Self {
+ x: self.x.abs(),
+ y: self.y.abs(),
+ }
+ }
+}
+
+impl Sub for Vector2 {
+ type Output = Vector2;
+
+ fn sub(self, o: Vector2) -> Self::Output {
+ Vector2 {
+ x: self.x - o.x,
+ y: self.y - o.y,
+ }
+ }
+}
+
+impl SubAssign for Vector2 {
+ fn sub_assign(&mut self, o: Self) {
+ *self = Self {
+ x: self.x - o.x,
+ y: self.y - o.y,
+ }
+ }
+}
+
+impl Add for Vector2 {
+ type Output = Vector2;
+
+ fn add(self, o: Vector2) -> Self::Output {
+ Vector2 {
+ x: self.x + o.x,
+ y: self.y + o.y,
+ }
+ }
+}
+
+impl Mul for Vector2 {
+ type Output = Vector2;
+
+ fn mul(self, o: Vector2) -> Self::Output {
+ Vector2 {
+ x: self.x * o.x,
+ y: self.y * o.y,
+ }
+ }
+}
+
+impl From<Vector2> for mint::Point2<f32> {
+ fn from(v: Vector2) -> Self {
+ [v.x, v.y].into()
+ }
+}
+
+impl From<mint::Point2<f32>> for Vector2 {
+ fn from(v: mint::Point2<f32>) -> Self {
+ Self { x: v.x, y: v.y }
+ }
+}
diff --git a/games/rstnode/rst-client/src/input.rs b/games/rstnode/rst-client/src/input.rs
index 4e901b8ade06..281386986434 100644
--- a/games/rstnode/rst-client/src/input.rs
+++ b/games/rstnode/rst-client/src/input.rs
@@ -1,50 +1,55 @@
//! Advanced input handler
+use crate::{graphics::Vector2, viewport::Viewport};
use ggez::{
event::EventHandler,
input::mouse::{self, MouseButton},
Context, GameResult,
};
-use mint::Point2;
pub struct InputHandle {
/// The mouse position on the viewport
- pub mouse_pos: Point2<f32>,
+ pub mouse_pos: Vector2,
/// Whether the left mouse button is pressed this frame
pub left_pressed: bool,
+ /// Whether the middle mouse button is pressed this frame
+ pub middle_pressed: bool,
/// Whether the right mouse button is pressed this frame
pub right_pressed: bool,
/// Set when pressing left mouse and unset when releasing it
- pub drag_point: Option<Point2<f32>>,
+ pub drag_point: Option<Vector2>,
}
impl InputHandle {
pub fn new() -> Self {
Self {
- mouse_pos: [0.0, 0.0].into(),
+ mouse_pos: Vector2::new(0.0, 0.0),
left_pressed: false,
+ middle_pressed: false,
right_pressed: false,
drag_point: None,
}
}
/// Get the unprojected mouse coordinates
- pub fn unproject(&self) -> Point2<f32> {
- self.mouse_pos.clone();
+ pub fn unproject(&self, vp: &Viewport) -> Vector2 {
+ // self.mouse_pos.clone() - vp.start().clone()
+
todo!()
}
}
impl EventHandler for InputHandle {
fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
- self.mouse_pos = mouse::position(&ctx);
+ self.mouse_pos = mouse::position(&ctx).into();
self.left_pressed = mouse::button_pressed(ctx, MouseButton::Left);
+ self.middle_pressed = mouse::button_pressed(ctx, MouseButton::Middle);
self.right_pressed = mouse::button_pressed(ctx, MouseButton::Right);
// Only set the drag_point once and unset when we release Left button
- if self.left_pressed && self.drag_point.is_none() {
+ if self.middle_pressed && self.drag_point.is_none() {
self.drag_point = Some(self.mouse_pos.clone());
- } else if !self.left_pressed {
+ } else if !self.middle_pressed {
self.drag_point = None;
}
diff --git a/games/rstnode/rst-client/src/main.rs b/games/rstnode/rst-client/src/main.rs
index aa86de26c952..a6ba4a59cdc1 100644
--- a/games/rstnode/rst-client/src/main.rs
+++ b/games/rstnode/rst-client/src/main.rs
@@ -14,6 +14,7 @@ mod input;
mod log;
mod settings;
mod state;
+mod viewport;
mod window;
#[allow(unused)]
@@ -36,7 +37,13 @@ fn main() {
// Load assets tree
let assets =
assets::load_tree(window.ctx(), &settings).unwrap_or_else(|e| fatal!("LoadError: {}!", e));
- let state = ClientState::new(settings, assets);
+ // Create the client state
+ let mut state = ClientState::new(settings, assets);
+
+ // Initialise the viewport first!
+ state.viewport().init(window.ctx());
+
+ // Window goes brrrr
window.run(state)
}
diff --git a/games/rstnode/rst-client/src/state.rs b/games/rstnode/rst-client/src/state.rs
index b1b5e89f3d13..d3b5bbcc3d7b 100644
--- a/games/rstnode/rst-client/src/state.rs
+++ b/games/rstnode/rst-client/src/state.rs
@@ -7,6 +7,7 @@ use crate::{
Renderer,
},
input::InputHandle,
+ viewport::Viewport,
GameSettings,
};
use ggez::{event::EventHandler, graphics, Context, GameResult};
@@ -17,6 +18,7 @@ pub struct ClientState {
assets: Assets,
settings: GameSettings,
input: InputHandle,
+ vp: Viewport,
// Game state
node: NodeRndr,
@@ -27,6 +29,7 @@ impl ClientState {
Self {
assets,
settings,
+ vp: Viewport::new(),
input: InputHandle::new(),
node: NodeRndr {
loc: Coordinates(512.0, 512.0),
@@ -49,6 +52,10 @@ impl ClientState {
}
}
+ pub fn viewport(&mut self) -> &mut Viewport {
+ &mut self.vp
+ }
+
pub fn assets(&self) -> &Assets {
&self.assets
}
@@ -56,7 +63,16 @@ impl ClientState {
impl EventHandler for ClientState {
fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
+ // TODO: get simulation updates
+
+ // Get new input state
self.input.update(ctx)?;
+
+ // Apply inputs to viewpoirt
+ self.vp.apply(ctx, &self.input)?;
+
+ // Update viewport
+ self.vp.update(ctx)?;
Ok(())
}
diff --git a/games/rstnode/rst-client/src/viewport.rs b/games/rstnode/rst-client/src/viewport.rs
new file mode 100644
index 000000000000..3f9e803e387b
--- /dev/null
+++ b/games/rstnode/rst-client/src/viewport.rs
@@ -0,0 +1,63 @@
+//! Viewport utilities
+
+use crate::{graphics::Vector2, input::InputHandle};
+use ggez::{
+ error::GameResult,
+ graphics::{self, Rect},
+ Context,
+};
+
+#[derive(Default)]
+pub struct Viewport {
+ start: Vector2,
+ prev_start: Vector2,
+ size: Vector2,
+}
+
+impl Viewport {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn start(&self) -> &Vector2 {
+ &self.start
+ }
+
+ /// Must be called at least once before calling
+ /// [`update`](Self::update)
+ pub fn init(&mut self, ctx: &mut Context) {
+ let Rect { x, y, w, h } = graphics::screen_coordinates(&ctx);
+ self.start = Vector2::new(x, y);
+ self.prev_start = self.start;
+ self.size = Vector2::new(w, h);
+ }
+
+ /// Update the game state with the curent viewport data
+ pub fn update(&self, ctx: &mut Context) -> GameResult<()> {
+ graphics::set_screen_coordinates(
+ ctx,
+ Rect {
+ x: self.start.x,
+ y: self.start.y,
+ w: self.size.x,
+ h: self.size.y,
+ },
+ )?;
+
+ Ok(())
+ }
+
+ /// Apply changes from the input handle to the viewport
+ pub fn apply(&mut self, _: &mut Context, input: &InputHandle) -> GameResult<()> {
+ if input.middle_pressed {
+ let drag = input.drag_point.as_ref().unwrap().clone();
+ let pos = input.mouse_pos.clone();
+ self.start = self.prev_start + (drag - pos);
+ debug!("Changing VP start: {}", self.start);
+ } else {
+ self.prev_start = self.start;
+ }
+
+ Ok(())
+ }
+}