Reworked UI sprites
parent
f7525901f5
commit
7d5b244492
|
@ -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] {
|
||||||
|
|
|
@ -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()],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue