Compare commits
No commits in common. "cb68e9d3761cc274f9656f7f0503ae4b02879f1e" and "40ba0fbc0fa5a0e3a54ae3fccc0cab493a163008" have entirely different histories.
cb68e9d376
...
40ba0fbc0f
|
@ -93,15 +93,16 @@ file = "ui/landscape-mask.png"
|
||||||
|
|
||||||
[sprite."ui::planet::button"]
|
[sprite."ui::planet::button"]
|
||||||
start_at = "off:top"
|
start_at = "off:top"
|
||||||
|
random_start_frame = false
|
||||||
|
|
||||||
section.off.top = "stop"
|
section.off.top = "stop"
|
||||||
section.off.bot = "stop"
|
section.off.bot = "stop"
|
||||||
section.off.timing.duration = 0.5
|
section.off.timing.fps = 60
|
||||||
section.off.frames = ["ui/planet-button-off.png"]
|
section.off.frames = ["ui/planet-button-off.png"]
|
||||||
|
|
||||||
section.on.top = "stop"
|
section.on.top = "stop"
|
||||||
section.on.bot = "stop"
|
section.on.bot = "stop"
|
||||||
section.on.timing.duration = 0.5
|
section.on.timing.fps = 60
|
||||||
section.on.frames = ["ui/planet-button-on.png"]
|
section.on.frames = ["ui/planet-button-on.png"]
|
||||||
|
|
||||||
[sprite."effect::blaster"]
|
[sprite."effect::blaster"]
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
[ui.landed]
|
|
||||||
frame.sprite = "ui::planet"
|
|
||||||
frame.pos = [0.0, 0.0]
|
|
||||||
frame.dim = [800.0, 800.0]
|
|
||||||
|
|
||||||
landscape.mask = "ui::landscapemask"
|
|
||||||
landscape.pos = [32.0, 75.0]
|
|
||||||
landscape.dim = [344.0, 173.0]
|
|
||||||
landscape.loc_div = 512
|
|
||||||
|
|
||||||
button.sprite = "ui::planet::button"
|
|
||||||
button.pos = [356, 90]
|
|
||||||
button.dim = [113.569, 20]
|
|
||||||
button.loc_div = 512
|
|
||||||
button.on_mouse_enter.edge = "on:top"
|
|
||||||
button.on_mouse_enter.duration = 0.1
|
|
||||||
button.on_mouse_leave.edge = "off:top"
|
|
||||||
button.on_mouse_leave.duration = 0.1
|
|
|
@ -33,7 +33,6 @@ mod syntax {
|
||||||
use crate::{
|
use crate::{
|
||||||
config,
|
config,
|
||||||
part::{effect, faction, outfit, ship, sprite, system},
|
part::{effect, faction, outfit, ship, sprite, system},
|
||||||
ui,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -45,7 +44,6 @@ mod syntax {
|
||||||
pub faction: Option<HashMap<String, faction::syntax::Faction>>,
|
pub faction: Option<HashMap<String, faction::syntax::Faction>>,
|
||||||
pub effect: Option<HashMap<String, effect::syntax::Effect>>,
|
pub effect: Option<HashMap<String, effect::syntax::Effect>>,
|
||||||
pub config: Option<config::syntax::Config>,
|
pub config: Option<config::syntax::Config>,
|
||||||
pub ui: Option<ui::syntax::Ui>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_hashmap<K, V>(
|
fn merge_hashmap<K, V>(
|
||||||
|
@ -83,7 +81,6 @@ mod syntax {
|
||||||
faction: None,
|
faction: None,
|
||||||
effect: None,
|
effect: None,
|
||||||
config: None,
|
config: None,
|
||||||
ui: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +96,6 @@ mod syntax {
|
||||||
.with_context(|| "while merging factions")?;
|
.with_context(|| "while merging factions")?;
|
||||||
merge_hashmap(&mut self.effect, other.effect)
|
merge_hashmap(&mut self.effect, other.effect)
|
||||||
.with_context(|| "while merging effects")?;
|
.with_context(|| "while merging effects")?;
|
||||||
|
|
||||||
if self.config.is_some() {
|
if self.config.is_some() {
|
||||||
if other.config.is_some() {
|
if other.config.is_some() {
|
||||||
bail!("invalid content dir, multiple config tables")
|
bail!("invalid content dir, multiple config tables")
|
||||||
|
@ -107,15 +103,6 @@ mod syntax {
|
||||||
} else {
|
} else {
|
||||||
self.config = other.config;
|
self.config = other.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ui.is_some() {
|
|
||||||
if other.ui.is_some() {
|
|
||||||
bail!("invalid content dir, multiple ui tables")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.ui = other.ui;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +159,6 @@ pub struct Content {
|
||||||
factions: Vec<Faction>,
|
factions: Vec<Faction>,
|
||||||
effects: Vec<Effect>,
|
effects: Vec<Effect>,
|
||||||
config: Config,
|
config: Config,
|
||||||
ui: Option<Ui>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loading methods
|
// Loading methods
|
||||||
|
@ -241,7 +227,6 @@ impl Content {
|
||||||
factions: Vec::new(),
|
factions: Vec::new(),
|
||||||
effects: Vec::new(),
|
effects: Vec::new(),
|
||||||
sprite_index: HashMap::new(),
|
sprite_index: HashMap::new(),
|
||||||
ui: None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: enforce sprite and image limits
|
// TODO: enforce sprite and image limits
|
||||||
|
@ -254,7 +239,6 @@ impl Content {
|
||||||
&mut content,
|
&mut content,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if root.effect.is_some() {
|
if root.effect.is_some() {
|
||||||
part::effect::Effect::build(
|
part::effect::Effect::build(
|
||||||
root.effect.take().unwrap(),
|
root.effect.take().unwrap(),
|
||||||
|
@ -263,10 +247,6 @@ impl Content {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if root.ui.is_some() {
|
|
||||||
part::ui::Ui::build(root.ui.take().unwrap(), &mut build_context, &mut content)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Order below this line does not matter
|
// Order below this line does not matter
|
||||||
if root.ship.is_some() {
|
if root.ship.is_some() {
|
||||||
part::ship::Ship::build(root.ship.take().unwrap(), &mut build_context, &mut content)?;
|
part::ship::Ship::build(root.ship.take().unwrap(), &mut build_context, &mut content)?;
|
||||||
|
@ -373,9 +353,4 @@ impl Content {
|
||||||
pub fn get_config(&self) -> &Config {
|
pub fn get_config(&self) -> &Config {
|
||||||
return &self.config;
|
return &self.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get ui configuration
|
|
||||||
pub fn get_ui(&self) -> &Ui {
|
|
||||||
return self.ui.as_ref().unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ pub(crate) mod outfitspace;
|
||||||
pub(crate) mod ship;
|
pub(crate) mod ship;
|
||||||
pub(crate) mod sprite;
|
pub(crate) mod sprite;
|
||||||
pub(crate) mod system;
|
pub(crate) mod system;
|
||||||
pub(crate) mod ui;
|
|
||||||
|
|
||||||
pub use config::Config;
|
pub use config::Config;
|
||||||
pub use effect::*;
|
pub use effect::*;
|
||||||
|
@ -21,4 +20,3 @@ pub use ship::{
|
||||||
};
|
};
|
||||||
pub use sprite::*;
|
pub use sprite::*;
|
||||||
pub use system::{System, SystemObject};
|
pub use system::{System, SystemObject};
|
||||||
pub use ui::*;
|
|
||||||
|
|
|
@ -1,250 +0,0 @@
|
||||||
use anyhow::{Context, Result};
|
|
||||||
use nalgebra::{Point2, Vector2};
|
|
||||||
|
|
||||||
use crate::{handle::SpriteHandle, Content, ContentBuildContext, SectionEdge};
|
|
||||||
|
|
||||||
pub(crate) mod syntax {
|
|
||||||
use crate::{sprite::syntax::SectionEdge, Content, ContentBuildContext};
|
|
||||||
use anyhow::{bail, Context, Result};
|
|
||||||
use nalgebra::{Point2, Vector2};
|
|
||||||
use serde::Deserialize;
|
|
||||||
// Raw serde syntax structs.
|
|
||||||
// These are never seen by code outside this crate.
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct Ui {
|
|
||||||
pub landed: UiLanded,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct UiLanded {
|
|
||||||
pub frame: UiSprite,
|
|
||||||
pub landscape: UiSprite,
|
|
||||||
pub button: UiSprite,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct UiSprite {
|
|
||||||
pub sprite: Option<String>,
|
|
||||||
pub pos: [f32; 2],
|
|
||||||
pub dim: [f32; 2],
|
|
||||||
pub loc_div: Option<f32>,
|
|
||||||
pub mask: Option<String>,
|
|
||||||
pub on_mouse_enter: Option<EdgeSpec>,
|
|
||||||
pub on_mouse_leave: Option<EdgeSpec>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct EdgeSpec {
|
|
||||||
pub edge: SectionEdge,
|
|
||||||
pub duration: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UiSprite {
|
|
||||||
pub fn build(
|
|
||||||
self,
|
|
||||||
build_context: &ContentBuildContext,
|
|
||||||
ct: &Content,
|
|
||||||
|
|
||||||
// If true, this ui sprite will be positioned relative to another
|
|
||||||
is_child: bool,
|
|
||||||
|
|
||||||
// If true, fail if self.sprite is missing.
|
|
||||||
// If false, fail if self.sprite exists.
|
|
||||||
// This is false for sprites that may change---for example, planet landscapes
|
|
||||||
should_have_sprite: bool,
|
|
||||||
) -> Result<super::UiSpriteConfig> {
|
|
||||||
let sprite = {
|
|
||||||
if should_have_sprite {
|
|
||||||
if self.sprite.is_none() {
|
|
||||||
bail!("no sprite given, but expected a value")
|
|
||||||
}
|
|
||||||
match ct.sprite_index.get(self.sprite.as_ref().unwrap()) {
|
|
||||||
None => bail!("ui sprite `{}` doesn't exist", self.sprite.unwrap()),
|
|
||||||
Some(t) => Some(*t),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if self.sprite.is_some() {
|
|
||||||
bail!("got a sprite, but didn't expect one")
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mask = if let Some(mask) = self.mask {
|
|
||||||
Some(match ct.sprite_index.get(&mask) {
|
|
||||||
None => bail!("mask `{}` doesn't exist", mask),
|
|
||||||
Some(t) => *t,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let on_mouse_enter = {
|
|
||||||
if let Some(x) = self.on_mouse_enter {
|
|
||||||
if sprite.is_none() {
|
|
||||||
bail!("got `on_mouse_enter` on a ui element with no fixed sprite")
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(
|
|
||||||
x.edge
|
|
||||||
.resolve_as_edge(sprite.unwrap(), build_context, x.duration)
|
|
||||||
.with_context(|| format!("failed to resolve mouse enter edge"))?,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let on_mouse_leave = {
|
|
||||||
if let Some(x) = self.on_mouse_leave {
|
|
||||||
if sprite.is_none() {
|
|
||||||
bail!("got `on_mouse_leave` on a ui element with no fixed sprite")
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(
|
|
||||||
x.edge
|
|
||||||
.resolve_as_edge(sprite.unwrap(), build_context, x.duration)
|
|
||||||
.with_context(|| format!("failed to resolve mouse leave edge"))?,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let d = self.loc_div.unwrap_or(1.0);
|
|
||||||
|
|
||||||
let rect = {
|
|
||||||
if is_child {
|
|
||||||
super::UiSpriteRect::Relative {
|
|
||||||
pos: Point2::new(self.pos[0], self.pos[1]) / d,
|
|
||||||
dim: Vector2::new(self.dim[0], self.dim[1]) / d,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super::UiSpriteRect::Absolute {
|
|
||||||
pos: Point2::new(self.pos[0], self.pos[1]) / d,
|
|
||||||
dim: Vector2::new(self.dim[0], self.dim[1]) / d,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return Ok(super::UiSpriteConfig {
|
|
||||||
sprite,
|
|
||||||
mask,
|
|
||||||
on_mouse_enter,
|
|
||||||
on_mouse_leave,
|
|
||||||
rect,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// UI Configuration
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Ui {
|
|
||||||
/// Landed interface frame
|
|
||||||
pub landed_frame: UiSpriteConfig,
|
|
||||||
|
|
||||||
/// Landed interface image
|
|
||||||
pub landed_landscape: UiSpriteConfig,
|
|
||||||
|
|
||||||
/// Test button
|
|
||||||
pub landed_button: UiSpriteConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A UI sprite's position
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum UiSpriteRect {
|
|
||||||
/// Positioning relative to a parent sprite
|
|
||||||
Relative {
|
|
||||||
// Note that both pos and dim include transparent pixels,
|
|
||||||
// of this sprite AND its parent.
|
|
||||||
|
|
||||||
// We use the top left corner here because that's how inkscape
|
|
||||||
// positions its objects. This makes it very easy to compute position.
|
|
||||||
// TODO: maybe add anchors here too?
|
|
||||||
/// The position of this sprite's northeast corner, relative to its parent's NE corner.
|
|
||||||
/// Positive X is right, positive Y is down.
|
|
||||||
pos: Point2<f32>,
|
|
||||||
|
|
||||||
/// This sprite's w and h, as a fraction of the parent's width and height.
|
|
||||||
dim: Vector2<f32>,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Absolute positioning
|
|
||||||
Absolute {
|
|
||||||
/// The position of the center of this sprite, in logical pixels,
|
|
||||||
/// with 0, 0 at the center of the screen
|
|
||||||
pos: Point2<f32>,
|
|
||||||
|
|
||||||
/// This sprite's w and h, in logical pixels.
|
|
||||||
dim: Vector2<f32>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UiSpriteRect {
|
|
||||||
/// Get this rectangle's position
|
|
||||||
pub fn get_pos(&self) -> &Point2<f32> {
|
|
||||||
match self {
|
|
||||||
Self::Relative { pos, .. } => pos,
|
|
||||||
Self::Absolute { pos, .. } => pos,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get this rectangle's dimensions
|
|
||||||
pub fn get_dim(&self) -> &Vector2<f32> {
|
|
||||||
match self {
|
|
||||||
Self::Relative { dim, .. } => dim,
|
|
||||||
Self::Absolute { dim, .. } => dim,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A single UI sprite instance
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct UiSpriteConfig {
|
|
||||||
/// The sprite to show
|
|
||||||
pub sprite: Option<SpriteHandle>,
|
|
||||||
|
|
||||||
/// The mask to use
|
|
||||||
pub mask: Option<SpriteHandle>,
|
|
||||||
|
|
||||||
/// This sprite's position and size
|
|
||||||
pub rect: UiSpriteRect,
|
|
||||||
|
|
||||||
/// Animation edge to take when mouse enters this sprite
|
|
||||||
pub on_mouse_enter: Option<SectionEdge>,
|
|
||||||
|
|
||||||
/// Animation edge to take when mouse leaves this sprite
|
|
||||||
pub on_mouse_leave: Option<SectionEdge>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::Build for Ui {
|
|
||||||
type InputSyntaxType = syntax::Ui;
|
|
||||||
|
|
||||||
fn build(
|
|
||||||
ui: Self::InputSyntaxType,
|
|
||||||
build_context: &mut ContentBuildContext,
|
|
||||||
ct: &mut Content,
|
|
||||||
) -> Result<()> {
|
|
||||||
ct.ui = Some(Ui {
|
|
||||||
landed_frame: ui
|
|
||||||
.landed
|
|
||||||
.frame
|
|
||||||
.build(build_context, ct, false, true)
|
|
||||||
.with_context(|| format!("in ui config (frame)"))?,
|
|
||||||
landed_landscape: ui
|
|
||||||
.landed
|
|
||||||
.landscape
|
|
||||||
.build(build_context, ct, true, false)
|
|
||||||
.with_context(|| format!("in ui config (image)"))?,
|
|
||||||
landed_button: ui
|
|
||||||
.landed
|
|
||||||
.button
|
|
||||||
.build(build_context, ct, true, true)
|
|
||||||
.with_context(|| format!("in ui config (button)"))?,
|
|
||||||
});
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -126,12 +126,7 @@ impl SpriteAutomaton {
|
||||||
fn take_edge(&mut self, ct: &Content, e: SectionEdge) {
|
fn take_edge(&mut self, ct: &Content, e: SectionEdge) {
|
||||||
let sprite = ct.get_sprite(self.sprite);
|
let sprite = ct.get_sprite(self.sprite);
|
||||||
let current_section = sprite.get_section(self.current_section);
|
let current_section = sprite.get_section(self.current_section);
|
||||||
|
let last_direction = self.current_direction;
|
||||||
let last = match self.current_direction {
|
|
||||||
AnimDirection::Stop => self.next_texture,
|
|
||||||
AnimDirection::Down => self.next_texture,
|
|
||||||
AnimDirection::Up => self.last_texture,
|
|
||||||
};
|
|
||||||
|
|
||||||
match e {
|
match e {
|
||||||
SectionEdge::Stop => {
|
SectionEdge::Stop => {
|
||||||
|
@ -203,6 +198,12 @@ impl SpriteAutomaton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let last = match last_direction {
|
||||||
|
AnimDirection::Stop => self.last_texture,
|
||||||
|
AnimDirection::Down => self.next_texture,
|
||||||
|
AnimDirection::Up => self.last_texture,
|
||||||
|
};
|
||||||
|
|
||||||
match self.current_direction {
|
match self.current_direction {
|
||||||
AnimDirection::Stop => {
|
AnimDirection::Stop => {
|
||||||
let current_section = sprite.get_section(self.current_section);
|
let current_section = sprite.get_section(self.current_section);
|
||||||
|
|
|
@ -21,7 +21,6 @@ use nalgebra::Vector2;
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
time::Instant,
|
|
||||||
};
|
};
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{Event, KeyboardInput, WindowEvent},
|
event::{Event, KeyboardInput, WindowEvent},
|
||||||
|
@ -133,7 +132,6 @@ fn try_main() -> Result<()> {
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut phys_img = PhysImage::new();
|
let mut phys_img = PhysImage::new();
|
||||||
let mut last_run = Instant::now();
|
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
match event {
|
match event {
|
||||||
|
@ -145,11 +143,9 @@ fn try_main() -> Result<()> {
|
||||||
ct: &content,
|
ct: &content,
|
||||||
phys_img: &phys_img,
|
phys_img: &phys_img,
|
||||||
player: &player,
|
player: &player,
|
||||||
time_since_last_run: last_run.elapsed().as_secs_f32(),
|
|
||||||
current_system: SystemHandle { index: 0 },
|
current_system: SystemHandle { index: 0 },
|
||||||
timing: game.get_timing().clone(),
|
timing: game.get_timing().clone(),
|
||||||
};
|
};
|
||||||
last_run = Instant::now();
|
|
||||||
|
|
||||||
match gpu.render(render_input) {
|
match gpu.render(render_input) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
|
|
|
@ -112,11 +112,6 @@ impl InputStatus {
|
||||||
self.v_scroll
|
self.v_scroll
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current mouse position
|
|
||||||
pub fn get_mouse_pos(&self) -> PhysicalPosition<f32> {
|
|
||||||
self.mouse_position
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is the player pressing the "turn left" key?
|
/// Is the player pressing the "turn left" key?
|
||||||
pub fn pressed_left(&self) -> bool {
|
pub fn pressed_left(&self) -> bool {
|
||||||
self.key_left
|
self.key_left
|
||||||
|
|
|
@ -18,15 +18,11 @@ struct VertexInput {
|
||||||
|
|
||||||
struct VertexOutput {
|
struct VertexOutput {
|
||||||
@builtin(position) position: vec4<f32>,
|
@builtin(position) position: vec4<f32>,
|
||||||
@location(0) tween: f32,
|
@location(0) texture_coords: vec2<f32>,
|
||||||
@location(1) texture_index_a: u32,
|
@location(1) texture_index: u32,
|
||||||
@location(2) texture_coords_a: vec2<f32>,
|
@location(2) mask_coords: vec2<f32>,
|
||||||
@location(3) texture_index_b: u32,
|
@location(3) mask_index: vec2<u32>,
|
||||||
@location(4) texture_coords_b: vec2<f32>,
|
@location(4) color_transform: vec4<f32>,
|
||||||
@location(5) color: vec4<f32>,
|
|
||||||
|
|
||||||
@location(6) mask_coords: vec2<f32>,
|
|
||||||
@location(7) mask_index: vec2<u32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@group(0) @binding(0)
|
@group(0) @binding(0)
|
||||||
|
@ -84,67 +80,31 @@ fn vertex_main(
|
||||||
vertex: VertexInput,
|
vertex: VertexInput,
|
||||||
instance: InstanceInput,
|
instance: InstanceInput,
|
||||||
) -> VertexOutput {
|
) -> VertexOutput {
|
||||||
var out: VertexOutput;
|
|
||||||
|
|
||||||
// TODO: this will break if we try to use texture 0.
|
// TODO: this will break if we try to use texture 0.
|
||||||
// implement animations for ui sprites & fix that here.
|
// implement animations for ui sprites & fix that here.
|
||||||
|
|
||||||
// Pick texture size by the size of the visible texture
|
let pos = transform_vertex(
|
||||||
// (texture index 0 is special, it's the "hidden" texture)
|
|
||||||
if instance.texture_index.x == 0u && instance.texture_index.y == 0u {
|
|
||||||
out.position = vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
|
||||||
} else if instance.texture_index.x == 0u {
|
|
||||||
out.position = transform_vertex(
|
|
||||||
instance,
|
|
||||||
vertex.position,
|
|
||||||
instance.texture_index.y,
|
|
||||||
);
|
|
||||||
} else if instance.texture_index.y == 0u {
|
|
||||||
out.position = transform_vertex(
|
|
||||||
instance,
|
instance,
|
||||||
vertex.position,
|
vertex.position,
|
||||||
instance.texture_index.x,
|
instance.texture_index.x,
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
out.position = transform_vertex(
|
|
||||||
instance,
|
|
||||||
vertex.position,
|
|
||||||
instance.texture_index.x,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
out.color = instance.color_transform;
|
var out: VertexOutput;
|
||||||
out.tween = instance.texture_fade;
|
out.position = pos;
|
||||||
|
out.color_transform = instance.color_transform;
|
||||||
|
|
||||||
// Texture 0 is special, it's the empty texture
|
|
||||||
if instance.texture_index.x == 0u {
|
// TODO: function to get texture from sprite
|
||||||
out.texture_index_a = 0u;
|
// Pick texture frame
|
||||||
out.texture_coords_a = vec2(0.0, 0.0);
|
|
||||||
} else {
|
|
||||||
let t = global_atlas[instance.texture_index.x];
|
let t = global_atlas[instance.texture_index.x];
|
||||||
out.texture_index_a = t.atlas_texture;
|
out.texture_index = u32(t.atlas_texture);
|
||||||
out.texture_coords_a = vec2(t.xpos, t.ypos);
|
out.texture_coords = vec2(t.xpos, t.ypos);
|
||||||
if vertex.texture_coords.x == 1.0 {
|
if vertex.texture_coords.x == 1.0 {
|
||||||
out.texture_coords_a = out.texture_coords_a + vec2(t.width, 0.0);
|
out.texture_coords = vec2(out.texture_coords.x + t.width, out.texture_coords.y);
|
||||||
}
|
}
|
||||||
if vertex.texture_coords.y == 1.0 {
|
if vertex.texture_coords.y == 1.0 {
|
||||||
out.texture_coords_a = out.texture_coords_a + vec2(0.0, t.height);
|
out.texture_coords = vec2(out.texture_coords.x, out.texture_coords.y + t.height);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if instance.texture_index.y == 0u {
|
|
||||||
out.texture_index_b = u32(0u);
|
|
||||||
out.texture_coords_b = vec2(0.0, 0.0);
|
|
||||||
} else {
|
|
||||||
let b = global_atlas[instance.texture_index.y];
|
|
||||||
out.texture_index_b = u32(b.atlas_texture);
|
|
||||||
out.texture_coords_b = vec2(b.xpos, b.ypos);
|
|
||||||
if vertex.texture_coords.x == 1.0 {
|
|
||||||
out.texture_coords_b = out.texture_coords_b + vec2(b.width, 0.0);
|
|
||||||
}
|
|
||||||
if vertex.texture_coords.y == 1.0 {
|
|
||||||
out.texture_coords_b = out.texture_coords_b + vec2(0.0, b.height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick mask image if mask is enabled
|
// Pick mask image if mask is enabled
|
||||||
|
@ -182,40 +142,12 @@ fn fragment_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
).a;
|
).a;
|
||||||
}
|
}
|
||||||
|
|
||||||
var texture_a: vec4<f32> = vec4(0.0, 0.0, 0.0, 0.0);
|
var color: vec4<f32> = textureSampleLevel(
|
||||||
if !(
|
texture_array[in.texture_index],
|
||||||
(in.texture_index_a == 0u) &&
|
|
||||||
(in.texture_coords_a.x == 0.0) &&
|
|
||||||
(in.texture_coords_a.y == 0.0)
|
|
||||||
) {
|
|
||||||
texture_a = textureSampleLevel(
|
|
||||||
texture_array[in.texture_index_a],
|
|
||||||
sampler_array[0],
|
sampler_array[0],
|
||||||
in.texture_coords_a,
|
in.texture_coords,
|
||||||
0.0
|
0.0
|
||||||
).rgba;
|
).rgba * in.color_transform;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var texture_b: vec4<f32> = vec4(0.0, 0.0, 0.0, 0.0);
|
|
||||||
if !(
|
|
||||||
(in.texture_index_b == 0u) &&
|
|
||||||
(in.texture_coords_b.x == 0.0) &&
|
|
||||||
(in.texture_coords_b.y == 0.0)
|
|
||||||
) {
|
|
||||||
texture_b = textureSampleLevel(
|
|
||||||
texture_array[in.texture_index_b],
|
|
||||||
sampler_array[0],
|
|
||||||
in.texture_coords_b,
|
|
||||||
0.0
|
|
||||||
).rgba;
|
|
||||||
}
|
|
||||||
|
|
||||||
var color: vec4<f32> = mix(
|
|
||||||
texture_a,
|
|
||||||
texture_b,
|
|
||||||
in.tween
|
|
||||||
) * in.color;
|
|
||||||
|
|
||||||
// Apply mask and discard fully transparent pixels
|
// Apply mask and discard fully transparent pixels
|
||||||
color = vec4(color.rgb, color.a *mask);
|
color = vec4(color.rgb, color.a *mask);
|
||||||
|
|
|
@ -25,9 +25,6 @@ pub struct RenderInput<'a> {
|
||||||
/// The current time, in seconds
|
/// The current time, in seconds
|
||||||
pub current_time: f32,
|
pub current_time: f32,
|
||||||
|
|
||||||
/// The amount of time that has passed since the last frame was drawn
|
|
||||||
pub time_since_last_run: f32,
|
|
||||||
|
|
||||||
/// Game content
|
/// Game content
|
||||||
pub ct: &'a Content,
|
pub ct: &'a Content,
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,7 @@ pub(super) struct Planet {
|
||||||
// UI elements
|
// UI elements
|
||||||
planet_desc: UiTextArea,
|
planet_desc: UiTextArea,
|
||||||
planet_name: UiTextArea,
|
planet_name: UiTextArea,
|
||||||
frame: UiSprite,
|
sprite: UiSprite,
|
||||||
landscape: UiSprite,
|
|
||||||
button: UiSprite,
|
|
||||||
|
|
||||||
/// 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.
|
||||||
|
@ -23,14 +21,33 @@ pub(super) struct Planet {
|
||||||
|
|
||||||
impl Planet {
|
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 mut sprite = UiSprite::new(
|
||||||
let button = UiSprite::from(ct, &ct.get_ui().landed_button);
|
ct.get_sprite_handle("ui::planet"),
|
||||||
let landscape = UiSprite::from_with_sprite(
|
None,
|
||||||
ct,
|
SpriteRect {
|
||||||
&ct.get_ui().landed_landscape,
|
pos: Point2::new(0.0, 0.0),
|
||||||
ct.get_sprite_handle("ui::landscape::test"),
|
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
|
||||||
current_object: None,
|
current_object: None,
|
||||||
|
@ -38,9 +55,9 @@ impl Planet {
|
||||||
planet_desc: UiTextArea::new(
|
planet_desc: UiTextArea::new(
|
||||||
ct,
|
ct,
|
||||||
state,
|
state,
|
||||||
frame.get_sprite(),
|
ct.get_sprite_handle("ui::planet"),
|
||||||
Point2::new(0.0, 0.0),
|
Point2::new(0.0, 0.0),
|
||||||
frame.get_height(),
|
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,
|
||||||
|
@ -53,9 +70,9 @@ impl Planet {
|
||||||
planet_name: UiTextArea::new(
|
planet_name: UiTextArea::new(
|
||||||
ct,
|
ct,
|
||||||
state,
|
state,
|
||||||
frame.get_sprite(),
|
ct.get_sprite_handle("ui::planet"),
|
||||||
Point2::new(0.0, 0.0),
|
Point2::new(0.0, 0.0),
|
||||||
frame.get_height(),
|
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,
|
||||||
|
@ -65,9 +82,9 @@ impl Planet {
|
||||||
Align::Center,
|
Align::Center,
|
||||||
),
|
),
|
||||||
|
|
||||||
frame,
|
// TODO: use both dimensions,
|
||||||
landscape,
|
// not just height
|
||||||
button,
|
sprite,
|
||||||
};
|
};
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
@ -117,16 +134,8 @@ impl Planet {
|
||||||
self.reflow(planet, state);
|
self.reflow(planet, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.button.step(input, state);
|
|
||||||
self.landscape.step(input, state);
|
|
||||||
self.frame.step(input, state);
|
|
||||||
|
|
||||||
// Draw elements
|
// Draw elements
|
||||||
self.button
|
self.sprite.push_to_buffer(input, state);
|
||||||
.push_to_buffer(input, state, Some(self.frame.get_rect(input)));
|
|
||||||
self.landscape
|
|
||||||
.push_to_buffer(input, state, Some(self.frame.get_rect(input)));
|
|
||||||
self.frame.push_to_buffer(input, state, None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_textarea(&self, input: &RenderInput, state: &RenderState) -> [TextArea; 2] {
|
pub fn get_textarea(&self, input: &RenderInput, state: &RenderState) -> [TextArea; 2] {
|
||||||
|
|
|
@ -9,7 +9,6 @@ use nalgebra::{Point2, Vector2};
|
||||||
use crate::{RenderInput, RenderState};
|
use crate::{RenderInput, RenderState};
|
||||||
|
|
||||||
/// Represents a rectangular region inside a sprite.
|
/// Represents a rectangular region inside a sprite.
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
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.
|
||||||
/// (0.0 is left edge of sprite, 1.0 is right edge)
|
/// (0.0 is left edge of sprite, 1.0 is right edge)
|
||||||
|
@ -20,18 +19,6 @@ pub(crate) struct SpriteRect {
|
||||||
pub dim: Vector2<f32>,
|
pub dim: Vector2<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpriteRect {
|
|
||||||
/// Northeast corner of this rect
|
|
||||||
pub fn ne_corner(&self) -> Point2<f32> {
|
|
||||||
self.pos + Vector2::new(-self.dim.x, self.dim.y) / 2.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Southwest corner of this rect
|
|
||||||
pub fn sw_corner(&self) -> Point2<f32> {
|
|
||||||
self.pos + Vector2::new(self.dim.x, -self.dim.y) / 2.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) trait UiElement {
|
pub(super) trait UiElement {
|
||||||
fn push_to_buffer_child(
|
fn push_to_buffer_child(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -1,145 +1,63 @@
|
||||||
use galactica_content::{Content, SectionEdge, SpriteAutomaton, SpriteHandle, UiSpriteConfig};
|
use galactica_content::SpriteHandle;
|
||||||
use galactica_util::to_radians;
|
use galactica_util::to_radians;
|
||||||
use nalgebra::{Point2, Vector2};
|
use nalgebra::{Point2, Vector2};
|
||||||
|
|
||||||
use super::SpriteRect;
|
use super::{SpriteRect, UiElement};
|
||||||
use crate::{vertexbuffer::types::UiInstance, PositionAnchor, RenderInput, RenderState};
|
use crate::{vertexbuffer::types::UiInstance, PositionAnchor, RenderInput, RenderState};
|
||||||
|
|
||||||
pub struct UiSprite {
|
pub struct UiSprite {
|
||||||
pub anim: SpriteAutomaton,
|
sprite: SpriteHandle,
|
||||||
mask: Option<SpriteHandle>,
|
mask: Option<SpriteHandle>,
|
||||||
|
|
||||||
rect: SpriteRect,
|
rect: SpriteRect,
|
||||||
has_mouse: bool,
|
children_under: Vec<Box<dyn UiElement>>,
|
||||||
|
children_above: Vec<Box<dyn UiElement>>,
|
||||||
on_mouse_enter: Option<SectionEdge>,
|
|
||||||
on_mouse_leave: Option<SectionEdge>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiSprite {
|
impl UiSprite {
|
||||||
pub fn from(ct: &Content, ui: &UiSpriteConfig) -> Self {
|
pub fn new(sprite: SpriteHandle, mask: Option<SpriteHandle>, rect: SpriteRect) -> Self {
|
||||||
Self::from_with_sprite(ct, ui, ui.sprite.unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_with_sprite(ct: &Content, ui: &UiSpriteConfig, sprite: SpriteHandle) -> Self {
|
|
||||||
if ui.sprite.is_none() {
|
|
||||||
unreachable!("called `UiSprite.from()` on a UiSprite with a None sprite!")
|
|
||||||
}
|
|
||||||
|
|
||||||
return Self {
|
return Self {
|
||||||
anim: SpriteAutomaton::new(ct, sprite),
|
sprite,
|
||||||
mask: ui.mask,
|
mask,
|
||||||
rect: SpriteRect {
|
rect,
|
||||||
pos: *ui.rect.get_pos(),
|
children_under: Vec::new(),
|
||||||
dim: *ui.rect.get_dim(),
|
children_above: Vec::new(),
|
||||||
},
|
|
||||||
has_mouse: false,
|
|
||||||
on_mouse_enter: ui.on_mouse_enter,
|
|
||||||
on_mouse_leave: ui.on_mouse_leave,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self, input: &RenderInput, state: &RenderState) {
|
/// Add a child under this sprite
|
||||||
if self.contains_mouse(input, state, Some(self.get_rect(input)))
|
pub fn add_child_under(&mut self, child: Box<dyn UiElement>) {
|
||||||
&& !self.has_mouse
|
self.children_under.push(child);
|
||||||
&& self.on_mouse_enter.is_some()
|
|
||||||
{
|
|
||||||
self.has_mouse = true;
|
|
||||||
self.anim.jump_to(input.ct, self.on_mouse_enter.unwrap())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.contains_mouse(input, state, Some(self.get_rect(input)))
|
/// Add a child above this sprite
|
||||||
&& self.has_mouse
|
//pub fn add_child_above(&mut self, child: Box<dyn UiElement>) {
|
||||||
&& self.on_mouse_leave.is_some()
|
// self.children_above.push(child);
|
||||||
{
|
//}
|
||||||
self.has_mouse = false;
|
|
||||||
self.anim.jump_to(input.ct, self.on_mouse_leave.unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
self.anim.step(input.ct, input.time_since_last_run);
|
/// Add this image to the gpu sprite buffer
|
||||||
}
|
pub fn push_to_buffer(&self, input: &RenderInput, state: &mut RenderState) {
|
||||||
|
|
||||||
pub fn contains_mouse(
|
|
||||||
&self,
|
|
||||||
input: &RenderInput,
|
|
||||||
state: &RenderState,
|
|
||||||
parent: Option<SpriteRect>,
|
|
||||||
) -> bool {
|
|
||||||
let rect = self.get_relative_rect(input, parent);
|
|
||||||
|
|
||||||
let fac = state.window.scale_factor() as f32;
|
|
||||||
let window_size = Vector2::new(
|
|
||||||
state.window_size.width as f32 / fac,
|
|
||||||
state.window_size.height as f32 / fac,
|
|
||||||
);
|
|
||||||
|
|
||||||
let pos = input.player.input.get_mouse_pos();
|
|
||||||
let mouse_pos = Vector2::new(
|
|
||||||
pos.x / fac - window_size.x / 2.0,
|
|
||||||
window_size.y / 2.0 - pos.y / fac,
|
|
||||||
);
|
|
||||||
|
|
||||||
let ne = rect.ne_corner();
|
|
||||||
let sw = rect.sw_corner();
|
|
||||||
return (mouse_pos.y < ne.y && mouse_pos.y > sw.y)
|
|
||||||
&& (mouse_pos.x > ne.x && mouse_pos.x < sw.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_rect(&self, input: &RenderInput) -> SpriteRect {
|
|
||||||
let pos = Point2::new(self.rect.pos.x, self.rect.pos.y);
|
let pos = Point2::new(self.rect.pos.x, self.rect.pos.y);
|
||||||
let dim = Vector2::new(
|
let dim = Vector2::new(
|
||||||
self.rect.dim.y * input.ct.get_sprite(self.anim.get_sprite()).aspect,
|
self.rect.dim.y * input.ct.get_sprite(self.sprite).aspect,
|
||||||
self.rect.dim.y,
|
self.rect.dim.y,
|
||||||
);
|
);
|
||||||
|
|
||||||
return SpriteRect { dim, pos };
|
for c in &self.children_under {
|
||||||
|
c.push_to_buffer_child(input, state, pos, dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_relative_rect(&self, input: &RenderInput, parent: Option<SpriteRect>) -> SpriteRect {
|
let sprite = input.ct.get_sprite(self.sprite);
|
||||||
if let Some(parent) = parent {
|
let texture_a = sprite.get_first_frame(); // ANIMATE
|
||||||
let zero = Point2::new(
|
|
||||||
parent.pos.x - (parent.dim.x / 2.0),
|
|
||||||
parent.pos.y + (parent.dim.y / 2.0),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut pos = zero
|
|
||||||
+ Vector2::new(
|
|
||||||
self.rect.pos.x * parent.dim.x,
|
|
||||||
-self.rect.pos.y * parent.dim.y,
|
|
||||||
);
|
|
||||||
let dim = Vector2::new(
|
|
||||||
self.rect.dim.x * parent.dim.x,
|
|
||||||
self.rect.dim.y * parent.dim.y,
|
|
||||||
);
|
|
||||||
|
|
||||||
pos += Vector2::new(dim.x, -dim.y) / 2.0;
|
|
||||||
|
|
||||||
return SpriteRect { dim, pos };
|
|
||||||
} else {
|
|
||||||
return self.get_rect(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add this image to the gpu sprite buffer
|
|
||||||
pub fn push_to_buffer(
|
|
||||||
&self,
|
|
||||||
input: &RenderInput,
|
|
||||||
state: &mut RenderState,
|
|
||||||
parent: Option<SpriteRect>,
|
|
||||||
) {
|
|
||||||
let rect = self.get_relative_rect(input, parent.clone());
|
|
||||||
|
|
||||||
// TODO: use both dimensions,
|
|
||||||
// not just height
|
|
||||||
let anim_state = self.anim.get_texture_idx();
|
|
||||||
state.push_ui_buffer(UiInstance {
|
state.push_ui_buffer(UiInstance {
|
||||||
anchor: PositionAnchor::CC.to_int(),
|
anchor: PositionAnchor::CC.to_int(),
|
||||||
position: rect.pos.into(),
|
position: pos.into(),
|
||||||
angle: to_radians(90.0),
|
angle: to_radians(90.0),
|
||||||
size: rect.dim.y,
|
size: dim.y,
|
||||||
color: [1.0, 1.0, 1.0, 1.0],
|
color: [1.0, 1.0, 1.0, 1.0],
|
||||||
texture_index: anim_state.texture_index(),
|
texture_index: [texture_a, texture_a],
|
||||||
texture_fade: anim_state.fade,
|
texture_fade: 1.0,
|
||||||
mask_index: self
|
mask_index: self
|
||||||
.mask
|
.mask
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
|
@ -149,13 +67,65 @@ impl UiSprite {
|
||||||
})
|
})
|
||||||
.unwrap_or([0, 0]),
|
.unwrap_or([0, 0]),
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_sprite(&self) -> SpriteHandle {
|
for c in &self.children_above {
|
||||||
self.anim.get_sprite()
|
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_first_frame(); // 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_first_frame(); // ANIMATE
|
||||||
|
[1, texture_b]
|
||||||
|
})
|
||||||
|
.unwrap_or([0, 0]),
|
||||||
|
});
|
||||||
|
|
||||||
|
for c in &self.children_above {
|
||||||
|
c.push_to_buffer_child(input, state, pos, dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_height(&self) -> f32 {
|
|
||||||
self.rect.dim.y
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue