Basic logo impl

This commit is contained in:
Thinkofdeath 2015-09-21 21:11:30 +01:00
parent 64d0768fb4
commit 876e88ec95
5 changed files with 283 additions and 18 deletions

View File

@ -18,7 +18,7 @@ I blame Mojang
The logo is totally not ascii art rendered as textures The logo is totally not ascii art rendered as textures
Look, it works on my machine. Look, it works on my machine.
Open Source! https://github.com/thinkofdeath/steven Open Source! https://github.com/thinkofdeath/steven
Built with Go! Built with Rust!
try { } catch (Exception e) { } try { } catch (Exception e) { }
panic(recover()) panic(recover())
// Abandon hope all ye who enter here // Abandon hope all ye who enter here
@ -50,3 +50,4 @@ No touchy the topic
Ceci n'est pas un splash. Ceci n'est pas un splash.
Xor is not actually a cat. Xor is not actually a cat.
The MD5 of md_5 is e14cfacdd442a953343ebd8529138680 The MD5 of md_5 is e14cfacdd442a953343ebd8529138680
I blame Scetch for this!

View File

@ -62,7 +62,7 @@ fn main() {
let mut last_frame = time::now(); let mut last_frame = time::now();
let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0; 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() { while !window.should_close() {
{ resource_manager.write().unwrap().tick(); } { resource_manager.write().unwrap().tick(); }
@ -71,6 +71,8 @@ fn main() {
last_frame = now; last_frame = now;
let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time; let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
logo.tick(&mut renderer, &mut ui_container);
let (width, height) = window.get_framebuffer_size(); let (width, height) = window.get_framebuffer_size();
ui_container.tick(&mut renderer, delta, width as f64, height as f64); ui_container.tick(&mut renderer, delta, width as f64, height as f64);
renderer.tick(delta, width as u32, height as u32); renderer.tick(delta, width as u32, height as u32);

View File

@ -28,7 +28,7 @@ const UI_HEIGHT: f64 = 480.0;
pub struct UIState { pub struct UIState {
textures: Arc<RwLock<render::TextureManager>>, textures: Arc<RwLock<render::TextureManager>>,
resources: Arc<RwLock<resources::Manager>>, resources: Arc<RwLock<resources::Manager>>,
version: usize, pub version: usize,
data: Vec<u8>, data: Vec<u8>,
prev_size: usize, prev_size: usize,
@ -97,7 +97,7 @@ impl UIState {
pos += 1; pos += 1;
} }
UIState { let mut state = UIState {
textures: textures, textures: textures,
resources: res, resources: res,
version: 0xFFFF, version: 0xFFFF,
@ -126,7 +126,9 @@ impl UIState {
char_map: char_map, char_map: char_map,
page_width: 0.0, page_width: 0.0,
page_height: 0.0, page_height: 0.0,
} };
state.load_font();
state
} }
pub fn tick(&mut self, width: u32, height: u32) { 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::draw_elements(gl::TRIANGLES, self.count, self.index_type, 0);
} }
gl::disable(gl::BLEND); gl::disable(gl::BLEND);
self.data.clear(); self.data.clear();
self.count = 0; self.count = 0;
@ -176,7 +177,7 @@ impl UIState {
pub fn add_bytes(&mut self, data: &Vec<u8>) { pub fn add_bytes(&mut self, data: &Vec<u8>) {
self.data.extend(data); 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 { 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 p = self.font_pages[page as usize].clone().unwrap();
let raw = if page == 0 { let raw = if page == 0 {
self.char_map[&c] as u32 (*self.char_map.get(&c).unwrap_or(&c)) as u32
} else { } else {
raw raw
}; };
@ -235,7 +236,7 @@ impl UIState {
} }
let r = c as u32; let r = c as u32;
if r >> 8 == 0 { 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 info = self.font_character_info[r as usize];
let sw = self.page_width / 16.0; let sw = self.page_width / 16.0;
return (((info.1 - info.0) as f64) / sw) * 16.0; return (((info.1 - info.0) as f64) / sw) * 16.0;
@ -315,7 +316,7 @@ impl UIState {
let page = raw >> 8; let page = raw >> 8;
if page == 0 { 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 info = self.font_character_info[raw as usize];
let w = if page == 0 { let w = if page == 0 {

View File

@ -1,17 +1,37 @@
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use std::f64::consts;
use ui; use ui;
use render; use render;
use resources; use resources;
use time;
use rand;
use rand::Rng;
pub struct Logo { pub struct Logo {
resources: Arc<RwLock<resources::Manager>>, 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 { impl Logo {
pub fn new(resources: Arc<RwLock<resources::Manager>>, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Logo { pub fn new(resources: Arc<RwLock<resources::Manager>>, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Logo {
let mut l = 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.init(renderer, ui_container);
l l
@ -77,8 +97,74 @@ impl Logo {
} }
row += 1; 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); shadow_batch.set_height(row as f64 * 8.0);
ui_container.add(layer0); 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);
} }
} }

View File

@ -25,6 +25,7 @@ const SCALED_HEIGHT: f64 = 480.0;
pub enum Element { pub enum Element {
Image(Image), Image(Image),
Batch(Batch), Batch(Batch),
Text(Text),
None, None,
} }
@ -70,7 +71,7 @@ impl Element {
fn get_size(&self) -> (f64, f64) { fn get_size(&self) -> (f64, f64) {
match self { match self {
$( $(
&Element::$name(ref val) => (val.width, val.height), &Element::$name(ref val) => val.get_size(),
)+ )+
_ => unimplemented!(), _ => 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>{ fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8>{
match self { match self {
$( $(
@ -108,7 +118,8 @@ impl Element {
element_impl!( element_impl!(
Image, Image,
Batch Batch,
Text
); );
pub enum Mode { pub enum Mode {
@ -160,6 +171,15 @@ struct ElementRefInner {
index: usize, 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}; const SCREEN: Region = Region{x: 0.0, y: 0.0, w: SCALED_WIDTH, h: SCALED_HEIGHT};
pub struct Container { pub struct Container {
@ -167,6 +187,7 @@ pub struct Container {
elements: HashMap<ElementRefInner, Element>, elements: HashMap<ElementRefInner, Element>,
// We need the order // We need the order
elements_list: Vec<ElementRefInner>, elements_list: Vec<ElementRefInner>,
version: usize,
last_sw: f64, last_sw: f64,
last_sh: f64, last_sh: f64,
@ -180,6 +201,7 @@ impl Container {
mode: Mode::Scaled, mode: Mode::Scaled,
elements: HashMap::new(), elements: HashMap::new(),
elements_list: Vec::new(), elements_list: Vec::new(),
version: 0xFFFF,
last_sw: 0.0, last_sw: 0.0,
last_sh: 0.0, last_sh: 0.0,
last_width: 0.0, last_width: 0.0,
@ -219,14 +241,20 @@ impl Container {
Mode::Unscaled(scale) => (scale, scale), 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_sw = sw;
self.last_sh = sh; self.last_sh = sh;
self.last_width = width; self.last_width = width;
self.last_height = height; self.last_height = height;
for (_, e) in &mut self.elements { for (_, e) in &mut self.elements {
e.set_dirty(true); 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 // 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> { fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
if self.dirty { if self.dirty {
self.dirty = false; self.dirty = false;
@ -390,7 +420,11 @@ impl Image {
&self.data &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.parent = Some(other.inner);
self.dirty = true; 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> { fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec<u8> {
if self.dirty { if self.dirty {
self.dirty = false; self.dirty = false;
@ -498,7 +536,11 @@ impl Batch {
&self.data &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.parent = Some(other.inner);
self.dirty = true; 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"),
}
}
}