Reworked UI sprites

master
Mark 2024-01-20 10:05:39 -08:00
parent f7525901f5
commit 7d5b244492
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
4 changed files with 179 additions and 96 deletions

View File

@ -1,42 +1,62 @@
use galactica_content::{Content, SystemObject, SystemObjectHandle}; use galactica_content::{Content, SystemObject, SystemObjectHandle};
use galactica_system::{data::ShipState, phys::PhysSimShipHandle}; use galactica_system::{data::ShipState, phys::PhysSimShipHandle};
use galactica_util::to_radians;
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 super::util::{SpriteRect, UiImage, UiTextArea}; use super::util::{SpriteRect, UiSprite, UiTextArea};
use crate::{vertexbuffer::types::UiInstance, PositionAnchor, RenderInput, RenderState}; use crate::{RenderInput, RenderState};
pub(super) struct Planet { pub(super) struct Planet {
// UI elements // UI elements
planet_desc: UiTextArea, planet_desc: UiTextArea,
planet_name: UiTextArea, planet_name: UiTextArea,
landscape: UiImage, sprite: UiSprite,
// Height of whole element,in logical pixels
size: f32,
/// 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>,
} }
// TODO: no scroll
// TODO: animate in/out // TODO: animate in/out
impl Planet { impl Planet {
pub fn new(ct: &Content, state: &mut RenderState) -> Self { pub fn new(ct: &Content, state: &mut RenderState) -> Self {
let size = 800.0; let mut sprite = UiSprite::new(
ct.get_sprite_handle("ui::planet"),
None,
SpriteRect {
pos: Point2::new(0.0, 0.0),
dim: Vector2::new(800.0, 800.0),
},
);
sprite.add_child_under(Box::new(UiSprite::new(
ct.get_sprite_handle("ui::landscape::test"),
Some(ct.get_sprite_handle("ui::landscapemask")),
SpriteRect {
pos: Point2::new(32.0, 75.0) / 512.0,
dim: Vector2::new(344.0, 173.0) / 512.0,
},
)));
sprite.add_child_under(Box::new(UiSprite::new(
ct.get_sprite_handle("ui::planet::button"),
None,
SpriteRect {
pos: Point2::new(375.0, 90.0) / 512.0,
dim: Vector2::new(113.569, 20.0) / 512.0,
},
)));
let s = Self { let s = Self {
// height of element in logical pixels // height of element in logical pixels
size,
current_object: None, current_object: None,
planet_desc: UiTextArea::new( planet_desc: UiTextArea::new(
state, state,
ct.get_sprite_handle("ui::planet"), ct.get_sprite_handle("ui::planet"),
Point2::new(0.0, 0.0), Point2::new(0.0, 0.0),
size, 800.0,
SpriteRect { SpriteRect {
pos: Point2::new(25.831, 284.883) / 512.0, pos: Point2::new(25.831, 284.883) / 512.0,
dim: Vector2::new(433.140, 97.220) / 512.0, dim: Vector2::new(433.140, 97.220) / 512.0,
@ -50,7 +70,7 @@ impl Planet {
state, state,
ct.get_sprite_handle("ui::planet"), ct.get_sprite_handle("ui::planet"),
Point2::new(0.0, 0.0), Point2::new(0.0, 0.0),
size, 800.0,
SpriteRect { SpriteRect {
pos: Point2::new(165.506, 82.0) / 512.0, pos: Point2::new(165.506, 82.0) / 512.0,
dim: Vector2::new(74.883, 17.0) / 512.0, dim: Vector2::new(74.883, 17.0) / 512.0,
@ -60,17 +80,9 @@ impl Planet {
Align::Center, Align::Center,
), ),
landscape: UiImage::new( // TODO: use both dimensions,
ct.get_sprite_handle("ui::planet"), // not just height
Point2::new(0.0, 0.0), sprite,
size,
ct.get_sprite_handle("ui::landscape::test"),
ct.get_sprite_handle("ui::landscapemask"),
SpriteRect {
pos: Point2::new(32.031, 75.587) / 512.0,
dim: Vector2::new(342.811, 171.402) / 512.0,
},
),
}; };
return s; return s;
@ -104,7 +116,7 @@ impl Planet {
.systemsim .systemsim
.get_ship(&PhysSimShipHandle(ship_handle)) .get_ship(&PhysSimShipHandle(ship_handle))
.unwrap(); .unwrap();
let planet_handle = match ship_data.data.get_state() { let planet_handle = match ship_data.get_data().get_state() {
ShipState::Landed { target } => *target, ShipState::Landed { target } => *target,
_ => unreachable!("tried to draw planet interface while not landed!"), _ => unreachable!("tried to draw planet interface while not landed!"),
}; };
@ -120,16 +132,7 @@ impl Planet {
} }
// Draw elements // Draw elements
self.landscape.push_to_buffer(state); self.sprite.push_to_buffer(input, state);
state.push_ui_buffer(UiInstance {
anchor: PositionAnchor::CC.to_int(),
position: [0.0, 0.0],
angle: to_radians(90.0),
size: self.size,
color: [1.0, 1.0, 1.0, 1.0],
sprite_index: input.ct.get_sprite_handle("ui::planet").get_index(),
mask_index: [0, 0],
});
} }
pub fn get_textarea(&self, _input: &RenderInput, state: &RenderState) -> [TextArea; 2] { pub fn get_textarea(&self, _input: &RenderInput, state: &RenderState) -> [TextArea; 2] {

View File

@ -1,60 +0,0 @@
use galactica_content::SpriteHandle;
use galactica_util::to_radians;
use nalgebra::{Point2, Vector2};
use super::SpriteRect;
use crate::{vertexbuffer::types::UiInstance, PositionAnchor, RenderState};
pub struct UiImage {
parent: SpriteHandle,
parent_position: Point2<f32>,
parent_size: f32,
inner: SpriteHandle,
mask: SpriteHandle,
rect: SpriteRect,
}
impl UiImage {
pub fn new(
parent: SpriteHandle,
parent_position: Point2<f32>,
parent_size: f32,
inner: SpriteHandle,
mask: SpriteHandle,
rect: SpriteRect,
) -> Self {
return Self {
parent,
parent_position,
parent_size,
inner,
mask,
rect,
};
}
/// Add this image to the gpu sprite buffer
pub fn push_to_buffer(&self, state: &mut RenderState) {
let h = self.parent_size;
let w = self.parent.aspect * h;
let zero = Point2::new(
self.parent_position.x - (w / 2.0),
self.parent_position.y + (h / 2.0),
);
let pos = zero + Vector2::new(self.rect.pos.x * w, -self.rect.pos.y * h);
let dim = Vector2::new(self.rect.dim.x * w, self.rect.dim.y * h);
state.push_ui_buffer(UiInstance {
anchor: PositionAnchor::CNw.to_int(),
position: pos.into(),
angle: to_radians(90.0),
size: dim.y,
color: [1.0, 1.0, 1.0, 1.0],
sprite_index: self.inner.get_index(),
mask_index: [1, self.mask.get_index()],
});
}
}

View File

@ -1,11 +1,13 @@
mod image; mod sprite;
mod textarea; mod textarea;
pub(super) use image::UiImage; pub(super) use sprite::UiSprite;
pub(super) use textarea::UiTextArea; pub(super) use textarea::UiTextArea;
use nalgebra::{Point2, Vector2}; use nalgebra::{Point2, Vector2};
use crate::{RenderInput, RenderState};
/// Represents a rectangular region inside a sprite. /// Represents a rectangular region inside a sprite.
pub(crate) struct SpriteRect { pub(crate) struct SpriteRect {
/// The position of the top-left corner of this rectangle, in fractional units. /// The position of the top-left corner of this rectangle, in fractional units.
@ -16,3 +18,13 @@ pub(crate) struct SpriteRect {
/// 1.0 will be as tall as the sprite, 0.5 will be half as tall /// 1.0 will be as tall as the sprite, 0.5 will be half as tall
pub dim: Vector2<f32>, pub dim: Vector2<f32>,
} }
pub(super) trait UiElement {
fn push_to_buffer_child(
&self,
input: &RenderInput,
state: &mut RenderState,
parent_pos: Point2<f32>,
parent_size: Vector2<f32>,
);
}

View File

@ -0,0 +1,128 @@
use galactica_content::SpriteHandle;
use galactica_util::to_radians;
use nalgebra::{Point2, Vector2};
use super::{SpriteRect, UiElement};
use crate::{vertexbuffer::types::UiInstance, PositionAnchor, RenderInput, RenderState};
pub struct UiSprite {
sprite: SpriteHandle,
mask: Option<SpriteHandle>,
rect: SpriteRect,
children_under: Vec<Box<dyn UiElement>>,
children_above: Vec<Box<dyn UiElement>>,
}
impl UiSprite {
pub fn new(sprite: SpriteHandle, mask: Option<SpriteHandle>, rect: SpriteRect) -> Self {
return Self {
sprite,
mask,
rect,
children_under: Vec::new(),
children_above: Vec::new(),
};
}
/// Add a child under this sprite
pub fn add_child_under(&mut self, child: Box<dyn UiElement>) {
self.children_under.push(child);
}
/// Add a child above this sprite
//pub fn add_child_above(&mut self, child: Box<dyn UiElement>) {
// self.children_above.push(child);
//}
/// Add this image to the gpu sprite buffer
pub fn push_to_buffer(&self, input: &RenderInput, state: &mut RenderState) {
let pos = Point2::new(self.rect.pos.x, self.rect.pos.y);
let dim = Vector2::new(self.rect.dim.y * self.sprite.aspect, self.rect.dim.y);
for c in &self.children_under {
c.push_to_buffer_child(input, state, pos, dim);
}
let sprite = input.ct.get_sprite(self.sprite);
let texture_a = sprite.get_section(sprite.default_section).frames[0]; // ANIMATE
state.push_ui_buffer(UiInstance {
anchor: PositionAnchor::CC.to_int(),
position: pos.into(),
angle: to_radians(90.0),
size: dim.y,
color: [1.0, 1.0, 1.0, 1.0],
texture_index: [texture_a, texture_a],
texture_fade: 1.0,
mask_index: self
.mask
.map(|x| {
let sprite = input.ct.get_sprite(x);
let texture_b = sprite.get_section(sprite.default_section).frames[0]; // ANIMATE
[1, texture_b]
})
.unwrap_or([0, 0]),
});
for c in &self.children_above {
c.push_to_buffer_child(input, state, pos, dim);
}
}
}
impl UiElement for UiSprite {
/// Add this image to the gpu sprite buffer,
/// as a child of another sprite
fn push_to_buffer_child(
&self,
input: &RenderInput,
state: &mut RenderState,
parent_pos: Point2<f32>,
parent_size: Vector2<f32>,
) {
let zero = Point2::new(
parent_pos.x - (parent_size.x / 2.0),
parent_pos.y + (parent_size.y / 2.0),
);
let pos = zero
+ Vector2::new(
self.rect.pos.x * parent_size.x,
-self.rect.pos.y * parent_size.y,
);
let dim = Vector2::new(
self.rect.dim.x * parent_size.x,
self.rect.dim.y * parent_size.y,
);
for c in &self.children_under {
c.push_to_buffer_child(input, state, pos, dim);
}
let sprite = input.ct.get_sprite(self.sprite);
let texture_a = sprite.get_section(sprite.default_section).frames[0]; // ANIMATE
state.push_ui_buffer(UiInstance {
anchor: PositionAnchor::CNw.to_int(),
position: pos.into(),
angle: to_radians(90.0),
size: dim.y,
color: [1.0, 1.0, 1.0, 1.0],
texture_index: [texture_a, texture_a],
texture_fade: 1.0,
mask_index: self
.mask
.map(|x| {
let sprite = input.ct.get_sprite(x);
let texture_b = sprite.get_section(sprite.default_section).frames[0]; // ANIMATE
[1, texture_b]
})
.unwrap_or([0, 0]),
});
for c in &self.children_above {
c.push_to_buffer_child(input, state, pos, dim);
}
}
}