Impl title and artist display with existing
This commit is contained in:
parent
f9ff594437
commit
05aa505694
1 changed files with 171 additions and 35 deletions
202
src/main.rs
202
src/main.rs
|
@ -11,12 +11,12 @@ use std::time::{Duration, Instant};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
const POLL_DURATION: Duration = Duration::from_secs(2);
|
const POLL_DURATION: Duration = Duration::from_secs(2);
|
||||||
const TITLE_X_OFFSET: f32 = 20.0f32;
|
const TEXT_X_OFFSET: f32 = 16.0f32;
|
||||||
const TITLE_Y_OFFSET: f32 = 20.0f32;
|
const TEXT_Y_OFFSET: f32 = 16.0f32;
|
||||||
const TIMER_X_OFFSET: f32 = 20.0f32;
|
|
||||||
const TIMER_Y_OFFSET: f32 = 20.0f32;
|
|
||||||
const TIME_MAX_DIFF: f64 = 2.0f64;
|
const TIME_MAX_DIFF: f64 = 2.0f64;
|
||||||
const INITIAL_FONT_SIZE: u16 = 96;
|
const INITIAL_FONT_SIZE: u16 = 96;
|
||||||
|
const ARTIST_INITIAL_FONT_SIZE: u16 = 48;
|
||||||
|
const TIMER_FONT_SIZE: u16 = 64;
|
||||||
const SCREEN_DIFF_MARGIN: f32 = 1.0;
|
const SCREEN_DIFF_MARGIN: f32 = 1.0;
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
|
@ -27,12 +27,20 @@ struct Opt {
|
||||||
port: u16,
|
port: u16,
|
||||||
#[structopt(short = "p")]
|
#[structopt(short = "p")]
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
|
#[structopt(long = "disable-show-title")]
|
||||||
|
disable_show_title: bool,
|
||||||
|
#[structopt(long = "disable-show-artist")]
|
||||||
|
disable_show_artist: bool,
|
||||||
|
#[structopt(long = "disable-show-filename")]
|
||||||
|
disable_show_filename: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Shared {
|
struct Shared {
|
||||||
art_data: Vec<u8>,
|
art_data: Vec<u8>,
|
||||||
art_data_size: usize,
|
art_data_size: usize,
|
||||||
current_song: String,
|
current_song_filename: String,
|
||||||
|
current_song_title: String,
|
||||||
|
current_song_artist: String,
|
||||||
current_song_length: f64,
|
current_song_length: f64,
|
||||||
current_song_position: f64,
|
current_song_position: f64,
|
||||||
current_song_pos_rec: Instant,
|
current_song_pos_rec: Instant,
|
||||||
|
@ -51,7 +59,9 @@ impl Shared {
|
||||||
Self {
|
Self {
|
||||||
art_data: Vec::new(),
|
art_data: Vec::new(),
|
||||||
art_data_size: 0,
|
art_data_size: 0,
|
||||||
current_song: String::new(),
|
current_song_filename: String::new(),
|
||||||
|
current_song_title: String::new(),
|
||||||
|
current_song_artist: String::new(),
|
||||||
current_song_length: 0.0,
|
current_song_length: 0.0,
|
||||||
current_song_position: 0.0,
|
current_song_position: 0.0,
|
||||||
current_song_pos_rec: Instant::now(),
|
current_song_pos_rec: Instant::now(),
|
||||||
|
@ -79,7 +89,9 @@ enum PollState {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct InfoFromShared {
|
struct InfoFromShared {
|
||||||
|
filename: String,
|
||||||
title: String,
|
title: String,
|
||||||
|
artist: String,
|
||||||
length: f64,
|
length: f64,
|
||||||
pos: f64,
|
pos: f64,
|
||||||
instant_rec: Instant,
|
instant_rec: Instant,
|
||||||
|
@ -367,13 +379,15 @@ fn info_loop(shared_data: Arc<Mutex<Shared>>) -> Result<(), String> {
|
||||||
poll_state = PollState::None;
|
poll_state = PollState::None;
|
||||||
} else if line.starts_with("file: ") {
|
} else if line.starts_with("file: ") {
|
||||||
let song_file = line.split_off(6);
|
let song_file = line.split_off(6);
|
||||||
if song_file != lock.current_song {
|
if song_file != lock.current_song_filename {
|
||||||
lock.current_song = song_file;
|
lock.current_song_filename = song_file;
|
||||||
lock.art_data.clear();
|
lock.art_data.clear();
|
||||||
lock.art_data_size = 0;
|
lock.art_data_size = 0;
|
||||||
lock.can_get_album_art = true;
|
lock.can_get_album_art = true;
|
||||||
lock.can_get_album_art_in_dir = true;
|
lock.can_get_album_art_in_dir = true;
|
||||||
//println!("Got different song file, clearing art_data...");
|
//println!("Got different song file, clearing art_data...");
|
||||||
|
lock.current_song_title.clear();
|
||||||
|
lock.current_song_artist.clear();
|
||||||
}
|
}
|
||||||
lock.dirty = true;
|
lock.dirty = true;
|
||||||
song_title_get_time = Instant::now();
|
song_title_get_time = Instant::now();
|
||||||
|
@ -406,6 +420,10 @@ fn info_loop(shared_data: Arc<Mutex<Shared>>) -> Result<(), String> {
|
||||||
if let Ok(value) = parse_artbinarysize_result {
|
if let Ok(value) = parse_artbinarysize_result {
|
||||||
current_binary_size = value;
|
current_binary_size = value;
|
||||||
}
|
}
|
||||||
|
} else if line.starts_with("Title: ") {
|
||||||
|
lock.current_song_title = line.split_off(7);
|
||||||
|
} else if line.starts_with("Artist: ") {
|
||||||
|
lock.current_song_artist = line.split_off(8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let Err((msg, read_line_in_progress)) = read_line_result {
|
} else if let Err((msg, read_line_in_progress)) = read_line_result {
|
||||||
|
@ -452,9 +470,9 @@ fn info_loop(shared_data: Arc<Mutex<Shared>>) -> Result<(), String> {
|
||||||
poll_state = PollState::Status;
|
poll_state = PollState::Status;
|
||||||
}
|
}
|
||||||
} else if (lock.art_data.is_empty() || lock.art_data.len() != lock.art_data_size)
|
} else if (lock.art_data.is_empty() || lock.art_data.len() != lock.art_data_size)
|
||||||
&& !lock.current_song.is_empty()
|
&& !lock.current_song_filename.is_empty()
|
||||||
{
|
{
|
||||||
let title = lock.current_song.clone();
|
let title = lock.current_song_filename.clone();
|
||||||
let art_data_length = lock.art_data.len();
|
let art_data_length = lock.art_data.len();
|
||||||
if lock.can_get_album_art {
|
if lock.can_get_album_art {
|
||||||
let write_result = lock.stream.write(
|
let write_result = lock.stream.write(
|
||||||
|
@ -464,6 +482,7 @@ fn info_loop(shared_data: Arc<Mutex<Shared>>) -> Result<(), String> {
|
||||||
println!("Got error requesting albumart: {}", e);
|
println!("Got error requesting albumart: {}", e);
|
||||||
} else {
|
} else {
|
||||||
poll_state = PollState::ReadPicture;
|
poll_state = PollState::ReadPicture;
|
||||||
|
//println!("polling readpicture");
|
||||||
}
|
}
|
||||||
} else if lock.can_get_album_art_in_dir {
|
} else if lock.can_get_album_art_in_dir {
|
||||||
let write_result = lock.stream.write(
|
let write_result = lock.stream.write(
|
||||||
|
@ -473,11 +492,12 @@ fn info_loop(shared_data: Arc<Mutex<Shared>>) -> Result<(), String> {
|
||||||
println!("Got error requesting albumart in dir: {}", e);
|
println!("Got error requesting albumart in dir: {}", e);
|
||||||
} else {
|
} else {
|
||||||
poll_state = PollState::ReadPictureInDir;
|
poll_state = PollState::ReadPictureInDir;
|
||||||
|
//println!("polling readpictureindir");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("Failed to acquire lock for writing to stream");
|
println!("INFO: Temporarily failed to acquire lock for writing to stream");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO DEBUG
|
// TODO DEBUG
|
||||||
|
@ -493,18 +513,22 @@ fn get_info_from_shared(
|
||||||
shared: Arc<Mutex<Shared>>,
|
shared: Arc<Mutex<Shared>>,
|
||||||
force_check: bool,
|
force_check: bool,
|
||||||
) -> Result<InfoFromShared, String> {
|
) -> Result<InfoFromShared, String> {
|
||||||
|
let mut filename: String = String::new();
|
||||||
let mut title: String = String::new();
|
let mut title: String = String::new();
|
||||||
|
let mut artist: String = String::new();
|
||||||
let mut length: f64 = 0.0;
|
let mut length: f64 = 0.0;
|
||||||
let mut pos: f64 = 0.0;
|
let mut pos: f64 = 0.0;
|
||||||
let mut instant_rec: Instant = Instant::now();
|
let mut instant_rec: Instant = Instant::now();
|
||||||
let mut error_text = String::new();
|
let mut error_text = String::new();
|
||||||
if let Ok(mut lock) = shared.lock() {
|
if let Ok(mut lock) = shared.lock() {
|
||||||
if lock.dirty || force_check {
|
if lock.dirty || force_check {
|
||||||
title = lock.current_song.clone();
|
filename = lock.current_song_filename.clone();
|
||||||
|
title = lock.current_song_title.clone();
|
||||||
|
artist = lock.current_song_artist.clone();
|
||||||
length = lock.current_song_length;
|
length = lock.current_song_length;
|
||||||
pos = lock.current_song_position;
|
pos = lock.current_song_position;
|
||||||
instant_rec = lock.current_song_pos_rec;
|
instant_rec = lock.current_song_pos_rec;
|
||||||
//println!("Current song: {}", lock.current_song);
|
//println!("Current song: {}", lock.current_song_filename);
|
||||||
//println!("Current song length: {}", lock.current_song_length);
|
//println!("Current song length: {}", lock.current_song_length);
|
||||||
//println!("Current song position: {}", lock.current_song_position);
|
//println!("Current song position: {}", lock.current_song_position);
|
||||||
if !lock.can_authenticate {
|
if !lock.can_authenticate {
|
||||||
|
@ -521,7 +545,9 @@ fn get_info_from_shared(
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(InfoFromShared {
|
Ok(InfoFromShared {
|
||||||
|
filename,
|
||||||
title,
|
title,
|
||||||
|
artist,
|
||||||
length,
|
length,
|
||||||
pos,
|
pos,
|
||||||
instant_rec,
|
instant_rec,
|
||||||
|
@ -591,13 +617,20 @@ async fn main() -> Result<(), String> {
|
||||||
let wait_time: f64 = 0.75;
|
let wait_time: f64 = 0.75;
|
||||||
let mut timer: f64 = 0.0;
|
let mut timer: f64 = 0.0;
|
||||||
let mut track_timer: f64 = 0.0;
|
let mut track_timer: f64 = 0.0;
|
||||||
|
let mut filename: String = String::new();
|
||||||
let mut title: String = String::new();
|
let mut title: String = String::new();
|
||||||
|
let mut artist: String = String::new();
|
||||||
let mut art_texture: Option<Texture2D> = None;
|
let mut art_texture: Option<Texture2D> = None;
|
||||||
let mut filename_font_size: Option<u16> = None;
|
let mut filename_font_size: Option<u16> = None;
|
||||||
let mut text_dim: TextDimensions = measure_text("undefined", None, 24, 1.0);
|
let mut text_dim: TextDimensions = measure_text("undefined", None, 24, 1.0);
|
||||||
let mut prev_width = screen_width();
|
let mut prev_width = screen_width();
|
||||||
let mut prev_height = screen_height();
|
let mut prev_height = screen_height();
|
||||||
let mut error_text = String::new();
|
let mut error_text = String::new();
|
||||||
|
let mut title_dim_opt: Option<TextDimensions> = None;
|
||||||
|
let mut title_font_size: u16 = INITIAL_FONT_SIZE;
|
||||||
|
let mut artist_dim_opt: Option<TextDimensions> = None;
|
||||||
|
let mut artist_font_size: u16 = ARTIST_INITIAL_FONT_SIZE;
|
||||||
|
let mut temp_offset_y: f32;
|
||||||
|
|
||||||
'macroquad_main: loop {
|
'macroquad_main: loop {
|
||||||
let dt: f64 = get_frame_time() as f64;
|
let dt: f64 = get_frame_time() as f64;
|
||||||
|
@ -611,6 +644,8 @@ async fn main() -> Result<(), String> {
|
||||||
prev_width = screen_width();
|
prev_width = screen_width();
|
||||||
prev_height = screen_height();
|
prev_height = screen_height();
|
||||||
filename_font_size = None;
|
filename_font_size = None;
|
||||||
|
title_dim_opt = None;
|
||||||
|
artist_dim_opt = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
timer -= dt;
|
timer -= dt;
|
||||||
|
@ -619,10 +654,14 @@ async fn main() -> Result<(), String> {
|
||||||
timer = wait_time;
|
timer = wait_time;
|
||||||
let info_result = get_info_from_shared(shared_data.clone(), false);
|
let info_result = get_info_from_shared(shared_data.clone(), false);
|
||||||
if let Ok(info) = info_result {
|
if let Ok(info) = info_result {
|
||||||
if info.title != title {
|
if info.filename != filename {
|
||||||
title = info.title;
|
filename = info.filename;
|
||||||
art_texture = None;
|
art_texture = None;
|
||||||
filename_font_size = None;
|
filename_font_size = None;
|
||||||
|
title.clear();
|
||||||
|
title_dim_opt = None;
|
||||||
|
artist.clear();
|
||||||
|
artist_dim_opt = None;
|
||||||
}
|
}
|
||||||
let duration_since = info.instant_rec.elapsed();
|
let duration_since = info.instant_rec.elapsed();
|
||||||
let recorded_time = info.length - info.pos - duration_since.as_secs_f64();
|
let recorded_time = info.length - info.pos - duration_since.as_secs_f64();
|
||||||
|
@ -632,6 +671,12 @@ async fn main() -> Result<(), String> {
|
||||||
if !info.error_text.is_empty() {
|
if !info.error_text.is_empty() {
|
||||||
error_text = info.error_text;
|
error_text = info.error_text;
|
||||||
}
|
}
|
||||||
|
if !info.title.is_empty() {
|
||||||
|
title = info.title;
|
||||||
|
}
|
||||||
|
if !info.artist.is_empty() {
|
||||||
|
artist = info.artist;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if art_texture.is_none() {
|
if art_texture.is_none() {
|
||||||
|
@ -692,13 +737,18 @@ async fn main() -> Result<(), String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !title.is_empty() {
|
temp_offset_y = 0.0;
|
||||||
|
if !filename.is_empty() && !opt.disable_show_filename {
|
||||||
if filename_font_size.is_none() {
|
if filename_font_size.is_none() {
|
||||||
filename_font_size = Some(INITIAL_FONT_SIZE);
|
filename_font_size = Some(INITIAL_FONT_SIZE);
|
||||||
loop {
|
loop {
|
||||||
text_dim =
|
text_dim = measure_text(
|
||||||
measure_text(&title, None, *filename_font_size.as_ref().unwrap(), 1.0f32);
|
&filename,
|
||||||
if text_dim.width + TITLE_X_OFFSET > prev_width {
|
None,
|
||||||
|
*filename_font_size.as_ref().unwrap(),
|
||||||
|
1.0f32,
|
||||||
|
);
|
||||||
|
if text_dim.width + TEXT_X_OFFSET > prev_width {
|
||||||
filename_font_size = filename_font_size.map(|s| s - 4);
|
filename_font_size = filename_font_size.map(|s| s - 4);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -707,7 +757,7 @@ async fn main() -> Result<(), String> {
|
||||||
if *filename_font_size.as_ref().unwrap() <= 4 {
|
if *filename_font_size.as_ref().unwrap() <= 4 {
|
||||||
filename_font_size = Some(4);
|
filename_font_size = Some(4);
|
||||||
text_dim = measure_text(
|
text_dim = measure_text(
|
||||||
&title,
|
&filename,
|
||||||
None,
|
None,
|
||||||
*filename_font_size.as_ref().unwrap(),
|
*filename_font_size.as_ref().unwrap(),
|
||||||
1.0f32,
|
1.0f32,
|
||||||
|
@ -717,37 +767,123 @@ async fn main() -> Result<(), String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
draw_rectangle(
|
draw_rectangle(
|
||||||
TITLE_X_OFFSET,
|
TEXT_X_OFFSET,
|
||||||
prev_height - TITLE_Y_OFFSET - text_dim.height,
|
prev_height - TEXT_Y_OFFSET - text_dim.height,
|
||||||
text_dim.width,
|
text_dim.width,
|
||||||
text_dim.height,
|
text_dim.height,
|
||||||
Color::new(0.0, 0.0, 0.0, 0.4),
|
Color::new(0.0, 0.0, 0.0, 0.4),
|
||||||
);
|
);
|
||||||
draw_text(
|
draw_text(
|
||||||
&title,
|
&filename,
|
||||||
TITLE_X_OFFSET,
|
TEXT_X_OFFSET,
|
||||||
prev_height - TITLE_Y_OFFSET,
|
prev_height - TEXT_Y_OFFSET,
|
||||||
*filename_font_size.as_ref().unwrap() as f32,
|
*filename_font_size.as_ref().unwrap() as f32,
|
||||||
WHITE,
|
WHITE,
|
||||||
);
|
);
|
||||||
|
|
||||||
let timer_string = seconds_to_time(track_timer);
|
temp_offset_y += TEXT_Y_OFFSET + text_dim.height;
|
||||||
let timer_dim = measure_text(&timer_string, None, 64, 1.0f32);
|
}
|
||||||
|
|
||||||
|
// Get title dimensions early so that artist size is at most title size
|
||||||
|
if !title.is_empty() && !opt.disable_show_title && title_dim_opt.is_none() {
|
||||||
|
title_font_size = INITIAL_FONT_SIZE;
|
||||||
|
loop {
|
||||||
|
title_dim_opt = Some(measure_text(&title, None, title_font_size, 1.0f32));
|
||||||
|
if title_dim_opt.as_ref().unwrap().width + TEXT_X_OFFSET > prev_width {
|
||||||
|
title_font_size -= 4;
|
||||||
|
if title_font_size < 4 {
|
||||||
|
title_font_size = 4;
|
||||||
|
title_dim_opt = Some(measure_text(&title, None, title_font_size, 1.0f32));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !artist.is_empty() && !opt.disable_show_artist {
|
||||||
|
if artist_dim_opt.is_none() {
|
||||||
|
if !title.is_empty() && !opt.disable_show_title {
|
||||||
|
artist_font_size = title_font_size;
|
||||||
|
} else {
|
||||||
|
artist_font_size = ARTIST_INITIAL_FONT_SIZE;
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
artist_dim_opt = Some(measure_text(&artist, None, artist_font_size, 1.0f32));
|
||||||
|
if artist_dim_opt.as_ref().unwrap().width + TEXT_X_OFFSET > prev_width {
|
||||||
|
artist_font_size -= 4;
|
||||||
|
if artist_font_size < 4 {
|
||||||
|
artist_font_size = 4;
|
||||||
|
artist_dim_opt =
|
||||||
|
Some(measure_text(&artist, None, artist_font_size, 1.0f32));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
draw_rectangle(
|
draw_rectangle(
|
||||||
TIMER_X_OFFSET,
|
TEXT_X_OFFSET,
|
||||||
prev_height - TITLE_Y_OFFSET - text_dim.height - TIMER_Y_OFFSET - timer_dim.height,
|
prev_height
|
||||||
|
- temp_offset_y
|
||||||
|
- TEXT_Y_OFFSET
|
||||||
|
- artist_dim_opt.as_ref().unwrap().height,
|
||||||
|
artist_dim_opt.as_ref().unwrap().width,
|
||||||
|
artist_dim_opt.as_ref().unwrap().height,
|
||||||
|
Color::new(0.0, 0.0, 0.0, 0.4),
|
||||||
|
);
|
||||||
|
draw_text(
|
||||||
|
&artist,
|
||||||
|
TEXT_X_OFFSET,
|
||||||
|
prev_height - temp_offset_y - TEXT_Y_OFFSET,
|
||||||
|
artist_font_size.into(),
|
||||||
|
WHITE,
|
||||||
|
);
|
||||||
|
|
||||||
|
temp_offset_y += TEXT_Y_OFFSET + artist_dim_opt.as_ref().unwrap().height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !title.is_empty() && !opt.disable_show_title {
|
||||||
|
draw_rectangle(
|
||||||
|
TEXT_X_OFFSET,
|
||||||
|
prev_height
|
||||||
|
- temp_offset_y
|
||||||
|
- TEXT_Y_OFFSET
|
||||||
|
- title_dim_opt.as_ref().unwrap().height,
|
||||||
|
title_dim_opt.as_ref().unwrap().width,
|
||||||
|
title_dim_opt.as_ref().unwrap().height,
|
||||||
|
Color::new(0.0, 0.0, 0.0, 0.4),
|
||||||
|
);
|
||||||
|
draw_text(
|
||||||
|
&title,
|
||||||
|
TEXT_X_OFFSET,
|
||||||
|
prev_height - temp_offset_y - TEXT_Y_OFFSET,
|
||||||
|
title_font_size.into(),
|
||||||
|
WHITE,
|
||||||
|
);
|
||||||
|
|
||||||
|
temp_offset_y += TEXT_Y_OFFSET + title_dim_opt.as_ref().unwrap().height;
|
||||||
|
}
|
||||||
|
|
||||||
|
let timer_string = seconds_to_time(track_timer);
|
||||||
|
let timer_dim = measure_text(&timer_string, None, TIMER_FONT_SIZE, 1.0f32);
|
||||||
|
draw_rectangle(
|
||||||
|
TEXT_X_OFFSET,
|
||||||
|
prev_height - temp_offset_y - TEXT_Y_OFFSET - timer_dim.height,
|
||||||
timer_dim.width,
|
timer_dim.width,
|
||||||
timer_dim.height,
|
timer_dim.height,
|
||||||
Color::new(0.0, 0.0, 0.0, 0.4),
|
Color::new(0.0, 0.0, 0.0, 0.4),
|
||||||
);
|
);
|
||||||
draw_text(
|
draw_text(
|
||||||
&timer_string,
|
&timer_string,
|
||||||
TIMER_X_OFFSET,
|
TEXT_X_OFFSET,
|
||||||
prev_height - TITLE_Y_OFFSET - text_dim.height - TIMER_Y_OFFSET,
|
prev_height - temp_offset_y - TEXT_Y_OFFSET,
|
||||||
64.0f32,
|
TIMER_FONT_SIZE.into(),
|
||||||
WHITE,
|
WHITE,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if !error_text.is_empty() {
|
if !error_text.is_empty() {
|
||||||
draw_text(&error_text, 0.0, 32.0f32, 32.0f32, WHITE);
|
draw_text(&error_text, 0.0, 32.0f32, 32.0f32, WHITE);
|
||||||
|
|
Loading…
Reference in a new issue