Compare commits

..

No commits in common. "1a2913041979640ab87edacedac77e34bf9cd9c4" and "570944cb774743885bd726db97687d42cc80cd00" have entirely different histories.

14 changed files with 76 additions and 424 deletions

View File

@ -1,9 +1,5 @@
# Specific projects # Specific projects
## Now:
- renderer scenes
- outfitter
## Small jobs ## Small jobs
- 🌟 Better planet desc formatting - 🌟 Better planet desc formatting
- Procedural suns - Procedural suns

View File

@ -16,7 +16,7 @@ pub struct InputStatus {
key_guns: bool, key_guns: bool,
key_leftclick: bool, key_leftclick: bool,
// One-shot keys (automatically released at the end of each frame) // One-shot keys (audomatically released at the end of each frame)
key_land: bool, key_land: bool,
v_scroll: f32, v_scroll: f32,
} }
@ -137,11 +137,6 @@ impl InputStatus {
self.key_guns self.key_guns
} }
/// Is the player pressing the left mouse button?
pub fn pressed_leftclick(&self) -> bool {
self.key_leftclick
}
/// Has the player pressed the "land" key? /// Has the player pressed the "land" key?
/// (One-shot, reset to false at the start of each frame) /// (One-shot, reset to false at the start of each frame)
pub fn pressed_land(&self) -> bool { pub fn pressed_land(&self) -> bool {

View File

@ -111,7 +111,7 @@ impl<'a> super::GPUState {
0..self.state.get_radialbar_counter(), 0..self.state.get_radialbar_counter(),
); );
let textareas = self.ui.get_textareas(input, &self.state); let textareas = self.ui.get_textareas_flying(input, &self.state);
self.state self.state
.text_renderer .text_renderer
.prepare( .prepare(
@ -219,7 +219,7 @@ impl<'a> super::GPUState {
0..self.state.get_radialbar_counter(), 0..self.state.get_radialbar_counter(),
); );
let textareas = self.ui.get_textareas(input, &self.state); let textareas = self.ui.get_textareas_landed(input, &self.state);
self.state self.state
.text_renderer .text_renderer
.prepare( .prepare(
@ -281,7 +281,6 @@ impl<'a> super::GPUState {
); );
self.state.frame_reset(); self.state.frame_reset();
self.ui.update_state(&input, &mut self.state);
match input match input
.phys_img .phys_img

View File

@ -1,121 +1,29 @@
use std::fmt::Debug;
use galactica_content::Content; use galactica_content::Content;
use galactica_system::{data::ShipState, phys::PhysSimShipHandle}; use galactica_system::{data::ShipState, phys::PhysSimShipHandle};
use glyphon::TextArea; use glyphon::TextArea;
use log::info;
use super::scenes::{FlyingScene, LandedScene, OutfitterScene}; use super::{fpsindicator::FpsIndicator, planet::Planet, radar::Radar, status::Status};
use crate::{RenderInput, RenderState}; use crate::{RenderInput, RenderState};
/// Output from a ui scene step
pub struct UiSceneStepResult {
/// If Some, switch to this scene
pub new_scene: Option<UiScenes>,
}
pub trait UiScene<'this>
where
Self: 'this,
{
/// Draw this scene
fn draw(&mut self, input: &RenderInput, state: &mut RenderState);
/// Update this scene's state for this frame.
/// Handles clicks, keys, etc.
fn step(&mut self, input: &RenderInput, state: &mut RenderState) -> UiSceneStepResult;
fn get_textareas(
&'this self,
v: &mut Vec<TextArea<'this>>,
input: &RenderInput,
state: &RenderState,
);
}
pub(super) enum UiScenes {
Landed(LandedScene),
Flying(FlyingScene),
Outfitter(OutfitterScene),
}
impl Debug for UiScenes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Flying(_) => write!(f, "UiScenes::Flying"),
Self::Landed(_) => write!(f, "UiScenes::Landed"),
Self::Outfitter(_) => write!(f, "UiScenes::Outfitter"),
}
}
}
impl UiScenes {
fn is_flying(&self) -> bool {
match self {
Self::Flying(_) => true,
_ => false,
}
}
fn is_landed(&self) -> bool {
match self {
Self::Landed(_) => true,
_ => false,
}
}
fn is_outfitter(&self) -> bool {
match self {
Self::Outfitter(_) => true,
_ => false,
}
}
}
impl<'a> UiScene<'a> for UiScenes {
fn draw(&mut self, input: &RenderInput, state: &mut RenderState) {
match self {
Self::Flying(s) => s.draw(input, state),
Self::Landed(s) => s.draw(input, state),
Self::Outfitter(s) => s.draw(input, state),
}
}
fn step(&mut self, input: &RenderInput, state: &mut RenderState) -> UiSceneStepResult {
match self {
Self::Flying(s) => s.step(input, state),
Self::Landed(s) => s.step(input, state),
Self::Outfitter(s) => s.step(input, state),
}
}
fn get_textareas(
&'a self,
v: &mut Vec<TextArea<'a>>,
input: &RenderInput,
state: &RenderState,
) {
match self {
Self::Flying(s) => s.get_textareas(v, input, state),
Self::Landed(s) => s.get_textareas(v, input, state),
Self::Outfitter(s) => s.get_textareas(v, input, state),
}
}
}
pub struct UiManager { pub struct UiManager {
current_scene: UiScenes, radar: Radar,
status: Status,
fps: FpsIndicator,
planet: Planet,
} }
impl UiManager { impl UiManager {
pub fn new(ct: &Content, state: &mut RenderState) -> Self { pub fn new(ct: &Content, state: &mut RenderState) -> Self {
Self { Self {
current_scene: UiScenes::Flying(FlyingScene::new(ct, state)), planet: Planet::new(ct, state),
radar: Radar::new(),
status: Status::new(),
fps: FpsIndicator::new(state),
} }
} }
// TODO: remove this. /// Draw all ui elements
pub fn update_state(&mut self, input: &RenderInput, state: &mut RenderState) { pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) {
let ship_handle = input.player.ship.unwrap(); let ship_handle = input.player.ship.unwrap();
let ship = &input let ship = &input
.phys_img .phys_img
@ -123,44 +31,41 @@ impl UiManager {
.unwrap() .unwrap()
.ship; .ship;
self.fps.update(input, state);
match ship.get_data().get_state() { match ship.get_data().get_state() {
ShipState::Collapsing ShipState::Collapsing
| ShipState::Dead | ShipState::Dead
| ShipState::Flying { .. } | ShipState::Flying { .. }
| ShipState::Landing { .. } | ShipState::Landing { .. }
| ShipState::UnLanding { .. } => { | ShipState::UnLanding { .. } => {
if !self.current_scene.is_flying() { self.radar.draw(input, state);
self.current_scene = UiScenes::Flying(FlyingScene::new(input.ct, state)); self.status.draw(input, state);
}
} }
ShipState::Landed { .. } => { ShipState::Landed { .. } => {
if !self.current_scene.is_landed() && !self.current_scene.is_outfitter() { self.planet.draw(input, state);
self.current_scene = UiScenes::Landed(LandedScene::new(input.ct, state))
} }
} }
} }
}
/// Draw all ui elements
pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) {
loop {
let r = self.current_scene.step(input, state);
if let Some(new_state) = r.new_scene {
info!("switching to {:?}", new_state);
self.current_scene = new_state;
} else {
break;
}
}
self.current_scene.draw(input, state);
}
/// Textareas to show while player is flying /// Textareas to show while player is flying
pub fn get_textareas(&self, input: &RenderInput, state: &RenderState) -> Vec<TextArea> { pub fn get_textareas_flying(
&self,
_input: &RenderInput,
_state: &RenderState,
) -> Vec<TextArea> {
let mut v = Vec::with_capacity(5); let mut v = Vec::with_capacity(5);
self.current_scene.get_textareas(&mut v, input, state); v.push(self.fps.get_textarea());
return v;
}
/// Textareas to show when player is landed
pub fn get_textareas_landed(&self, input: &RenderInput, state: &RenderState) -> Vec<TextArea> {
let mut v = Vec::with_capacity(5);
v.extend(self.planet.get_textarea(input, state));
return v; return v;
} }
} }

View File

@ -1,5 +1,8 @@
mod fpsindicator;
mod manager; mod manager;
mod scenes; mod planet;
mod radar;
mod status;
mod util; mod util;
pub use manager::UiManager; pub use manager::UiManager;

View File

@ -3,20 +3,13 @@ use galactica_system::{data::ShipState, phys::PhysSimShipHandle};
use glyphon::{cosmic_text::Align, Attrs, Color, Metrics, TextArea, Weight}; use glyphon::{cosmic_text::Align, Attrs, Color, Metrics, TextArea, Weight};
use nalgebra::{Point2, Vector2}; use nalgebra::{Point2, Vector2};
use crate::{ use super::util::{SpriteRect, UiSprite, UiTextArea};
ui::{ use crate::{RenderInput, RenderState};
manager::{UiScene, UiSceneStepResult, UiScenes},
util::{SpriteRect, UiSprite, UiTextArea},
},
RenderInput, RenderState,
};
use super::OutfitterScene; pub(super) struct Planet {
pub struct LandedScene {
// UI elements // UI elements
description: UiTextArea, planet_desc: UiTextArea,
title: UiTextArea, planet_name: UiTextArea,
frame: UiSprite, frame: UiSprite,
landscape: UiSprite, landscape: UiSprite,
button: UiSprite, button: UiSprite,
@ -24,13 +17,11 @@ pub struct LandedScene {
/// What object we're displaying currently. /// What object we're displaying currently.
/// Whenever this changes, we need to reflow text. /// Whenever this changes, we need to reflow text.
current_object: Option<SystemObjectHandle>, current_object: Option<SystemObjectHandle>,
/// True if we've caught a left click event.
/// Used for edge detection.
leftclick_down: bool,
} }
impl LandedScene { // TODO: animate in/out
impl Planet {
pub fn new(ct: &Content, state: &mut RenderState) -> Self { pub fn new(ct: &Content, state: &mut RenderState) -> Self {
let frame = UiSprite::from(ct, &ct.get_ui().landed_frame); let frame = UiSprite::from(ct, &ct.get_ui().landed_frame);
let button = UiSprite::from(ct, &ct.get_ui().landed_button); let button = UiSprite::from(ct, &ct.get_ui().landed_button);
@ -43,9 +34,8 @@ impl LandedScene {
let s = Self { let s = Self {
// height of element in logical pixels // height of element in logical pixels
current_object: None, current_object: None,
leftclick_down: false,
description: UiTextArea::new( planet_desc: UiTextArea::new(
ct, ct,
state, state,
frame.get_sprite(), frame.get_sprite(),
@ -60,7 +50,7 @@ impl LandedScene {
Align::Left, Align::Left,
), ),
title: UiTextArea::new( planet_name: UiTextArea::new(
ct, ct,
state, state,
frame.get_sprite(), frame.get_sprite(),
@ -82,9 +72,11 @@ impl LandedScene {
return s; return s;
} }
}
impl Planet {
fn reflow(&mut self, planet: &SystemObject, state: &mut RenderState) { fn reflow(&mut self, planet: &SystemObject, state: &mut RenderState) {
self.description.set_text( self.planet_desc.set_text(
state, state,
&planet.desc, &planet.desc,
Attrs::new() Attrs::new()
@ -92,7 +84,7 @@ impl LandedScene {
.family(glyphon::Family::SansSerif), .family(glyphon::Family::SansSerif),
); );
self.title.set_text( self.planet_name.set_text(
state, state,
&planet.name, &planet.name,
Attrs::new() Attrs::new()
@ -101,29 +93,8 @@ impl LandedScene {
); );
self.current_object = Some(planet.handle); self.current_object = Some(planet.handle);
} }
}
impl<'this> UiScene<'this> for LandedScene { pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) {
fn step(&mut self, input: &RenderInput, state: &mut RenderState) -> UiSceneStepResult {
let frame_rect = Some(self.frame.get_rect(input));
self.button.step(input, state, frame_rect);
self.landscape.step(input, state, frame_rect);
self.frame.step(input, state, None);
let mut new_scene = None;
if input.player.input.pressed_leftclick() && !self.leftclick_down {
self.leftclick_down = true;
if self.button.contains_mouse(input, state, frame_rect) {
new_scene = Some(UiScenes::Outfitter(OutfitterScene::new(input.ct, state)));
}
} else if !input.player.input.pressed_leftclick() {
self.leftclick_down = false;
}
return UiSceneStepResult { new_scene };
}
fn draw(&mut self, input: &RenderInput, state: &mut RenderState) {
// Get required data // Get required data
let ship_handle = input.player.ship.unwrap(); let ship_handle = input.player.ship.unwrap();
let ship_data = &input let ship_data = &input
@ -146,20 +117,24 @@ impl<'this> UiScene<'this> for LandedScene {
self.reflow(planet, state); self.reflow(planet, state);
} }
self.button
.step(input, state, Some(self.frame.get_rect(input)));
self.landscape
.step(input, state, Some(self.frame.get_rect(input)));
self.frame.step(input, state, None);
// Draw elements // Draw elements
let frame_rect = Some(self.frame.get_rect(input)); self.button
self.button.push_to_buffer(input, state, frame_rect); .push_to_buffer(input, state, Some(self.frame.get_rect(input)));
self.landscape.push_to_buffer(input, state, frame_rect); self.landscape
.push_to_buffer(input, state, Some(self.frame.get_rect(input)));
self.frame.push_to_buffer(input, state, None); self.frame.push_to_buffer(input, state, None);
} }
fn get_textareas( pub fn get_textarea(&self, input: &RenderInput, state: &RenderState) -> [TextArea; 2] {
&'this self, [
v: &mut Vec<TextArea<'this>>, self.planet_desc.get_textarea(input, state),
input: &RenderInput, self.planet_name.get_textarea(input, state),
state: &RenderState, ]
) {
v.push(self.description.get_textarea(input, state));
v.push(self.title.get_textarea(input, state));
} }
} }

View File

@ -1,6 +0,0 @@
mod fpsindicator;
mod radar;
mod scene;
mod status;
pub use scene::FlyingScene;

View File

@ -1,45 +0,0 @@
use galactica_content::Content;
use glyphon::TextArea;
use super::{fpsindicator::FpsIndicator, radar::Radar, status::Status};
use crate::{
ui::manager::{UiScene, UiSceneStepResult},
RenderInput, RenderState,
};
pub struct FlyingScene {
radar: Radar,
status: Status,
fps: FpsIndicator,
}
impl FlyingScene {
pub fn new(_ct: &Content, state: &mut RenderState) -> Self {
Self {
radar: Radar::new(),
status: Status::new(),
fps: FpsIndicator::new(state),
}
}
}
impl<'this> UiScene<'this> for FlyingScene {
fn step(&mut self, input: &RenderInput, state: &mut RenderState) -> UiSceneStepResult {
self.fps.update(input, state);
return UiSceneStepResult { new_scene: None };
}
fn draw(&mut self, input: &RenderInput, state: &mut RenderState) {
self.radar.draw(input, state);
self.status.draw(input, state);
}
fn get_textareas(
&'this self,
v: &mut Vec<TextArea<'this>>,
_input: &RenderInput,
_state: &RenderState,
) {
v.push(self.fps.get_textarea());
}
}

View File

@ -1,7 +0,0 @@
mod flying;
mod landed;
mod outfitter;
pub use flying::FlyingScene;
pub use landed::LandedScene;
pub use outfitter::OutfitterScene;

View File

@ -1,145 +0,0 @@
use galactica_content::{Content, SystemObject, SystemObjectHandle};
use galactica_system::{data::ShipState, phys::PhysSimShipHandle};
use glyphon::{cosmic_text::Align, Attrs, Color, Metrics, TextArea, Weight};
use nalgebra::{Point2, Vector2};
use crate::{
ui::{
manager::{UiScene, UiSceneStepResult, UiScenes},
util::{SpriteRect, UiSprite, UiTextArea},
},
RenderInput, RenderState,
};
use super::LandedScene;
pub struct OutfitterScene {
// UI elements
description: UiTextArea,
landscape: UiSprite,
button: UiSprite,
/// What object we're displaying currently.
/// Whenever this changes, we need to reflow text.
current_object: Option<SystemObjectHandle>,
/// True if we've caught a left click event.
/// Used for edge detection.
leftclick_down: bool,
}
impl OutfitterScene {
pub fn new(ct: &Content, state: &mut RenderState) -> Self {
let button = UiSprite::new(
ct,
ct.get_sprite_handle("ui::button"),
None,
SpriteRect {
pos: Point2::new(0.0, 0.0),
dim: Vector2::new(200.0, 200.0),
},
None,
None,
);
let landscape = UiSprite::from_with_sprite(
ct,
&ct.get_ui().landed_landscape,
ct.get_sprite_handle("ui::landscape::test"),
);
let s = Self {
// height of element in logical pixels
current_object: None,
leftclick_down: false,
description: UiTextArea::new(
ct,
state,
button.get_sprite(),
Point2::new(0.0, 0.0),
800.0,
SpriteRect {
pos: Point2::new(25.831, 284.883) / 512.0,
dim: Vector2::new(433.140, 97.220) / 512.0,
},
Metrics::new(16.0, 18.0),
Color::rgb(255, 255, 255),
Align::Left,
),
landscape,
button,
};
return s;
}
fn reflow(&mut self, planet: &SystemObject, state: &mut RenderState) {
self.description.set_text(
state,
&planet.desc,
Attrs::new()
.weight(Weight::NORMAL)
.family(glyphon::Family::SansSerif),
);
self.current_object = Some(planet.handle);
}
}
impl<'this> UiScene<'this> for OutfitterScene {
fn step(&mut self, input: &RenderInput, state: &mut RenderState) -> UiSceneStepResult {
self.button.step(input, state, None);
self.landscape.step(input, state, None);
let mut new_scene = None;
if input.player.input.pressed_leftclick() && !self.leftclick_down {
self.leftclick_down = true;
if self.button.contains_mouse(input, state, None) {
new_scene = Some(UiScenes::Landed(LandedScene::new(input.ct, state)));
}
} else if !input.player.input.pressed_leftclick() {
self.leftclick_down = false;
}
return UiSceneStepResult { new_scene };
}
fn draw(&mut self, input: &RenderInput, state: &mut RenderState) {
// Get required data
let ship_handle = input.player.ship.unwrap();
let ship_data = &input
.phys_img
.get_ship(&PhysSimShipHandle(ship_handle))
.unwrap()
.ship;
let planet_handle = match ship_data.get_data().get_state() {
ShipState::Landed { target } => *target,
_ => unreachable!("tried to draw planet interface while not landed!"),
};
let planet = input.ct.get_system_object(planet_handle);
// Reconfigure for new planet if necessary
if self
.current_object
.map(|x| x != planet_handle)
.unwrap_or(true)
{
self.reflow(planet, state);
}
// Draw elements
self.button.push_to_buffer(input, state, None);
self.landscape.push_to_buffer(input, state, None);
}
fn get_textareas(
&'this self,
v: &mut Vec<TextArea<'this>>,
input: &RenderInput,
state: &RenderState,
) {
v.push(self.description.get_textarea(input, state));
}
}

View File

@ -17,24 +17,6 @@ pub struct UiSprite {
} }
impl UiSprite { impl UiSprite {
pub fn new(
ct: &Content,
sprite: SpriteHandle,
mask: Option<SpriteHandle>,
rect: SpriteRect,
on_mouse_enter: Option<SectionEdge>,
on_mouse_leave: Option<SectionEdge>,
) -> Self {
return Self {
anim: SpriteAutomaton::new(ct, sprite),
mask,
rect,
has_mouse: false,
on_mouse_enter,
on_mouse_leave,
};
}
pub fn from(ct: &Content, ui: &UiSpriteConfig) -> Self { pub fn from(ct: &Content, ui: &UiSpriteConfig) -> Self {
if ui.sprite.is_none() { if ui.sprite.is_none() {
unreachable!("called `UiSprite.from()` on a UiSprite with a None sprite!") unreachable!("called `UiSprite.from()` on a UiSprite with a None sprite!")
@ -44,17 +26,17 @@ impl UiSprite {
} }
pub fn from_with_sprite(ct: &Content, ui: &UiSpriteConfig, sprite: SpriteHandle) -> Self { pub fn from_with_sprite(ct: &Content, ui: &UiSpriteConfig, sprite: SpriteHandle) -> Self {
Self::new( return Self {
ct, anim: SpriteAutomaton::new(ct, sprite),
sprite, mask: ui.mask,
ui.mask, rect: SpriteRect {
SpriteRect {
pos: *ui.rect.get_pos(), pos: *ui.rect.get_pos(),
dim: *ui.rect.get_dim(), dim: *ui.rect.get_dim(),
}, },
ui.on_mouse_enter, has_mouse: false,
ui.on_mouse_leave, on_mouse_enter: ui.on_mouse_enter,
) on_mouse_leave: ui.on_mouse_leave,
};
} }
pub fn step(&mut self, input: &RenderInput, state: &RenderState, parent: Option<SpriteRect>) { pub fn step(&mut self, input: &RenderInput, state: &RenderState, parent: Option<SpriteRect>) {