Added radialbar builder
parent
093a7f271c
commit
3c582006ef
|
@ -1,3 +1,44 @@
|
|||
fn init(state) { return []; }
|
||||
fn init(state) {
|
||||
|
||||
|
||||
let ring = SpriteBuilder(
|
||||
"ring",
|
||||
"ui::status",
|
||||
Rect(
|
||||
-5.0, -5.0, 100.0, 100.0,
|
||||
SpriteAnchor::NorthEast,
|
||||
SpriteAnchor::NorthEast
|
||||
)
|
||||
);
|
||||
|
||||
let shield = RadialBuilder(
|
||||
"shield", 2.5,
|
||||
Color(0.3, 0.6, 0.8, 1.0),
|
||||
Rect(
|
||||
-9.5, -9.5, 91.0, 91.0,
|
||||
SpriteAnchor::NorthEast,
|
||||
SpriteAnchor::NorthEast
|
||||
)
|
||||
);
|
||||
shield.set_progress(0.2);
|
||||
|
||||
let hull = RadialBuilder(
|
||||
"hull", 2.5,
|
||||
Color(0.8, 0.7, 0.5, 1.0),
|
||||
Rect(
|
||||
-13.5, -13.5, 83.0, 83.0,
|
||||
SpriteAnchor::NorthEast,
|
||||
SpriteAnchor::NorthEast
|
||||
)
|
||||
);
|
||||
hull.set_progress(0.4);
|
||||
|
||||
return [
|
||||
ring,
|
||||
shield,
|
||||
hull
|
||||
];
|
||||
}
|
||||
|
||||
fn hover(element, hover_state) {}
|
||||
fn click(element, click_state) {}
|
|
@ -121,11 +121,8 @@ fn try_main() -> Result<()> {
|
|||
|
||||
let event_loop = EventLoop::new();
|
||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
let mut gpu = pollster::block_on(galactica_render::GPUState::new(
|
||||
window,
|
||||
content.clone(),
|
||||
RenderScenes::System,
|
||||
))?;
|
||||
let mut gpu = pollster::block_on(galactica_render::GPUState::new(window, content.clone()))?;
|
||||
gpu.set_scene(RenderScenes::System);
|
||||
gpu.init(&content);
|
||||
|
||||
// TODO: don't clone content
|
||||
|
|
|
@ -37,11 +37,7 @@ pub struct GPUState {
|
|||
|
||||
impl GPUState {
|
||||
/// Make a new GPUState that draws on `window`
|
||||
pub async fn new(
|
||||
window: winit::window::Window,
|
||||
ct: Rc<Content>,
|
||||
scene: RenderScenes,
|
||||
) -> Result<Self> {
|
||||
pub async fn new(window: winit::window::Window, ct: Rc<Content>) -> Result<Self> {
|
||||
let window_size = window.inner_size();
|
||||
let window_aspect = window_size.width as f32 / window_size.height as f32;
|
||||
|
||||
|
@ -229,7 +225,7 @@ impl GPUState {
|
|||
starfield_pipeline,
|
||||
ui_pipeline,
|
||||
radialbar_pipeline,
|
||||
scene,
|
||||
scene: RenderScenes::Landed,
|
||||
|
||||
state: RenderState {
|
||||
queue,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use galactica_content::Content;
|
||||
use galactica_util::constants::{OBJECT_SPRITE_INSTANCE_LIMIT, UI_SPRITE_INSTANCE_LIMIT};
|
||||
use galactica_util::constants::{
|
||||
OBJECT_SPRITE_INSTANCE_LIMIT, RADIALBAR_SPRITE_INSTANCE_LIMIT, UI_SPRITE_INSTANCE_LIMIT,
|
||||
};
|
||||
use glyphon::{FontSystem, SwashCache, TextAtlas, TextRenderer};
|
||||
use std::rc::Rc;
|
||||
use wgpu::BufferAddress;
|
||||
|
@ -152,7 +154,6 @@ impl RenderState {
|
|||
self.vertex_buffers.object_counter as u32
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn push_radialbar_buffer(&mut self, instance: RadialBarInstance) {
|
||||
// Enforce buffer limit
|
||||
if self.vertex_buffers.radialbar_counter as u64 > RADIALBAR_SPRITE_INSTANCE_LIMIT {
|
||||
|
@ -167,7 +168,6 @@ impl RenderState {
|
|||
);
|
||||
self.vertex_buffers.radialbar_counter += 1;
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn get_radialbar_counter(&self) -> u32 {
|
||||
self.vertex_buffers.radialbar_counter as u32
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
use nalgebra::Vector4;
|
||||
use rhai::{CustomType, TypeBuilder};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Color {
|
||||
pub val: Vector4<f32>,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
|
||||
Self {
|
||||
val: Vector4::new(r, g, b, a),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_array(&self) -> [f32; 4] {
|
||||
[self.val.x, self.val.y, self.val.z, self.val.w]
|
||||
}
|
||||
}
|
||||
|
||||
impl CustomType for Color {
|
||||
fn build(mut builder: TypeBuilder<Self>) {
|
||||
builder.with_name("Color").with_fn("Color", Self::new);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
mod color;
|
||||
mod radialbuilder;
|
||||
mod rect;
|
||||
mod sprite;
|
||||
mod spritebuilder;
|
||||
|
@ -11,6 +13,8 @@ pub fn register_into_engine(engine: &mut Engine) {
|
|||
engine
|
||||
.build_type::<State>()
|
||||
.build_type::<Rect>()
|
||||
.build_type::<Color>()
|
||||
.build_type::<RadialBuilder>()
|
||||
.build_type::<SpriteElement>()
|
||||
.build_type::<SpriteBuilder>()
|
||||
.build_type::<TextBoxBuilder>()
|
||||
|
@ -30,6 +34,8 @@ pub fn register_into_engine(engine: &mut Engine) {
|
|||
.register_static_module("SceneAction", exported_module!(sceneaction_mod).into());
|
||||
}
|
||||
|
||||
pub use color::*;
|
||||
pub use radialbuilder::*;
|
||||
pub use rect::*;
|
||||
pub use sprite::*;
|
||||
pub use spritebuilder::*;
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
use nalgebra::clamp;
|
||||
use rhai::{CustomType, ImmutableString, TypeBuilder};
|
||||
|
||||
use super::{color::Color, Rect};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RadialBuilder {
|
||||
pub name: ImmutableString,
|
||||
pub rect: Rect,
|
||||
|
||||
pub stroke: f32,
|
||||
pub color: Color,
|
||||
pub progress: f32,
|
||||
}
|
||||
|
||||
impl RadialBuilder {
|
||||
pub fn new(name: ImmutableString, stroke: f32, color: Color, rect: Rect) -> Self {
|
||||
Self {
|
||||
name,
|
||||
rect,
|
||||
stroke,
|
||||
color,
|
||||
progress: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_progress(&mut self, progress: f32) {
|
||||
self.progress = clamp(progress, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl CustomType for RadialBuilder {
|
||||
fn build(mut builder: TypeBuilder<Self>) {
|
||||
builder
|
||||
.with_name("RadialBuilder")
|
||||
.with_fn("RadialBuilder", Self::new)
|
||||
.with_fn("set_progress", Self::set_progress);
|
||||
}
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
use rhai::{CustomType, TypeBuilder};
|
||||
use rhai::{CustomType, ImmutableString, TypeBuilder};
|
||||
|
||||
use super::Rect;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SpriteBuilder {
|
||||
pub name: String,
|
||||
pub name: ImmutableString,
|
||||
pub rect: Rect,
|
||||
pub sprite: String,
|
||||
pub mask: Option<String>,
|
||||
pub sprite: ImmutableString,
|
||||
pub mask: Option<ImmutableString>,
|
||||
}
|
||||
|
||||
impl SpriteBuilder {
|
||||
pub fn new(name: String, sprite: String, rect: Rect) -> Self {
|
||||
pub fn new(name: ImmutableString, sprite: ImmutableString, rect: Rect) -> Self {
|
||||
Self {
|
||||
name,
|
||||
rect,
|
||||
|
@ -20,7 +20,7 @@ impl SpriteBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_mask(&mut self, mask: String) {
|
||||
pub fn set_mask(&mut self, mask: ImmutableString) {
|
||||
self.mask = Some(mask);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
use rhai::{CustomType, TypeBuilder};
|
||||
use rhai::{CustomType, ImmutableString, TypeBuilder};
|
||||
|
||||
use super::{Rect, TextBoxFont, TextBoxJustify};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TextBoxBuilder {
|
||||
pub name: String,
|
||||
pub name: ImmutableString,
|
||||
pub font_size: f32,
|
||||
pub line_height: f32,
|
||||
pub font: TextBoxFont,
|
||||
pub justify: TextBoxJustify,
|
||||
pub rect: Rect,
|
||||
pub text: String,
|
||||
pub text: ImmutableString,
|
||||
}
|
||||
|
||||
impl TextBoxBuilder {
|
||||
pub fn new(
|
||||
name: String,
|
||||
name: ImmutableString,
|
||||
font_size: f32,
|
||||
line_height: f32,
|
||||
font: TextBoxFont,
|
||||
|
@ -29,11 +29,11 @@ impl TextBoxBuilder {
|
|||
font,
|
||||
justify,
|
||||
rect,
|
||||
text: String::new(),
|
||||
text: ImmutableString::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_text(&mut self, text: String) {
|
||||
pub fn set_text(&mut self, text: ImmutableString) {
|
||||
self.text = text
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,13 @@ use std::{cell::RefCell, collections::HashSet, fmt::Debug, rc::Rc};
|
|||
|
||||
use super::{
|
||||
api::{self, SceneAction, SpriteElement, TextBoxBuilder},
|
||||
util::{Sprite, TextBox},
|
||||
util::{RadialBar, TextBox},
|
||||
};
|
||||
use crate::{
|
||||
ui::api::{SpriteBuilder, State},
|
||||
ui::{
|
||||
api::{RadialBuilder, SpriteBuilder, State},
|
||||
util::Sprite,
|
||||
},
|
||||
RenderInput, RenderState,
|
||||
};
|
||||
|
||||
|
@ -58,6 +61,7 @@ impl ToString for UiScene {
|
|||
|
||||
enum UiElement {
|
||||
Sprite(Rc<RefCell<Sprite>>),
|
||||
RadialBar(Rc<RefCell<RadialBar>>),
|
||||
Text(TextBox),
|
||||
}
|
||||
|
||||
|
@ -66,6 +70,10 @@ impl UiElement {
|
|||
Self::Sprite(Rc::new(RefCell::new(sprite)))
|
||||
}
|
||||
|
||||
pub fn new_radialbar(bar: RadialBar) -> Self {
|
||||
Self::RadialBar(Rc::new(RefCell::new(bar)))
|
||||
}
|
||||
|
||||
pub fn new_text(text: TextBox) -> Self {
|
||||
Self::Text(text)
|
||||
}
|
||||
|
@ -83,6 +91,13 @@ impl UiElement {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn radialbar(&self) -> Option<Rc<RefCell<RadialBar>>> {
|
||||
match self {
|
||||
Self::RadialBar(r) => Some(r.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct UiManager {
|
||||
|
@ -143,32 +158,55 @@ impl UiManager {
|
|||
for v in builders {
|
||||
if v.is::<SpriteBuilder>() {
|
||||
let s = v.cast::<SpriteBuilder>();
|
||||
if used_names.contains(&s.name) {
|
||||
if used_names.contains(s.name.as_str()) {
|
||||
error!(
|
||||
"UI scene `{}` re-uses element name `{}`",
|
||||
self.current_scene.to_string(),
|
||||
s.name
|
||||
);
|
||||
} else {
|
||||
used_names.insert(s.name.clone());
|
||||
used_names.insert(s.name.to_string());
|
||||
}
|
||||
self.elements.push(UiElement::new_sprite(Sprite::new(
|
||||
&self.ct, s.name, s.sprite, s.mask, s.rect,
|
||||
&self.ct,
|
||||
s.name.to_string(),
|
||||
s.sprite.to_string(),
|
||||
s.mask.map(|x| x.to_string()),
|
||||
s.rect,
|
||||
)));
|
||||
} else if v.is::<RadialBuilder>() {
|
||||
let r = v.cast::<RadialBuilder>();
|
||||
if used_names.contains(r.name.as_str()) {
|
||||
error!(
|
||||
"UI scene `{}` re-uses element name `{}`",
|
||||
self.current_scene.to_string(),
|
||||
r.name
|
||||
);
|
||||
} else {
|
||||
used_names.insert(r.name.to_string());
|
||||
}
|
||||
self.elements.push(UiElement::new_radialbar(RadialBar::new(
|
||||
&self.ct,
|
||||
r.name.to_string(),
|
||||
r.stroke,
|
||||
r.color,
|
||||
r.rect,
|
||||
r.progress,
|
||||
)));
|
||||
} else if v.is::<TextBoxBuilder>() {
|
||||
let t = v.cast::<TextBoxBuilder>();
|
||||
if used_names.contains(&t.name) {
|
||||
if used_names.contains(t.name.as_str()) {
|
||||
error!(
|
||||
"UI scene `{}` re-uses element name `{}`",
|
||||
self.current_scene.to_string(),
|
||||
t.name
|
||||
);
|
||||
} else {
|
||||
used_names.insert(t.name.clone());
|
||||
used_names.insert(t.name.to_string());
|
||||
}
|
||||
let mut b = TextBox::new(
|
||||
state,
|
||||
t.name,
|
||||
t.name.to_string(),
|
||||
t.font_size,
|
||||
t.line_height,
|
||||
t.font,
|
||||
|
@ -187,12 +225,7 @@ impl UiManager {
|
|||
|
||||
/// Draw all ui elements
|
||||
pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) -> Result<()> {
|
||||
let mut iter = self
|
||||
.elements
|
||||
.iter()
|
||||
.map(|x| x.sprite())
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap());
|
||||
let mut iter = self.elements.iter();
|
||||
|
||||
let action: SceneAction = loop {
|
||||
let e = match iter.next() {
|
||||
|
@ -200,29 +233,40 @@ impl UiManager {
|
|||
None => break SceneAction::None,
|
||||
};
|
||||
|
||||
let mut x = (*e).borrow_mut();
|
||||
let m = x.check_mouse(input, state);
|
||||
x.step(input, state);
|
||||
x.push_to_buffer(input, state);
|
||||
drop(x);
|
||||
// we MUST drop here, since script calls mutate the sprite RefCell
|
||||
let action: Dynamic = {
|
||||
if let Some(e) = e.sprite() {
|
||||
let mut x = (*e).borrow_mut();
|
||||
let m = x.check_mouse(input, state);
|
||||
x.step(input, state);
|
||||
x.push_to_buffer(input, state);
|
||||
drop(x);
|
||||
// we MUST drop here, since script calls mutate the sprite RefCell
|
||||
|
||||
let action: Dynamic = match m {
|
||||
MouseEvent::None => Dynamic::from(SceneAction::None),
|
||||
match m {
|
||||
MouseEvent::None => Dynamic::from(SceneAction::None),
|
||||
|
||||
MouseEvent::Release | MouseEvent::Click => self.engine.call_fn(
|
||||
&mut self.scope,
|
||||
Self::get_scene_ast(&self.ct, self.current_scene),
|
||||
"click",
|
||||
(SpriteElement::new(self.ct.clone(), e.clone()), m.is_click()),
|
||||
)?,
|
||||
MouseEvent::Release | MouseEvent::Click => self.engine.call_fn(
|
||||
&mut self.scope,
|
||||
Self::get_scene_ast(&self.ct, self.current_scene),
|
||||
"click",
|
||||
(SpriteElement::new(self.ct.clone(), e.clone()), m.is_click()),
|
||||
)?,
|
||||
|
||||
MouseEvent::Leave | MouseEvent::Enter => self.engine.call_fn(
|
||||
&mut self.scope,
|
||||
Self::get_scene_ast(&self.ct, self.current_scene),
|
||||
"hover",
|
||||
(SpriteElement::new(self.ct.clone(), e.clone()), m.is_enter()),
|
||||
)?,
|
||||
MouseEvent::Leave | MouseEvent::Enter => self.engine.call_fn(
|
||||
&mut self.scope,
|
||||
Self::get_scene_ast(&self.ct, self.current_scene),
|
||||
"hover",
|
||||
(SpriteElement::new(self.ct.clone(), e.clone()), m.is_enter()),
|
||||
)?,
|
||||
}
|
||||
} else if let Some(e) = e.radialbar() {
|
||||
let mut x = (*e).borrow_mut();
|
||||
x.step(input, state);
|
||||
x.push_to_buffer(input, state);
|
||||
Dynamic::from(SceneAction::None)
|
||||
} else {
|
||||
Dynamic::from(SceneAction::None)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(action) = action.try_cast::<SceneAction>() {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
mod radialbar;
|
||||
mod sprite;
|
||||
mod textbox;
|
||||
|
||||
pub use radialbar::*;
|
||||
pub use sprite::*;
|
||||
pub use textbox::*;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
use galactica_content::Content;
|
||||
use std::f32::consts::TAU;
|
||||
|
||||
use super::super::api::Rect;
|
||||
use crate::{
|
||||
ui::api::Color, vertexbuffer::types::RadialBarInstance, PositionAnchor, RenderInput,
|
||||
RenderState,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RadialBar {
|
||||
pub name: String,
|
||||
pub rect: Rect,
|
||||
pub stroke: f32,
|
||||
pub color: Color,
|
||||
pub progress: f32,
|
||||
}
|
||||
|
||||
impl RadialBar {
|
||||
pub fn new(
|
||||
_ct: &Content,
|
||||
name: String,
|
||||
stroke: f32,
|
||||
color: Color,
|
||||
rect: Rect,
|
||||
progress: f32,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
rect,
|
||||
stroke,
|
||||
color,
|
||||
progress,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_to_buffer(&self, input: &RenderInput, state: &mut RenderState) {
|
||||
let rect = self.rect.to_centered(state, input.ct.get_config().ui_scale);
|
||||
|
||||
state.push_radialbar_buffer(RadialBarInstance {
|
||||
position: [rect.pos.x, rect.pos.y],
|
||||
anchor: PositionAnchor::CC.to_int(),
|
||||
diameter: rect.dim.x.min(rect.dim.y),
|
||||
stroke: self.stroke * input.ct.get_config().ui_scale,
|
||||
color: self.color.as_array(),
|
||||
angle: self.progress * TAU,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn step(&mut self, _input: &RenderInput, _state: &mut RenderState) {}
|
||||
}
|
Loading…
Reference in New Issue