Reworked UI sprites
parent
f7525901f5
commit
7d5b244492
|
@ -1,42 +1,62 @@
|
|||
use galactica_content::{Content, SystemObject, SystemObjectHandle};
|
||||
use galactica_system::{data::ShipState, phys::PhysSimShipHandle};
|
||||
use galactica_util::to_radians;
|
||||
use glyphon::{cosmic_text::Align, Attrs, Color, Metrics, TextArea, Weight};
|
||||
use nalgebra::{Point2, Vector2};
|
||||
|
||||
use super::util::{SpriteRect, UiImage, UiTextArea};
|
||||
use crate::{vertexbuffer::types::UiInstance, PositionAnchor, RenderInput, RenderState};
|
||||
use super::util::{SpriteRect, UiSprite, UiTextArea};
|
||||
use crate::{RenderInput, RenderState};
|
||||
|
||||
pub(super) struct Planet {
|
||||
// UI elements
|
||||
planet_desc: UiTextArea,
|
||||
planet_name: UiTextArea,
|
||||
landscape: UiImage,
|
||||
|
||||
// Height of whole element,in logical pixels
|
||||
size: f32,
|
||||
sprite: UiSprite,
|
||||
|
||||
/// What object we're displaying currently.
|
||||
/// Whenever this changes, we need to reflow text.
|
||||
current_object: Option<SystemObjectHandle>,
|
||||
}
|
||||
|
||||
// TODO: no scroll
|
||||
// TODO: animate in/out
|
||||
|
||||
impl Planet {
|
||||
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 {
|
||||
// height of element in logical pixels
|
||||
size,
|
||||
current_object: None,
|
||||
|
||||
planet_desc: UiTextArea::new(
|
||||
state,
|
||||
ct.get_sprite_handle("ui::planet"),
|
||||
Point2::new(0.0, 0.0),
|
||||
size,
|
||||
800.0,
|
||||
SpriteRect {
|
||||
pos: Point2::new(25.831, 284.883) / 512.0,
|
||||
dim: Vector2::new(433.140, 97.220) / 512.0,
|
||||
|
@ -50,7 +70,7 @@ impl Planet {
|
|||
state,
|
||||
ct.get_sprite_handle("ui::planet"),
|
||||
Point2::new(0.0, 0.0),
|
||||
size,
|
||||
800.0,
|
||||
SpriteRect {
|
||||
pos: Point2::new(165.506, 82.0) / 512.0,
|
||||
dim: Vector2::new(74.883, 17.0) / 512.0,
|
||||
|
@ -60,17 +80,9 @@ impl Planet {
|
|||
Align::Center,
|
||||
),
|
||||
|
||||
landscape: UiImage::new(
|
||||
ct.get_sprite_handle("ui::planet"),
|
||||
Point2::new(0.0, 0.0),
|
||||
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,
|
||||
},
|
||||
),
|
||||
// TODO: use both dimensions,
|
||||
// not just height
|
||||
sprite,
|
||||
};
|
||||
|
||||
return s;
|
||||
|
@ -104,7 +116,7 @@ impl Planet {
|
|||
.systemsim
|
||||
.get_ship(&PhysSimShipHandle(ship_handle))
|
||||
.unwrap();
|
||||
let planet_handle = match ship_data.data.get_state() {
|
||||
let planet_handle = match ship_data.get_data().get_state() {
|
||||
ShipState::Landed { target } => *target,
|
||||
_ => unreachable!("tried to draw planet interface while not landed!"),
|
||||
};
|
||||
|
@ -120,16 +132,7 @@ impl Planet {
|
|||
}
|
||||
|
||||
// Draw elements
|
||||
self.landscape.push_to_buffer(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],
|
||||
});
|
||||
self.sprite.push_to_buffer(input, state);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
pub(super) use image::UiImage;
|
||||
pub(super) use sprite::UiSprite;
|
||||
pub(super) use textarea::UiTextArea;
|
||||
|
||||
use nalgebra::{Point2, Vector2};
|
||||
|
||||
use crate::{RenderInput, RenderState};
|
||||
|
||||
/// Represents a rectangular region inside a sprite.
|
||||
pub(crate) struct SpriteRect {
|
||||
/// 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
|
||||
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