Basic logo impl
This commit is contained in:
parent
64d0768fb4
commit
876e88ec95
|
@ -18,7 +18,7 @@ I blame Mojang
|
|||
The logo is totally not ascii art rendered as textures
|
||||
Look, it works on my machine.
|
||||
Open Source! https://github.com/thinkofdeath/steven
|
||||
Built with Go!
|
||||
Built with Rust!
|
||||
try { } catch (Exception e) { }
|
||||
panic(recover())
|
||||
// Abandon hope all ye who enter here
|
||||
|
@ -50,3 +50,4 @@ No touchy the topic
|
|||
Ceci n'est pas un splash.
|
||||
Xor is not actually a cat.
|
||||
The MD5 of md_5 is e14cfacdd442a953343ebd8529138680
|
||||
I blame Scetch for this!
|
||||
|
|
|
@ -62,7 +62,7 @@ fn main() {
|
|||
let mut last_frame = time::now();
|
||||
let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;
|
||||
|
||||
let logo = ui::logo::Logo::new(resource_manager.clone(), &mut renderer, &mut ui_container);
|
||||
let mut logo = ui::logo::Logo::new(resource_manager.clone(), &mut renderer, &mut ui_container);
|
||||
|
||||
while !window.should_close() {
|
||||
{ resource_manager.write().unwrap().tick(); }
|
||||
|
@ -71,6 +71,8 @@ fn main() {
|
|||
last_frame = now;
|
||||
let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
|
||||
|
||||
logo.tick(&mut renderer, &mut ui_container);
|
||||
|
||||
let (width, height) = window.get_framebuffer_size();
|
||||
ui_container.tick(&mut renderer, delta, width as f64, height as f64);
|
||||
renderer.tick(delta, width as u32, height as u32);
|
||||
|
|
|
@ -28,7 +28,7 @@ const UI_HEIGHT: f64 = 480.0;
|
|||
pub struct UIState {
|
||||
textures: Arc<RwLock<render::TextureManager>>,
|
||||
resources: Arc<RwLock<resources::Manager>>,
|
||||
version: usize,
|
||||
pub version: usize,
|
||||
|
||||
data: Vec<u8>,
|
||||
prev_size: usize,
|
||||
|
@ -97,7 +97,7 @@ impl UIState {
|
|||
pos += 1;
|
||||
}
|
||||
|
||||
UIState {
|
||||
let mut state = UIState {
|
||||
textures: textures,
|
||||
resources: res,
|
||||
version: 0xFFFF,
|
||||
|
@ -126,7 +126,9 @@ impl UIState {
|
|||
char_map: char_map,
|
||||
page_width: 0.0,
|
||||
page_height: 0.0,
|
||||
}
|
||||
};
|
||||
state.load_font();
|
||||
state
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, width: u32, height: u32) {
|
||||
|
@ -168,7 +170,6 @@ impl UIState {
|
|||
gl::draw_elements(gl::TRIANGLES, self.count, self.index_type, 0);
|
||||
}
|
||||
|
||||
|
||||
gl::disable(gl::BLEND);
|
||||
self.data.clear();
|
||||
self.count = 0;
|
||||
|
@ -176,7 +177,7 @@ impl UIState {
|
|||
|
||||
pub fn add_bytes(&mut self, data: &Vec<u8>) {
|
||||
self.data.extend(data);
|
||||
self.count += (data.len() / (28 + 4)) * 6;
|
||||
self.count += (data.len() / (28 * 4)) * 6;
|
||||
}
|
||||
|
||||
pub fn character_texture(&mut self, c: char) -> render::Texture {
|
||||
|
@ -195,7 +196,7 @@ impl UIState {
|
|||
let p = self.font_pages[page as usize].clone().unwrap();
|
||||
|
||||
let raw = if page == 0 {
|
||||
self.char_map[&c] as u32
|
||||
(*self.char_map.get(&c).unwrap_or(&c)) as u32
|
||||
} else {
|
||||
raw
|
||||
};
|
||||
|
@ -235,7 +236,7 @@ impl UIState {
|
|||
}
|
||||
let r = c as u32;
|
||||
if r >> 8 == 0 {
|
||||
let r = self.char_map[&c] as u32;
|
||||
let r = (*self.char_map.get(&c).unwrap_or(&c)) as u32;
|
||||
let info = self.font_character_info[r as usize];
|
||||
let sw = self.page_width / 16.0;
|
||||
return (((info.1 - info.0) as f64) / sw) * 16.0;
|
||||
|
@ -315,7 +316,7 @@ impl UIState {
|
|||
let page = raw >> 8;
|
||||
|
||||
if page == 0 {
|
||||
raw = self.char_map[&ch] as u32;
|
||||
raw = (*self.char_map.get(&ch).unwrap_or(&ch)) as u32;
|
||||
}
|
||||
let info = self.font_character_info[raw as usize];
|
||||
let w = if page == 0 {
|
||||
|
|
|
@ -1,17 +1,37 @@
|
|||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::f64::consts;
|
||||
use ui;
|
||||
use render;
|
||||
use resources;
|
||||
use time;
|
||||
use rand;
|
||||
use rand::Rng;
|
||||
|
||||
pub struct Logo {
|
||||
resources: Arc<RwLock<resources::Manager>>,
|
||||
|
||||
shadow: ui::ElementRef<ui::Batch>,
|
||||
layer0: ui::ElementRef<ui::Batch>,
|
||||
|
||||
text: ui::ElementRef<ui::Text>,
|
||||
text_base_scale: f64,
|
||||
text_orig_x: f64,
|
||||
text_index: isize,
|
||||
text_strings: Vec<String>,
|
||||
}
|
||||
|
||||
impl Logo {
|
||||
pub fn new(resources: Arc<RwLock<resources::Manager>>, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Logo {
|
||||
let mut l = Logo {
|
||||
resources: resources
|
||||
resources: resources,
|
||||
shadow: Default::default(),
|
||||
layer0: Default::default(),
|
||||
text: Default::default(),
|
||||
text_base_scale: 0.0,
|
||||
text_orig_x: 0.0,
|
||||
text_index: -1,
|
||||
text_strings: Vec::new(),
|
||||
};
|
||||
l.init(renderer, ui_container);
|
||||
l
|
||||
|
@ -77,8 +97,74 @@ impl Logo {
|
|||
}
|
||||
row += 1;
|
||||
}
|
||||
{
|
||||
let mut splashes = res.open_all("minecraft", "texts/splashes.txt");
|
||||
for file in &mut splashes {
|
||||
let mut texts = String::new();
|
||||
file.read_to_string(&mut texts).unwrap();
|
||||
for line in texts.lines() {
|
||||
self.text_strings.push(line.to_owned().replace("\r", ""));
|
||||
}
|
||||
}
|
||||
let mut r: rand::XorShiftRng = rand::SeedableRng::from_seed([45, 64, 32, 12]);
|
||||
r.shuffle(&mut self.text_strings[..]);
|
||||
}
|
||||
|
||||
ui_container.add(shadow_batch);
|
||||
ui_container.add(layer0);
|
||||
shadow_batch.set_height(row as f64 * 8.0);
|
||||
layer0.set_height(row as f64 * 8.0);
|
||||
|
||||
self.shadow = ui_container.add(shadow_batch);
|
||||
self.layer0 = ui_container.add(layer0);
|
||||
|
||||
let mut txt = ui::Text::new(renderer, "", 0.0, -8.0, 255, 255, 0);
|
||||
txt.set_h_attach(ui::HAttach::Right);
|
||||
txt.set_v_attach(ui::VAttach::Bottom);
|
||||
txt.set_parent(&self.shadow);
|
||||
txt.set_rotation(-consts::PI / 8.0);
|
||||
|
||||
let width = txt.get_width();
|
||||
self.text_base_scale = 300.0 / width;
|
||||
if self.text_base_scale > 1.0 {
|
||||
self.text_base_scale = 1.0;
|
||||
}
|
||||
txt.set_x((-width / 2.0) * self.text_base_scale);
|
||||
self.text_orig_x = txt.get_x();
|
||||
self.text = ui_container.add(txt);
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||
let now = time::now().to_timespec();
|
||||
|
||||
// Splash text
|
||||
let text = ui_container.get_mut(&self.text);
|
||||
let text_index = (now.sec / 15) as isize % self.text_strings.len() as isize;
|
||||
if self.text_index != text_index {
|
||||
self.text_index = text_index;
|
||||
text.set_text(renderer, &self.text_strings[text_index as usize]);
|
||||
let width = text.get_width();
|
||||
self.text_base_scale = 300.0 / width;
|
||||
if self.text_base_scale > 1.0 {
|
||||
self.text_base_scale = 1.0;
|
||||
}
|
||||
text.set_x((-width / 2.0) * self.text_base_scale);
|
||||
self.text_orig_x = text.get_x();
|
||||
}
|
||||
|
||||
let timer = now.nsec as f64 / 1000000000.0;
|
||||
let mut offset = timer / 0.5;
|
||||
if offset > 1.0 {
|
||||
offset = 2.0 - offset;
|
||||
}
|
||||
offset = ((offset * consts::PI).cos() + 1.0) / 2.0;
|
||||
text.set_scale_x((0.7 + (offset / 3.0)) * self.text_base_scale);
|
||||
text.set_scale_y((0.7 + (offset / 3.0)) * self.text_base_scale);
|
||||
let scale = text.get_scale_x();
|
||||
text.set_x(self.text_orig_x * scale * self.text_base_scale);
|
||||
}
|
||||
|
||||
pub fn remove(self, ui_container: &mut ui::Container) {
|
||||
ui_container.remove(&self.shadow);
|
||||
ui_container.remove(&self.layer0);
|
||||
ui_container.remove(&self.text);
|
||||
}
|
||||
}
|
185
src/ui/mod.rs
185
src/ui/mod.rs
|
@ -25,6 +25,7 @@ const SCALED_HEIGHT: f64 = 480.0;
|
|||
pub enum Element {
|
||||
Image(Image),
|
||||
Batch(Batch),
|
||||
Text(Text),
|
||||
None,
|
||||
}
|
||||
|
||||
|
@ -70,7 +71,7 @@ impl Element {
|
|||
fn get_size(&self) -> (f64, f64) {
|
||||
match self {
|
||||
$(
|
||||
&Element::$name(ref val) => (val.width, val.height),
|
||||
&Element::$name(ref val) => val.get_size(),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
|
@ -94,6 +95,15 @@ impl Element {
|
|||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, renderer: &mut render::Renderer) {
|
||||
match self {
|
||||
$(
|
||||
&mut Element::$name(ref mut val) => val.update(renderer),
|
||||
)+
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8>{
|
||||
match self {
|
||||
$(
|
||||
|
@ -108,7 +118,8 @@ impl Element {
|
|||
|
||||
element_impl!(
|
||||
Image,
|
||||
Batch
|
||||
Batch,
|
||||
Text
|
||||
);
|
||||
|
||||
pub enum Mode {
|
||||
|
@ -160,6 +171,15 @@ struct ElementRefInner {
|
|||
index: usize,
|
||||
}
|
||||
|
||||
impl <T> Default for ElementRef<T> {
|
||||
fn default() -> Self {
|
||||
ElementRef {
|
||||
inner: ElementRefInner{ index: 0 },
|
||||
ty: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SCREEN: Region = Region{x: 0.0, y: 0.0, w: SCALED_WIDTH, h: SCALED_HEIGHT};
|
||||
|
||||
pub struct Container {
|
||||
|
@ -167,6 +187,7 @@ pub struct Container {
|
|||
elements: HashMap<ElementRefInner, Element>,
|
||||
// We need the order
|
||||
elements_list: Vec<ElementRefInner>,
|
||||
version: usize,
|
||||
|
||||
last_sw: f64,
|
||||
last_sh: f64,
|
||||
|
@ -180,6 +201,7 @@ impl Container {
|
|||
mode: Mode::Scaled,
|
||||
elements: HashMap::new(),
|
||||
elements_list: Vec::new(),
|
||||
version: 0xFFFF,
|
||||
last_sw: 0.0,
|
||||
last_sh: 0.0,
|
||||
last_width: 0.0,
|
||||
|
@ -219,14 +241,20 @@ impl Container {
|
|||
Mode::Unscaled(scale) => (scale, scale),
|
||||
};
|
||||
|
||||
if self.last_sw != sw || self.last_sh != sh || self.last_width != width || self.last_height != height {
|
||||
if self.last_sw != sw || self.last_sh != sh
|
||||
|| self.last_width != width || self.last_height != height
|
||||
|| self.version != renderer.ui.version {
|
||||
self.last_sw = sw;
|
||||
self.last_sh = sh;
|
||||
self.last_width = width;
|
||||
self.last_height = height;
|
||||
for (_, e) in &mut self.elements {
|
||||
e.set_dirty(true);
|
||||
if self.version != renderer.ui.version {
|
||||
e.update(renderer);
|
||||
}
|
||||
}
|
||||
self.version = renderer.ui.version;
|
||||
}
|
||||
|
||||
// Borrow rules seem to prevent us from doing this in the first pass
|
||||
|
@ -375,6 +403,8 @@ impl Image {
|
|||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, renderer: &mut render::Renderer) {}
|
||||
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
|
||||
if self.dirty {
|
||||
self.dirty = false;
|
||||
|
@ -390,7 +420,11 @@ impl Image {
|
|||
&self.data
|
||||
}
|
||||
|
||||
pub fn set_parent<T: UIElement>(&mut self, other: ElementRef<T>) {
|
||||
pub fn get_size(&self) -> (f64, f64) {
|
||||
(self.width, self.height)
|
||||
}
|
||||
|
||||
pub fn set_parent<T: UIElement>(&mut self, other: &ElementRef<T>) {
|
||||
self.parent = Some(other.inner);
|
||||
self.dirty = true;
|
||||
}
|
||||
|
@ -481,6 +515,10 @@ impl Batch {
|
|||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, renderer: &mut render::Renderer) {
|
||||
|
||||
}
|
||||
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
|
||||
if self.dirty {
|
||||
self.dirty = false;
|
||||
|
@ -498,7 +536,11 @@ impl Batch {
|
|||
&self.data
|
||||
}
|
||||
|
||||
pub fn set_parent<T: UIElement>(&mut self, other: ElementRef<T>) {
|
||||
pub fn get_size(&self) -> (f64, f64) {
|
||||
(self.width, self.height)
|
||||
}
|
||||
|
||||
pub fn set_parent<T: UIElement>(&mut self, other: &ElementRef<T>) {
|
||||
self.parent = Some(other.inner);
|
||||
self.dirty = true;
|
||||
}
|
||||
|
@ -536,3 +578,136 @@ impl UIElement for Batch {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Text {
|
||||
dirty: bool,
|
||||
data: Vec<u8>,
|
||||
|
||||
parent: Option<ElementRefInner>,
|
||||
should_draw: bool,
|
||||
layer: isize,
|
||||
val: String,
|
||||
x: f64,
|
||||
y: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
v_attach: VAttach,
|
||||
h_attach: HAttach,
|
||||
scale_x: f64,
|
||||
scale_y: f64,
|
||||
rotation: f64,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
a: u8,
|
||||
}
|
||||
|
||||
impl Text {
|
||||
pub fn new(renderer: &render::Renderer, val: &str, x: f64, y: f64, r: u8, g: u8, b: u8) -> Text {
|
||||
Text {
|
||||
dirty: true,
|
||||
data: Vec::new(),
|
||||
|
||||
parent: None,
|
||||
should_draw: true,
|
||||
layer: 0,
|
||||
val: val.to_owned(),
|
||||
x: x,
|
||||
y: y,
|
||||
width: renderer.ui.size_of_string(val),
|
||||
height: 18.0,
|
||||
v_attach: VAttach::Top,
|
||||
h_attach: HAttach::Left,
|
||||
scale_x: 1.0,
|
||||
scale_y: 1.0,
|
||||
rotation: 0.0,
|
||||
r: r,
|
||||
g: g,
|
||||
b: b,
|
||||
a: 255,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, renderer: &mut render::Renderer) {
|
||||
self.width = renderer.ui.size_of_string(&self.val);
|
||||
}
|
||||
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
|
||||
if self.dirty {
|
||||
self.dirty = false;
|
||||
let sx = r.w / self.width;
|
||||
let sy = r.h / self.height;
|
||||
let mut text = if self.rotation == 0.0 {
|
||||
renderer.ui.new_text_scaled(&self.val, r.x, r.y, sx*self.scale_x, sy*self.scale_y, self.r, self.g, self.b)
|
||||
} else {
|
||||
let c = self.rotation.cos();
|
||||
let s = self.rotation.sin();
|
||||
let tmpx = r.w / 2.0;
|
||||
let tmpy = r.h / 2.0;
|
||||
let w = (tmpx*c - tmpy*s).abs();
|
||||
let h = (tmpy*c + tmpx*s).abs();
|
||||
renderer.ui.new_text_rotated(&self.val, r.x+w-(r.w / 2.0), r.y+h-(r.h / 2.0), sx*self.scale_x, sy*self.scale_y, self.rotation, self.r, self.g, self.b)
|
||||
};
|
||||
for e in &mut text.elements {
|
||||
e.a = self.a;
|
||||
e.layer = self.layer;
|
||||
}
|
||||
self.data = text.bytes(width, height);
|
||||
}
|
||||
&self.data
|
||||
}
|
||||
|
||||
pub fn get_size(&self) -> (f64, f64) {
|
||||
((self.width + 2.0) * self.scale_x, self.height * self.scale_y)
|
||||
}
|
||||
|
||||
pub fn set_parent<T: UIElement>(&mut self, other: &ElementRef<T>) {
|
||||
self.parent = Some(other.inner);
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub fn get_text(&self) -> &str {
|
||||
&self.val
|
||||
}
|
||||
|
||||
pub fn set_text(&mut self, renderer: &render::Renderer, val: &str) {
|
||||
self.dirty = true;
|
||||
self.val = val.to_owned();
|
||||
self.width = renderer.ui.size_of_string(val);
|
||||
}
|
||||
|
||||
lazy_field!(layer, isize, get_layer, set_layer);
|
||||
lazy_field!(x, f64, get_x, set_x);
|
||||
lazy_field!(y, f64, get_y, set_y);
|
||||
lazy_field!(width, f64, get_width, set_width);
|
||||
lazy_field!(height, f64, get_height, set_height);
|
||||
lazy_field!(v_attach, VAttach, get_v_attach, set_v_attach);
|
||||
lazy_field!(h_attach, HAttach, get_h_attach, set_h_attach);
|
||||
lazy_field!(scale_x, f64, get_scale_x, set_scale_x);
|
||||
lazy_field!(scale_y, f64, get_scale_y, set_scale_y);
|
||||
lazy_field!(rotation, f64, get_rotation, set_rotation);
|
||||
lazy_field!(r, u8, get_r, set_r);
|
||||
lazy_field!(g, u8, get_g, set_g);
|
||||
lazy_field!(b, u8, get_b, set_b);
|
||||
|
||||
}
|
||||
|
||||
impl UIElement for Text {
|
||||
fn wrap(self) -> Element {
|
||||
Element::Text(self)
|
||||
}
|
||||
|
||||
fn unwrap_ref<'a>(e: &'a Element) -> &'a Text {
|
||||
match e {
|
||||
&Element::Text(ref val) => val,
|
||||
_ => panic!("Incorrect type"),
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Text {
|
||||
match e {
|
||||
&mut Element::Text(ref mut val) => val,
|
||||
_ => panic!("Incorrect type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue