2016-03-16 14:25:35 -04:00
|
|
|
|
// Copyright 2016 Matthew Collins
|
2015-09-17 11:21:56 -04:00
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
2015-09-17 11:04:25 -04:00
|
|
|
|
|
2018-11-04 14:48:03 -05:00
|
|
|
|
use crate::gl;
|
|
|
|
|
use crate::render;
|
|
|
|
|
use crate::render::glsl;
|
|
|
|
|
use crate::render::shaders;
|
2020-06-21 15:17:24 -04:00
|
|
|
|
use crate::resources;
|
|
|
|
|
use byteorder::{NativeEndian, WriteBytesExt};
|
2018-09-30 20:21:05 -04:00
|
|
|
|
use image::GenericImageView;
|
2020-06-21 15:17:24 -04:00
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::sync::{Arc, RwLock};
|
2015-09-17 11:04:25 -04:00
|
|
|
|
|
|
|
|
|
const UI_WIDTH: f64 = 854.0;
|
|
|
|
|
const UI_HEIGHT: f64 = 480.0;
|
|
|
|
|
|
2015-10-07 14:36:59 -04:00
|
|
|
|
pub struct UIState {
|
|
|
|
|
textures: Arc<RwLock<render::TextureManager>>,
|
|
|
|
|
resources: Arc<RwLock<resources::Manager>>,
|
|
|
|
|
pub version: usize,
|
|
|
|
|
|
|
|
|
|
data: Vec<u8>,
|
|
|
|
|
prev_size: usize,
|
|
|
|
|
count: usize,
|
|
|
|
|
|
|
|
|
|
array: gl::VertexArray,
|
|
|
|
|
buffer: gl::Buffer,
|
|
|
|
|
index_buffer: gl::Buffer,
|
|
|
|
|
index_type: gl::Type,
|
|
|
|
|
max_index: usize,
|
|
|
|
|
|
|
|
|
|
shader: UIShader,
|
|
|
|
|
|
|
|
|
|
// Font
|
|
|
|
|
font_pages: Vec<Option<render::Texture>>,
|
|
|
|
|
font_character_info: Vec<(i32, i32)>,
|
|
|
|
|
char_map: HashMap<char, char>,
|
|
|
|
|
page_width: f64,
|
|
|
|
|
page_height: f64,
|
2015-09-17 11:04:25 -04:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-06 18:49:52 -04:00
|
|
|
|
init_shader! {
|
2016-03-20 16:17:21 -04:00
|
|
|
|
Program UIShader {
|
|
|
|
|
vert = "ui_vertex",
|
|
|
|
|
frag = "ui_frag",
|
|
|
|
|
attribute = {
|
2016-04-09 06:08:17 -04:00
|
|
|
|
required position => "aPosition",
|
|
|
|
|
required texture_info => "aTextureInfo",
|
|
|
|
|
required texture_offset => "aTextureOffset",
|
|
|
|
|
required color => "aColor",
|
2016-03-20 16:17:21 -04:00
|
|
|
|
},
|
|
|
|
|
uniform = {
|
2016-04-09 06:08:17 -04:00
|
|
|
|
required texture => "textures",
|
|
|
|
|
required screensize => "screenSize",
|
2016-03-20 16:17:21 -04:00
|
|
|
|
},
|
|
|
|
|
}
|
2015-10-06 18:49:52 -04:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-17 11:04:25 -04:00
|
|
|
|
impl UIState {
|
2020-06-21 15:17:24 -04:00
|
|
|
|
pub fn new(
|
|
|
|
|
glsl: &glsl::Registry,
|
|
|
|
|
textures: Arc<RwLock<render::TextureManager>>,
|
|
|
|
|
res: Arc<RwLock<resources::Manager>>,
|
|
|
|
|
) -> UIState {
|
2015-10-07 14:36:59 -04:00
|
|
|
|
let shader = UIShader::new(glsl);
|
|
|
|
|
|
|
|
|
|
let array = gl::VertexArray::new();
|
|
|
|
|
array.bind();
|
|
|
|
|
let buffer = gl::Buffer::new();
|
|
|
|
|
buffer.bind(gl::ARRAY_BUFFER);
|
|
|
|
|
shader.position.enable();
|
|
|
|
|
shader.texture_info.enable();
|
|
|
|
|
shader.texture_offset.enable();
|
|
|
|
|
shader.color.enable();
|
|
|
|
|
shader.position.vertex_pointer_int(3, gl::SHORT, 28, 0);
|
2020-06-21 15:17:24 -04:00
|
|
|
|
shader
|
|
|
|
|
.texture_info
|
|
|
|
|
.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 28, 8);
|
|
|
|
|
shader
|
|
|
|
|
.texture_offset
|
|
|
|
|
.vertex_pointer_int(3, gl::SHORT, 28, 16);
|
|
|
|
|
shader
|
|
|
|
|
.color
|
|
|
|
|
.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 28, 24);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
|
|
|
|
|
let index_buffer = gl::Buffer::new();
|
|
|
|
|
index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
|
|
|
|
|
|
|
|
|
let mut pages = Vec::with_capacity(0x100);
|
|
|
|
|
for _ in 0..0x100 {
|
|
|
|
|
pages.push(Option::None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut char_map = HashMap::new();
|
|
|
|
|
let ascii_chars = "ÀÁÂÈÊËÍÓÔÕÚßãõğİıŒœŞşŴŵžȇ \
|
|
|
|
|
!\"#$%&'()*+,-./0123456789:;\
|
|
|
|
|
<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ \
|
|
|
|
|
ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞\
|
|
|
|
|
╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αβΓπΣσμτΦΘΩδ∞∅∈∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■";
|
|
|
|
|
for (pos, c) in ascii_chars.chars().enumerate() {
|
|
|
|
|
char_map.insert(c, ::std::char::from_u32(pos as u32).unwrap());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut state = UIState {
|
2018-11-04 16:43:30 -05:00
|
|
|
|
textures,
|
2015-10-07 14:36:59 -04:00
|
|
|
|
resources: res,
|
|
|
|
|
version: 0xFFFF,
|
|
|
|
|
|
|
|
|
|
data: Vec::new(),
|
|
|
|
|
count: 0,
|
|
|
|
|
prev_size: 0,
|
|
|
|
|
|
|
|
|
|
index_type: gl::UNSIGNED_BYTE,
|
2018-11-04 16:43:30 -05:00
|
|
|
|
array,
|
|
|
|
|
buffer,
|
|
|
|
|
index_buffer,
|
2015-10-07 14:36:59 -04:00
|
|
|
|
max_index: 0,
|
|
|
|
|
|
2018-11-04 16:43:30 -05:00
|
|
|
|
shader,
|
2015-10-07 14:36:59 -04:00
|
|
|
|
|
|
|
|
|
// Font
|
|
|
|
|
font_pages: pages,
|
|
|
|
|
font_character_info: vec![(0, 0); 0x10000],
|
2018-11-04 16:43:30 -05:00
|
|
|
|
char_map,
|
2015-10-07 14:36:59 -04:00
|
|
|
|
page_width: 0.0,
|
|
|
|
|
page_height: 0.0,
|
|
|
|
|
};
|
|
|
|
|
state.load_font();
|
|
|
|
|
state
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn tick(&mut self, width: u32, height: u32) {
|
|
|
|
|
{
|
|
|
|
|
let version = self.resources.read().unwrap().version();
|
|
|
|
|
if self.version != version {
|
|
|
|
|
self.version = version;
|
|
|
|
|
self.load_font();
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-20 16:17:21 -04:00
|
|
|
|
// Prevent clipping with the world
|
2015-10-07 14:36:59 -04:00
|
|
|
|
gl::clear(gl::ClearFlags::Depth);
|
|
|
|
|
gl::enable(gl::BLEND);
|
|
|
|
|
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
|
|
|
|
self.shader.program.use_program();
|
|
|
|
|
self.shader.texture.set_int(0);
|
|
|
|
|
if self.count > 0 {
|
|
|
|
|
self.array.bind();
|
|
|
|
|
if self.max_index < self.count {
|
|
|
|
|
let (data, ty) = render::generate_element_buffer(self.count);
|
|
|
|
|
self.index_type = ty;
|
|
|
|
|
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
2020-06-21 15:17:24 -04:00
|
|
|
|
self.index_buffer
|
|
|
|
|
.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
self.max_index = self.count;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
|
self.shader
|
|
|
|
|
.screensize
|
|
|
|
|
.set_float2(width as f32, height as f32);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
|
|
|
|
|
self.buffer.bind(gl::ARRAY_BUFFER);
|
2016-03-19 13:34:12 -04:00
|
|
|
|
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
if self.data.len() > self.prev_size {
|
|
|
|
|
self.prev_size = self.data.len();
|
2020-06-21 15:17:24 -04:00
|
|
|
|
self.buffer
|
|
|
|
|
.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
} else {
|
2016-03-19 16:35:31 -04:00
|
|
|
|
self.buffer.re_set_data(gl::ARRAY_BUFFER, &self.data);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
}
|
2016-03-27 18:31:57 -04:00
|
|
|
|
gl::draw_elements(gl::TRIANGLES, self.count as i32, self.index_type, 0);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gl::disable(gl::BLEND);
|
|
|
|
|
self.data.clear();
|
|
|
|
|
self.count = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-26 10:24:26 -04:00
|
|
|
|
pub fn add_bytes(&mut self, data: &[u8]) {
|
|
|
|
|
self.data.extend_from_slice(data);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
self.count += (data.len() / (28 * 4)) * 6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn character_texture(&mut self, c: char) -> render::Texture {
|
|
|
|
|
let raw = c as u32;
|
|
|
|
|
let page = raw >> 8;
|
2016-03-20 16:17:21 -04:00
|
|
|
|
// Lazy load fonts to size memory
|
2015-10-07 14:36:59 -04:00
|
|
|
|
if self.font_pages[page as usize].is_none() {
|
|
|
|
|
let name = if page == 0 {
|
|
|
|
|
"font/ascii".to_owned()
|
|
|
|
|
} else {
|
|
|
|
|
format!("font/unicode_page_{:02X}", page)
|
|
|
|
|
};
|
|
|
|
|
let textures = self.textures.clone();
|
|
|
|
|
self.font_pages[page as usize] = Some(render::Renderer::get_texture(&textures, &name));
|
|
|
|
|
}
|
|
|
|
|
let p = self.font_pages[page as usize].clone().unwrap();
|
|
|
|
|
|
|
|
|
|
let raw = if page == 0 {
|
|
|
|
|
(*self.char_map.get(&c).unwrap_or(&c)) as u32
|
|
|
|
|
} else {
|
|
|
|
|
raw
|
|
|
|
|
};
|
|
|
|
|
let ch = raw & 0xFF;
|
|
|
|
|
let cx = ch & 0xF;
|
|
|
|
|
let cy = ch >> 4;
|
|
|
|
|
let info = self.font_character_info[raw as usize];
|
|
|
|
|
if page == 0 {
|
|
|
|
|
let sw = (self.page_width / 16.0) as u32;
|
|
|
|
|
let sh = (self.page_height / 16.0) as u32;
|
2020-06-21 15:17:24 -04:00
|
|
|
|
return p.relative(
|
|
|
|
|
(cx * sw + info.0 as u32) as f32 / (self.page_width as f32),
|
|
|
|
|
(cy * sh) as f32 / (self.page_height as f32),
|
|
|
|
|
(info.1 - info.0) as f32 / (self.page_width as f32),
|
|
|
|
|
(sh as f32) / (self.page_height as f32),
|
|
|
|
|
);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
}
|
2020-06-21 15:17:24 -04:00
|
|
|
|
p.relative(
|
|
|
|
|
(cx * 16 + info.0 as u32) as f32 / 256.0,
|
|
|
|
|
(cy * 16) as f32 / 256.0,
|
|
|
|
|
(info.1 - info.0) as f32 / 256.0,
|
|
|
|
|
16.0 / 256.0,
|
|
|
|
|
)
|
2015-10-07 14:36:59 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn size_of_string(&self, val: &str) -> f64 {
|
|
|
|
|
let mut size = 0.0;
|
|
|
|
|
for c in val.chars() {
|
|
|
|
|
size += self.size_of_char(c) + 2.0;
|
|
|
|
|
}
|
|
|
|
|
size - 2.0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn size_of_char(&self, c: char) -> f64 {
|
|
|
|
|
if c == ' ' {
|
|
|
|
|
return 4.0;
|
|
|
|
|
}
|
|
|
|
|
let r = c as u32;
|
|
|
|
|
if r >> 8 == 0 {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
let info = self.font_character_info[c as usize];
|
|
|
|
|
(info.1 - info.0) as f64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn load_font(&mut self) {
|
|
|
|
|
for page in &mut self.font_pages {
|
|
|
|
|
*page = None;
|
|
|
|
|
}
|
|
|
|
|
let res = self.resources.read().unwrap();
|
|
|
|
|
if let Some(mut info) = res.open("minecraft", "font/glyph_sizes.bin") {
|
|
|
|
|
let mut data = Vec::with_capacity(0x10000);
|
|
|
|
|
info.read_to_end(&mut data).unwrap();
|
|
|
|
|
for (i, info) in self.font_character_info.iter_mut().enumerate() {
|
2016-03-20 16:17:21 -04:00
|
|
|
|
// Top nibble - start position
|
|
|
|
|
// Bottom nibble - end position
|
2015-10-07 14:36:59 -04:00
|
|
|
|
info.0 = (data[i] >> 4) as i32;
|
|
|
|
|
info.1 = (data[i] & 0xF) as i32 + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if let Some(mut val) = res.open("minecraft", "textures/font/ascii.png") {
|
|
|
|
|
let mut data = Vec::new();
|
|
|
|
|
val.read_to_end(&mut data).unwrap();
|
|
|
|
|
if let Ok(img) = image::load_from_memory(&data) {
|
|
|
|
|
let (width, height) = img.dimensions();
|
|
|
|
|
self.page_width = width as f64;
|
|
|
|
|
self.page_height = height as f64;
|
|
|
|
|
let sw = width / 16;
|
|
|
|
|
let sh = height / 16;
|
|
|
|
|
for i in 0..256 {
|
|
|
|
|
let cx = (i & 0xF) * sw;
|
|
|
|
|
let cy = (i >> 4) * sh;
|
|
|
|
|
let mut start = true;
|
|
|
|
|
'x_loop: for x in 0..sw {
|
|
|
|
|
for y in 0..sh {
|
2020-01-05 12:10:59 -05:00
|
|
|
|
let a = img.get_pixel(cx + x, cy + y).0[3];
|
2015-10-07 14:36:59 -04:00
|
|
|
|
if start && a != 0 {
|
|
|
|
|
self.font_character_info[i as usize].0 = x as i32;
|
|
|
|
|
start = false;
|
|
|
|
|
continue 'x_loop;
|
|
|
|
|
} else if !start && a != 0 {
|
|
|
|
|
continue 'x_loop;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !start {
|
|
|
|
|
self.font_character_info[i as usize].1 = x as i32;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new_text(&mut self, val: &str, x: f64, y: f64, r: u8, g: u8, b: u8) -> UIText {
|
|
|
|
|
self.new_text_scaled(val, x, y, 1.0, 1.0, r, g, b)
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
|
pub fn new_text_scaled(
|
|
|
|
|
&mut self,
|
|
|
|
|
val: &str,
|
|
|
|
|
x: f64,
|
|
|
|
|
y: f64,
|
|
|
|
|
sx: f64,
|
|
|
|
|
sy: f64,
|
|
|
|
|
r: u8,
|
|
|
|
|
g: u8,
|
|
|
|
|
b: u8,
|
|
|
|
|
) -> UIText {
|
2015-10-07 14:36:59 -04:00
|
|
|
|
self.create_text(val, x, y, sx, sy, 0.0, r, g, b)
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
|
pub fn new_text_rotated(
|
|
|
|
|
&mut self,
|
|
|
|
|
val: &str,
|
|
|
|
|
x: f64,
|
|
|
|
|
y: f64,
|
|
|
|
|
sx: f64,
|
|
|
|
|
sy: f64,
|
|
|
|
|
rotation: f64,
|
|
|
|
|
r: u8,
|
|
|
|
|
g: u8,
|
|
|
|
|
b: u8,
|
|
|
|
|
) -> UIText {
|
2015-10-07 14:36:59 -04:00
|
|
|
|
self.create_text(val, x, y, sx, sy, rotation, r, g, b)
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
|
fn create_text(
|
|
|
|
|
&mut self,
|
|
|
|
|
val: &str,
|
|
|
|
|
x: f64,
|
|
|
|
|
y: f64,
|
|
|
|
|
sx: f64,
|
|
|
|
|
sy: f64,
|
|
|
|
|
rotation: f64,
|
|
|
|
|
r: u8,
|
|
|
|
|
g: u8,
|
|
|
|
|
b: u8,
|
|
|
|
|
) -> UIText {
|
2015-10-07 14:36:59 -04:00
|
|
|
|
let mut elements = Vec::new();
|
|
|
|
|
let mut offset = 0.0;
|
|
|
|
|
for ch in val.chars() {
|
|
|
|
|
if ch == ' ' {
|
|
|
|
|
offset += 6.0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
let texture = self.character_texture(ch);
|
|
|
|
|
let w = self.size_of_char(ch);
|
|
|
|
|
|
|
|
|
|
let mut dsx = offset + 2.0;
|
|
|
|
|
let mut dsy = 2.0;
|
|
|
|
|
let mut dx = offset;
|
|
|
|
|
let mut dy = 0.0;
|
|
|
|
|
if rotation != 0.0 {
|
|
|
|
|
let c = rotation.cos();
|
|
|
|
|
let s = rotation.sin();
|
|
|
|
|
let tmpx = dsx - (w * 0.5);
|
|
|
|
|
let tmpy = dsy - (16.0 * 0.5);
|
|
|
|
|
dsx = (w * 0.5) + (tmpx * c - tmpy * s);
|
|
|
|
|
dsy = (16.0 * 0.5) + (tmpy * c + tmpx * s);
|
|
|
|
|
let tmpx = dx - (w * 0.5);
|
|
|
|
|
let tmpy = dy - (16.0 * 0.5);
|
|
|
|
|
dx = (w * 0.5) + (tmpx * c - tmpy * s);
|
|
|
|
|
dy = (16.0 * 0.5) + (tmpy * c + tmpx * s);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
|
let mut shadow = UIElement::new(
|
|
|
|
|
&texture,
|
|
|
|
|
x + dsx * sx,
|
|
|
|
|
y + dsy * sy,
|
|
|
|
|
w * sx,
|
|
|
|
|
16.0 * sy,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
1.0,
|
|
|
|
|
1.0,
|
|
|
|
|
);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
shadow.r = ((r as f64) * 0.25) as u8;
|
|
|
|
|
shadow.g = ((g as f64) * 0.25) as u8;
|
|
|
|
|
shadow.b = ((b as f64) * 0.25) as u8;
|
|
|
|
|
shadow.rotation = rotation;
|
|
|
|
|
elements.push(shadow);
|
|
|
|
|
|
2020-06-21 15:17:24 -04:00
|
|
|
|
let mut text = UIElement::new(
|
|
|
|
|
&texture,
|
|
|
|
|
x + dx * sx,
|
|
|
|
|
y + dy * sy,
|
|
|
|
|
w * sx,
|
|
|
|
|
16.0 * sy,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
1.0,
|
|
|
|
|
1.0,
|
|
|
|
|
);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
text.r = r;
|
|
|
|
|
text.g = g;
|
|
|
|
|
text.b = b;
|
|
|
|
|
text.rotation = rotation;
|
|
|
|
|
elements.push(text);
|
|
|
|
|
offset += w + 2.0;
|
|
|
|
|
}
|
|
|
|
|
UIText {
|
2018-11-04 16:43:30 -05:00
|
|
|
|
elements,
|
2015-10-07 14:36:59 -04:00
|
|
|
|
width: (offset - 2.0) * sx,
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-17 11:04:25 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct UIText {
|
2015-10-07 14:36:59 -04:00
|
|
|
|
pub elements: Vec<UIElement>,
|
|
|
|
|
pub width: f64,
|
2015-09-17 11:04:25 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl UIText {
|
2015-10-07 14:36:59 -04:00
|
|
|
|
pub fn bytes(&self, width: f64, height: f64) -> Vec<u8> {
|
|
|
|
|
let mut buf = Vec::with_capacity(28 * 4 * self.elements.len());
|
|
|
|
|
for e in &self.elements {
|
|
|
|
|
buf.extend(e.bytes(width, height));
|
|
|
|
|
}
|
|
|
|
|
buf
|
|
|
|
|
}
|
2015-09-17 11:04:25 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct UIElement {
|
2015-10-07 14:36:59 -04:00
|
|
|
|
pub x: f64,
|
|
|
|
|
pub y: f64,
|
|
|
|
|
pub w: f64,
|
|
|
|
|
pub h: f64,
|
|
|
|
|
pub layer: isize,
|
|
|
|
|
pub t_x: u16,
|
|
|
|
|
pub t_y: u16,
|
|
|
|
|
pub t_w: u16,
|
|
|
|
|
pub t_h: u16,
|
|
|
|
|
pub t_offsetx: i16,
|
|
|
|
|
pub t_offsety: i16,
|
|
|
|
|
pub t_atlas: i16,
|
|
|
|
|
pub t_sizew: i16,
|
|
|
|
|
pub t_sizeh: i16,
|
|
|
|
|
pub r: u8,
|
|
|
|
|
pub g: u8,
|
|
|
|
|
pub b: u8,
|
|
|
|
|
pub a: u8,
|
|
|
|
|
pub rotation: f64,
|
2015-09-17 11:04:25 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl UIElement {
|
2020-06-21 15:17:24 -04:00
|
|
|
|
pub fn new(
|
|
|
|
|
tex: &render::Texture,
|
|
|
|
|
x: f64,
|
|
|
|
|
y: f64,
|
|
|
|
|
width: f64,
|
|
|
|
|
height: f64,
|
|
|
|
|
tx: f64,
|
|
|
|
|
ty: f64,
|
|
|
|
|
tw: f64,
|
|
|
|
|
th: f64,
|
|
|
|
|
) -> UIElement {
|
2015-10-07 14:36:59 -04:00
|
|
|
|
let twidth = tex.get_width();
|
|
|
|
|
let theight = tex.get_height();
|
|
|
|
|
UIElement {
|
|
|
|
|
x: x / UI_WIDTH,
|
|
|
|
|
y: y / UI_HEIGHT,
|
|
|
|
|
w: width / UI_WIDTH,
|
|
|
|
|
h: height / UI_HEIGHT,
|
|
|
|
|
layer: 0,
|
|
|
|
|
t_x: tex.get_x() as u16,
|
|
|
|
|
t_y: tex.get_y() as u16,
|
|
|
|
|
t_w: twidth as u16,
|
|
|
|
|
t_h: theight as u16,
|
|
|
|
|
t_atlas: tex.atlas as i16,
|
|
|
|
|
t_offsetx: (tx * (twidth as f64) * 16.0) as i16,
|
|
|
|
|
t_offsety: (ty * (theight as f64) * 16.0) as i16,
|
|
|
|
|
t_sizew: (tw * (twidth as f64) * 16.0) as i16,
|
|
|
|
|
t_sizeh: (th * (theight as f64) * 16.0) as i16,
|
|
|
|
|
r: 255,
|
|
|
|
|
g: 255,
|
|
|
|
|
b: 255,
|
|
|
|
|
a: 255,
|
|
|
|
|
rotation: 0.0,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn bytes(&self, width: f64, height: f64) -> Vec<u8> {
|
|
|
|
|
let mut buf = Vec::with_capacity(28 * 4);
|
2020-06-21 15:17:24 -04:00
|
|
|
|
self.append_vertex(
|
|
|
|
|
&mut buf,
|
|
|
|
|
self.x,
|
|
|
|
|
self.y,
|
|
|
|
|
self.t_offsetx,
|
|
|
|
|
self.t_offsety,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
);
|
|
|
|
|
self.append_vertex(
|
|
|
|
|
&mut buf,
|
|
|
|
|
self.x + self.w,
|
|
|
|
|
self.y,
|
|
|
|
|
self.t_offsetx + self.t_sizew,
|
|
|
|
|
self.t_offsety,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
);
|
|
|
|
|
self.append_vertex(
|
|
|
|
|
&mut buf,
|
|
|
|
|
self.x,
|
|
|
|
|
self.y + self.h,
|
|
|
|
|
self.t_offsetx,
|
|
|
|
|
self.t_offsety + self.t_sizeh,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
);
|
|
|
|
|
self.append_vertex(
|
|
|
|
|
&mut buf,
|
|
|
|
|
self.x + self.w,
|
|
|
|
|
self.y + self.h,
|
|
|
|
|
self.t_offsetx + self.t_sizew,
|
|
|
|
|
self.t_offsety + self.t_sizeh,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
);
|
2015-10-07 14:36:59 -04:00
|
|
|
|
buf
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(unused_must_use)]
|
2020-06-21 15:17:24 -04:00
|
|
|
|
pub fn append_vertex(
|
|
|
|
|
&self,
|
|
|
|
|
buf: &mut Vec<u8>,
|
|
|
|
|
x: f64,
|
|
|
|
|
y: f64,
|
|
|
|
|
tx: i16,
|
|
|
|
|
ty: i16,
|
|
|
|
|
width: f64,
|
|
|
|
|
height: f64,
|
|
|
|
|
) {
|
2015-10-07 14:36:59 -04:00
|
|
|
|
let mut dx = x as f64;
|
|
|
|
|
let mut dy = y as f64;
|
|
|
|
|
if self.rotation != 0.0 {
|
|
|
|
|
let c = self.rotation.cos();
|
|
|
|
|
let s = self.rotation.sin();
|
|
|
|
|
let tmpx = dx - self.x - (self.w / 2.0);
|
|
|
|
|
let tmpy = dy - self.y - (self.h / 2.0);
|
|
|
|
|
dx = (self.w / 2.0) + (tmpx * c - tmpy * s) + self.x;
|
|
|
|
|
dy = (self.h / 2.0) + (tmpy * c + tmpx * s) + self.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buf.write_i16::<NativeEndian>((dx * width + 0.5).floor() as i16);
|
|
|
|
|
buf.write_i16::<NativeEndian>((dy * height + 0.5).floor() as i16);
|
|
|
|
|
buf.write_i16::<NativeEndian>((self.layer * 256) as i16);
|
|
|
|
|
buf.write_i16::<NativeEndian>(0);
|
|
|
|
|
buf.write_u16::<NativeEndian>(self.t_x);
|
|
|
|
|
buf.write_u16::<NativeEndian>(self.t_y);
|
|
|
|
|
buf.write_u16::<NativeEndian>(self.t_w);
|
|
|
|
|
buf.write_u16::<NativeEndian>(self.t_h);
|
|
|
|
|
buf.write_i16::<NativeEndian>(tx);
|
|
|
|
|
buf.write_i16::<NativeEndian>(ty);
|
|
|
|
|
buf.write_i16::<NativeEndian>(self.t_atlas);
|
|
|
|
|
buf.write_i16::<NativeEndian>(0);
|
|
|
|
|
buf.write_u8(self.r);
|
|
|
|
|
buf.write_u8(self.g);
|
|
|
|
|
buf.write_u8(self.b);
|
|
|
|
|
buf.write_u8(self.a);
|
|
|
|
|
}
|
|
|
|
|
}
|