#![allow(clippy::too_many_arguments)]
pub mod particles;
pub mod camera;
pub mod debug_log;
pub mod render_queue;
pub mod gpu_instancing;
pub mod input_sdl2;
pub mod backend_sdl2;
pub mod audio_sdl2;
pub mod font_sdl2;
pub mod sdl2_ffi;
pub mod toolkit;
pub mod fsr;
use raylib::consts::KeyboardKey;
use raylib::prelude::*;
#[cfg(feature = "migui")]
use migui::{Color as MiguiColor, MiguiBackend, Rect as MiguiRect};
use std::collections::HashMap;
use std::ffi::CString;
use std::str::FromStr;
pub struct AudioSystem {
initialized: bool,
sounds: HashMap<String, raylib::ffi::Sound>,
music: Option<raylib::ffi::Music>,
}
impl AudioSystem {
pub fn new() -> Self {
unsafe {
raylib::ffi::InitAudioDevice();
println!("[AUDIO] Dispositivo de audio inicializado");
}
Self {
initialized: true,
sounds: HashMap::new(),
music: None,
}
}
pub fn load_sound(&mut self, id: &str, path: &str) -> Result<(), String> {
if !self.initialized {
return Err("Audio no inicializado".into());
}
let c_path = CString::new(path).map_err(|e| format!("Error en path: {}", e))?;
unsafe {
let sound = raylib::ffi::LoadSound(c_path.as_ptr());
if !sound.stream.buffer.is_null() || sound.frameCount > 0 {
println!("[AUDIO] Sonido '{}' cargado: {}", id, path);
self.sounds.insert(id.to_string(), sound);
Ok(())
} else {
Err(format!("Error cargando sonido '{}'", path))
}
}
}
pub fn play_sound(&self, id: &str) -> bool {
if let Some(sound) = self.sounds.get(id) {
unsafe {
raylib::ffi::PlaySound(*sound);
}
true
} else {
false
}
}
pub fn stop_sound(&self, id: &str) -> bool {
if let Some(sound) = self.sounds.get(id) {
unsafe {
raylib::ffi::StopSound(*sound);
}
true
} else {
false
}
}
pub fn set_sound_volume(&self, id: &str, volume: f32) -> bool {
if let Some(sound) = self.sounds.get(id) {
unsafe {
raylib::ffi::SetSoundVolume(*sound, volume);
}
true
} else {
false
}
}
pub fn load_music(&mut self, path: &str) -> Result<(), String> {
if !self.initialized {
return Err("Audio no inicializado".into());
}
let c_path = CString::new(path).map_err(|e| format!("Error en path: {}", e))?;
unsafe {
let music = raylib::ffi::LoadMusicStream(c_path.as_ptr());
if !music.stream.buffer.is_null() || music.frameCount > 0 {
println!("[AUDIO] Música cargada: {}", path);
self.music = Some(music);
Ok(())
} else {
Err(format!("Error cargando música '{}'", path))
}
}
}
pub fn play_music(&mut self) {
if let Some(ref music) = self.music {
unsafe {
raylib::ffi::PlayMusicStream(*music);
}
println!("[AUDIO] Reproduciendo música");
}
}
pub fn stop_music(&mut self) {
if let Some(ref music) = self.music {
unsafe {
raylib::ffi::StopMusicStream(*music);
}
println!("[AUDIO] Música detenida");
}
}
pub fn update_music(&mut self) {
if let Some(ref music) = self.music {
unsafe {
raylib::ffi::UpdateMusicStream(*music);
}
}
}
pub fn set_music_volume(&mut self, volume: f32) {
if let Some(ref music) = self.music {
unsafe {
raylib::ffi::SetMusicVolume(*music, volume);
}
}
}
pub fn is_music_playing(&self) -> bool {
if let Some(ref music) = self.music {
unsafe { raylib::ffi::IsMusicStreamPlaying(*music) }
} else {
false
}
}
pub fn unload_sound(&mut self, id: &str) {
if let Some(sound) = self.sounds.remove(id) {
unsafe {
raylib::ffi::UnloadSound(sound);
}
println!("[AUDIO] Sonido '{}' descargado", id);
}
}
pub fn unload_music(&mut self) {
if let Some(music) = self.music.take() {
unsafe {
raylib::ffi::UnloadMusicStream(music);
}
println!("[AUDIO] Música descargada");
}
}
pub fn has_sound(&self, id: &str) -> bool {
self.sounds.contains_key(id)
}
pub fn sound_count(&self) -> usize {
self.sounds.len()
}
}
impl Default for AudioSystem {
fn default() -> Self {
Self::new()
}
}
impl Drop for AudioSystem {
fn drop(&mut self) {
println!("[AUDIO] Cerrando sistema de audio...");
for (_, sound) in self.sounds.drain() {
unsafe {
raylib::ffi::UnloadSound(sound);
}
}
if let Some(music) = self.music.take() {
unsafe {
raylib::ffi::UnloadMusicStream(music);
}
}
if self.initialized {
unsafe {
raylib::ffi::CloseAudioDevice();
}
println!("[AUDIO] Dispositivo cerrado");
}
}
}
pub const RED: Color = Color {
r: 230,
g: 41,
b: 55,
a: 255,
};
pub const GREEN: Color = Color {
r: 117,
g: 203,
b: 100,
a: 255,
};
pub const BLUE: Color = Color {
r: 51,
g: 122,
b: 206,
a: 255,
};
pub const YELLOW: Color = Color {
r: 253,
g: 249,
b: 0,
a: 255,
};
pub const WHITE: Color = Color {
r: 255,
g: 255,
b: 255,
a: 255,
};
pub const BLACK: Color = Color {
r: 0,
g: 0,
b: 0,
a: 255,
};
pub const MAGENTA: Color = Color {
r: 255,
g: 0,
b: 255,
a: 255,
};
pub const PINK: Color = Color {
r: 255,
g: 192,
b: 203,
a: 255,
};
pub const ORANGE: Color = Color {
r: 255,
g: 165,
b: 0,
a: 255,
};
pub const GRAY: Color = Color {
r: 128,
g: 128,
b: 128,
a: 255,
};
pub const CYAN: Color = Color {
r: 0,
g: 255,
b: 255,
a: 255,
};
pub const PURPLE: Color = Color {
r: 128,
g: 0,
b: 128,
a: 255,
};
pub const BROWN: Color = Color {
r: 165,
g: 42,
b: 42,
a: 255,
};
pub const LIME: Color = Color {
r: 0,
g: 255,
b: 0,
a: 255,
};
pub const NAVY: Color = Color {
r: 0,
g: 0,
b: 128,
a: 255,
};
pub const OLIVE: Color = Color {
r: 128,
g: 128,
b: 0,
a: 255,
};
pub const TEAL: Color = Color {
r: 0,
g: 128,
b: 128,
a: 255,
};
pub const MAROON: Color = Color {
r: 128,
g: 0,
b: 0,
a: 255,
};
pub const KEY_ESCAPE: KeyboardKey = unsafe { std::mem::transmute(256i32) };
pub const KEY_SPACE: KeyboardKey = unsafe { std::mem::transmute(32i32) };
pub const KEY_ENTER: KeyboardKey = unsafe { std::mem::transmute(257i32) };
pub const KEY_UP: KeyboardKey = unsafe { std::mem::transmute(265i32) };
pub const KEY_DOWN: KeyboardKey = unsafe { std::mem::transmute(264i32) };
pub const KEY_LEFT: KeyboardKey = unsafe { std::mem::transmute(263i32) };
pub const KEY_RIGHT: KeyboardKey = unsafe { std::mem::transmute(262i32) };
pub const KEY_A: KeyboardKey = unsafe { std::mem::transmute(65i32) };
pub const KEY_B: KeyboardKey = unsafe { std::mem::transmute(66i32) };
pub const KEY_C: KeyboardKey = unsafe { std::mem::transmute(67i32) };
pub const KEY_D: KeyboardKey = unsafe { std::mem::transmute(68i32) };
pub const KEY_E: KeyboardKey = unsafe { std::mem::transmute(69i32) };
pub const KEY_F: KeyboardKey = unsafe { std::mem::transmute(70i32) };
pub const KEY_G: KeyboardKey = unsafe { std::mem::transmute(71i32) };
pub const KEY_H: KeyboardKey = unsafe { std::mem::transmute(72i32) };
pub const KEY_I: KeyboardKey = unsafe { std::mem::transmute(73i32) };
pub const KEY_J: KeyboardKey = unsafe { std::mem::transmute(74i32) };
pub const KEY_K: KeyboardKey = unsafe { std::mem::transmute(75i32) };
pub const KEY_L: KeyboardKey = unsafe { std::mem::transmute(76i32) };
pub const KEY_M: KeyboardKey = unsafe { std::mem::transmute(77i32) };
pub const KEY_N: KeyboardKey = unsafe { std::mem::transmute(78i32) };
pub const KEY_O: KeyboardKey = unsafe { std::mem::transmute(79i32) };
pub const KEY_P: KeyboardKey = unsafe { std::mem::transmute(80i32) };
pub const KEY_Q: KeyboardKey = unsafe { std::mem::transmute(81i32) };
pub const KEY_R: KeyboardKey = unsafe { std::mem::transmute(82i32) };
pub const KEY_S: KeyboardKey = unsafe { std::mem::transmute(83i32) };
pub const KEY_T: KeyboardKey = unsafe { std::mem::transmute(84i32) };
pub const KEY_U: KeyboardKey = unsafe { std::mem::transmute(85i32) };
pub const KEY_V: KeyboardKey = unsafe { std::mem::transmute(86i32) };
pub const KEY_W: KeyboardKey = unsafe { std::mem::transmute(87i32) };
pub const KEY_X: KeyboardKey = unsafe { std::mem::transmute(88i32) };
pub const KEY_Y: KeyboardKey = unsafe { std::mem::transmute(89i32) };
pub const KEY_Z: KeyboardKey = unsafe { std::mem::transmute(90i32) };
pub const KEY_ZERO: KeyboardKey = unsafe { std::mem::transmute(48i32) };
pub const KEY_ONE: KeyboardKey = unsafe { std::mem::transmute(49i32) };
pub const KEY_TWO: KeyboardKey = unsafe { std::mem::transmute(50i32) };
pub const KEY_THREE: KeyboardKey = unsafe { std::mem::transmute(51i32) };
pub const KEY_FOUR: KeyboardKey = unsafe { std::mem::transmute(52i32) };
pub const KEY_FIVE: KeyboardKey = unsafe { std::mem::transmute(53i32) };
pub const KEY_SIX: KeyboardKey = unsafe { std::mem::transmute(54i32) };
pub const KEY_SEVEN: KeyboardKey = unsafe { std::mem::transmute(55i32) };
pub const KEY_EIGHT: KeyboardKey = unsafe { std::mem::transmute(56i32) };
pub const KEY_NINE: KeyboardKey = unsafe { std::mem::transmute(57i32) };
pub const KEY_TAB: KeyboardKey = unsafe { std::mem::transmute(258i32) };
pub const KEY_CAPS_LOCK: KeyboardKey = unsafe { std::mem::transmute(259i32) };
pub const KEY_LEFT_SHIFT: KeyboardKey = unsafe { std::mem::transmute(340i32) };
pub const KEY_RIGHT_SHIFT: KeyboardKey = unsafe { std::mem::transmute(344i32) };
pub const KEY_LEFT_CONTROL: KeyboardKey = unsafe { std::mem::transmute(341i32) };
pub const KEY_RIGHT_CONTROL: KeyboardKey = unsafe { std::mem::transmute(345i32) };
pub const KEY_LEFT_ALT: KeyboardKey = unsafe { std::mem::transmute(342i32) };
pub const KEY_RIGHT_ALT: KeyboardKey = unsafe { std::mem::transmute(346i32) };
pub const KEY_PAGE_UP: KeyboardKey = unsafe { std::mem::transmute(266i32) };
pub const KEY_PAGE_DOWN: KeyboardKey = unsafe { std::mem::transmute(267i32) };
pub const KEY_HOME: KeyboardKey = unsafe { std::mem::transmute(268i32) };
pub const KEY_END: KeyboardKey = unsafe { std::mem::transmute(269i32) };
pub const KEY_INSERT: KeyboardKey = unsafe { std::mem::transmute(260i32) };
pub const KEY_DELETE: KeyboardKey = unsafe { std::mem::transmute(261i32) };
pub const KEY_F1: KeyboardKey = unsafe { std::mem::transmute(290i32) };
pub const KEY_F2: KeyboardKey = unsafe { std::mem::transmute(291i32) };
pub const KEY_F3: KeyboardKey = unsafe { std::mem::transmute(292i32) };
pub const KEY_F4: KeyboardKey = unsafe { std::mem::transmute(293i32) };
pub const KEY_F5: KeyboardKey = unsafe { std::mem::transmute(294i32) };
pub const KEY_F6: KeyboardKey = unsafe { std::mem::transmute(295i32) };
pub const KEY_F7: KeyboardKey = unsafe { std::mem::transmute(296i32) };
pub const KEY_F8: KeyboardKey = unsafe { std::mem::transmute(297i32) };
pub const KEY_F9: KeyboardKey = unsafe { std::mem::transmute(298i32) };
pub const KEY_F10: KeyboardKey = unsafe { std::mem::transmute(299i32) };
pub const KEY_F11: KeyboardKey = unsafe { std::mem::transmute(300i32) };
pub const KEY_F12: KeyboardKey = unsafe { std::mem::transmute(301i32) };
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ColorRydit {
Rojo,
Verde,
Azul,
Amarillo,
Blanco,
Negro,
Magenta,
Rosa,
Naranja,
Gris,
Cyan,
Morado,
Cafe,
Lima,
AzulOscuro,
Oliva,
Turquesa,
Vino,
}
impl ColorRydit {
pub fn to_color(&self) -> Color {
match self {
ColorRydit::Rojo => RED,
ColorRydit::Verde => GREEN,
ColorRydit::Azul => BLUE,
ColorRydit::Amarillo => YELLOW,
ColorRydit::Blanco => WHITE,
ColorRydit::Negro => BLACK,
ColorRydit::Magenta => MAGENTA,
ColorRydit::Rosa => PINK,
ColorRydit::Naranja => ORANGE,
ColorRydit::Gris => GRAY,
ColorRydit::Cyan => CYAN,
ColorRydit::Morado => PURPLE,
ColorRydit::Cafe => BROWN,
ColorRydit::Lima => LIME,
ColorRydit::AzulOscuro => NAVY,
ColorRydit::Oliva => OLIVE,
ColorRydit::Turquesa => TEAL,
ColorRydit::Vino => MAROON,
}
}
pub fn to_rgb(&self) -> (u8, u8, u8) {
match self {
ColorRydit::Rojo => (255, 0, 0),
ColorRydit::Verde => (0, 255, 0),
ColorRydit::Azul => (0, 0, 255),
ColorRydit::Amarillo => (255, 255, 0),
ColorRydit::Blanco => (255, 255, 255),
ColorRydit::Negro => (0, 0, 0),
ColorRydit::Magenta => (255, 0, 255),
ColorRydit::Rosa => (255, 192, 203),
ColorRydit::Naranja => (255, 165, 0),
ColorRydit::Gris => (128, 128, 128),
ColorRydit::Cyan => (0, 255, 255),
ColorRydit::Morado => (128, 0, 128),
ColorRydit::Cafe => (165, 42, 42),
ColorRydit::Lima => (0, 255, 0),
ColorRydit::AzulOscuro => (0, 0, 139),
ColorRydit::Oliva => (128, 128, 0),
ColorRydit::Turquesa => (64, 224, 208),
ColorRydit::Vino => (128, 0, 64),
}
}
#[cfg(feature = "migui")]
pub fn from_migui(color: MiguiColor) -> Self {
let r = color.r;
let g = color.g;
let b = color.b;
let colores = vec![
(ColorRydit::Rojo, RED),
(ColorRydit::Verde, GREEN),
(ColorRydit::Azul, BLUE),
(ColorRydit::Amarillo, YELLOW),
(ColorRydit::Blanco, WHITE),
(ColorRydit::Negro, BLACK),
(ColorRydit::Gris, GRAY),
(ColorRydit::Naranja, ORANGE),
(ColorRydit::Cyan, CYAN),
(ColorRydit::Morado, PURPLE),
(ColorRydit::Cafe, BROWN),
(ColorRydit::Lima, LIME),
(ColorRydit::AzulOscuro, NAVY),
(ColorRydit::Oliva, OLIVE),
(ColorRydit::Turquesa, TEAL),
(ColorRydit::Vino, MAROON),
];
let mut mejor_color = ColorRydit::Blanco;
let mut mejor_distancia = f32::MAX;
for (ry_color, raylib_color) in colores {
let dr = (r as i32 - raylib_color.r as i32).pow(2) as f32;
let dg = (g as i32 - raylib_color.g as i32).pow(2) as f32;
let db = (b as i32 - raylib_color.b as i32).pow(2) as f32;
let distancia = dr + dg + db;
if distancia < mejor_distancia {
mejor_distancia = distancia;
mejor_color = ry_color;
}
}
mejor_color
}
}
impl FromStr for ColorRydit {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"rojo" | "red" => Ok(ColorRydit::Rojo),
"verde" | "green" => Ok(ColorRydit::Verde),
"azul" | "blue" => Ok(ColorRydit::Azul),
"amarillo" | "yellow" => Ok(ColorRydit::Amarillo),
"blanco" | "white" => Ok(ColorRydit::Blanco),
"negro" | "black" => Ok(ColorRydit::Negro),
"magenta" | "fucsia" => Ok(ColorRydit::Magenta),
"rosa" | "pink" => Ok(ColorRydit::Rosa),
"naranja" | "orange" => Ok(ColorRydit::Naranja),
"gris" | "gray" | "grey" => Ok(ColorRydit::Gris),
"cyan" | "celeste" => Ok(ColorRydit::Cyan),
"morado" | "purple" | "violeta" => Ok(ColorRydit::Morado),
"cafe" | "brown" | "marron" => Ok(ColorRydit::Cafe),
"lima" | "lime" => Ok(ColorRydit::Lima),
"azuloscuro" | "navy" | "azul oscuro" => Ok(ColorRydit::AzulOscuro),
"oliva" | "olive" => Ok(ColorRydit::Oliva),
"turquesa" | "teal" => Ok(ColorRydit::Turquesa),
"vino" | "maroon" | "granate" => Ok(ColorRydit::Vino),
_ => Ok(ColorRydit::Blanco),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Key {
Escape,
Space,
Enter,
Tab,
CapsLock,
LeftShift,
RightShift,
LeftControl,
RightControl,
LeftAlt,
RightAlt,
PageUp,
PageDown,
Home,
End,
Insert,
Delete,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
ArrowUp,
ArrowDown,
ArrowLeft,
ArrowRight,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Num0,
Num1,
Num2,
Num3,
Num4,
Num5,
Num6,
Num7,
Num8,
Num9,
}
impl Key {
pub fn to_raylib(&self) -> KeyboardKey {
match self {
Key::Escape => KEY_ESCAPE,
Key::Space => KEY_SPACE,
Key::Enter => KEY_ENTER,
Key::Tab => KEY_TAB,
Key::CapsLock => KEY_CAPS_LOCK,
Key::LeftShift => KEY_LEFT_SHIFT,
Key::RightShift => KEY_RIGHT_SHIFT,
Key::LeftControl => KEY_LEFT_CONTROL,
Key::RightControl => KEY_RIGHT_CONTROL,
Key::LeftAlt => KEY_LEFT_ALT,
Key::RightAlt => KEY_RIGHT_ALT,
Key::PageUp => KEY_PAGE_UP,
Key::PageDown => KEY_PAGE_DOWN,
Key::Home => KEY_HOME,
Key::End => KEY_END,
Key::Insert => KEY_INSERT,
Key::Delete => KEY_DELETE,
Key::F1 => KEY_F1,
Key::F2 => KEY_F2,
Key::F3 => KEY_F3,
Key::F4 => KEY_F4,
Key::F5 => KEY_F5,
Key::F6 => KEY_F6,
Key::F7 => KEY_F7,
Key::F8 => KEY_F8,
Key::F9 => KEY_F9,
Key::F10 => KEY_F10,
Key::F11 => KEY_F11,
Key::F12 => KEY_F12,
Key::ArrowUp => KEY_UP,
Key::ArrowDown => KEY_DOWN,
Key::ArrowLeft => KEY_LEFT,
Key::ArrowRight => KEY_RIGHT,
Key::A => KEY_A,
Key::B => KEY_B,
Key::C => KEY_C,
Key::D => KEY_D,
Key::E => KEY_E,
Key::F => KEY_F,
Key::G => KEY_G,
Key::H => KEY_H,
Key::I => KEY_I,
Key::J => KEY_J,
Key::K => KEY_K,
Key::L => KEY_L,
Key::M => KEY_M,
Key::N => KEY_N,
Key::O => KEY_O,
Key::P => KEY_P,
Key::Q => KEY_Q,
Key::R => KEY_R,
Key::S => KEY_S,
Key::T => KEY_T,
Key::U => KEY_U,
Key::V => KEY_V,
Key::W => KEY_W,
Key::X => KEY_X,
Key::Y => KEY_Y,
Key::Z => KEY_Z,
Key::Num0 => KEY_ZERO,
Key::Num1 => KEY_ONE,
Key::Num2 => KEY_TWO,
Key::Num3 => KEY_THREE,
Key::Num4 => KEY_FOUR,
Key::Num5 => KEY_FIVE,
Key::Num6 => KEY_SIX,
Key::Num7 => KEY_SEVEN,
Key::Num8 => KEY_EIGHT,
Key::Num9 => KEY_NINE,
}
}
}
pub struct RyditGfx {
handle: RaylibHandle,
thread: RaylibThread,
width: i32,
height: i32,
fps: i32,
pub input_sdl2: input_sdl2::InputState,
#[allow(dead_code)]
sdl_context: Option<sdl2::Sdl>,
sdl_event_pump: Option<sdl2::EventPump>,
#[allow(dead_code)]
fsr: Option<fsr::FsrUpscaler>,
#[allow(dead_code)]
fsr_enabled: bool,
}
impl RyditGfx {
pub fn new(title: &str, width: i32, height: i32) -> Self {
let (handle, thread) = raylib::init().size(width, height).title(title).build();
println!("[RYDIT-GFX]: Ventana creada {}x{}", width, height);
println!("[RYDIT-GFX]: Rust = Arquitecto, Raylib = Pincel");
println!(
"[RYDIT-GFX]: DISPLAY={}",
std::env::var("DISPLAY").unwrap_or_else(|_| "NO SET".to_string())
);
let sdl_context = sdl2::init().ok();
if let Some(_) = &sdl_context {
sdl2::hint::set("SDL_VIDEODRIVER", "x11");
sdl2::hint::set("SDL_HINT_VIDEO_X11_FORCE_EGL", "1");
sdl2::hint::set("SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH", "1");
sdl2::hint::set("SDL_HINT_TOUCH_MOUSE_EVENTS", "1");
sdl2::hint::set("SDL_HINT_ENABLE_SCREEN_KEYBOARD", "1");
sdl2::hint::set("SDL_HINT_IME_SHOW_UI", "1");
eprintln!("[RYDIT-GFX] SDL2 hints configurados para Android/Termux-X11");
}
let sdl_event_pump = sdl_context.as_ref().and_then(|ctx| ctx.event_pump().ok());
Self {
handle,
thread,
width,
height,
fps: 60,
input_sdl2: input_sdl2::InputState::new(),
sdl_context,
sdl_event_pump,
fsr: None, fsr_enabled: false,
}
}
pub fn set_target_fps(&mut self, fps: i32) {
self.fps = fps;
self.handle.set_target_fps(fps as u32);
}
pub fn get_target_fps(&self) -> i32 {
self.fps
}
pub fn get_fps(&self) -> i32 {
self.handle.get_fps() as i32
}
pub fn should_close(&self) -> bool {
self.handle.window_should_close()
}
pub fn procesar_eventos_sdl2(&mut self) {
self.input_sdl2.limpiar_frame();
if let Some(ref mut event_pump) = self.sdl_event_pump {
for event in event_pump.poll_iter() {
match event {
sdl2::event::Event::KeyDown {
keycode: Some(keycode),
repeat: false,
..
} => {
self.input_sdl2.teclas.insert(keycode, true);
self.input_sdl2.teclas_pressionadas_frame.push(keycode);
}
sdl2::event::Event::KeyUp {
keycode: Some(keycode),
..
} => {
self.input_sdl2.teclas.insert(keycode, false);
}
_ => {}
}
}
}
}
pub fn is_key_pressed_sdl2(&self, nombre: &str) -> bool {
self.input_sdl2.is_key_pressed(nombre)
}
pub fn is_key_just_pressed_sdl2(&self, nombre: &str) -> bool {
self.input_sdl2.is_key_just_pressed(nombre)
}
pub fn width(&self) -> i32 {
self.width
}
pub fn height(&self) -> i32 {
self.height
}
pub fn begin_draw(&mut self) -> DrawHandle<'_> {
let d = self.handle.begin_drawing(&self.thread);
DrawHandle::new(d)
}
pub fn end_draw(&mut self) {
}
pub fn init_fsr(&mut self, quality: fsr::FsrQuality) -> Result<(), String> {
match fsr::FsrUpscaler::new() {
Ok(fsr) => {
eprintln!("[FSR] Inicializado: {:?}", quality);
self.fsr = Some(fsr);
self.fsr_enabled = true;
Ok(())
}
Err(e) => {
eprintln!("[FSR] Error al inicializar: {} (FSR desactivado)", e);
self.fsr = None;
self.fsr_enabled = false;
Err(e)
}
}
}
pub fn set_fsr_enabled(&mut self, enabled: bool) {
if let Some(ref mut fsr) = self.fsr {
fsr.set_enabled(enabled);
self.fsr_enabled = enabled;
}
}
pub fn set_fsr_quality(&mut self, quality: fsr::FsrQuality) {
if let Some(ref mut fsr) = self.fsr {
fsr.set_quality(quality);
}
}
pub fn cycle_fsr_quality(&mut self) {
if let Some(ref mut fsr) = self.fsr {
fsr.cycle_quality();
}
}
pub fn is_fsr_enabled(&self) -> bool {
self.fsr_enabled && self.fsr.is_some()
}
pub fn fsr_quality(&self) -> Option<fsr::FsrQuality> {
self.fsr.as_ref().map(|f| f.quality())
}
pub fn clear_background(&mut self, color: ColorRydit) {
let mut d = self.begin_draw();
d.clear(color);
}
pub fn draw_circle(&mut self, x: i32, y: i32, radius: i32, color: ColorRydit) {
{
let mut d = self.begin_draw();
d.draw_circle(x, y, radius, color);
drop(d); }
}
pub fn draw_rect(&mut self, x: i32, y: i32, w: i32, h: i32, color: ColorRydit) {
{
let mut d = self.begin_draw();
d.draw_rectangle(x, y, w, h, color);
drop(d); }
}
pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: ColorRydit) {
{
let mut d = self.begin_draw();
d.draw_line(x1, y1, x2, y2, color);
drop(d); }
}
pub fn draw_text(&mut self, text: &str, x: i32, y: i32, size: i32, color: ColorRydit) {
{
let mut d = self.begin_draw();
d.draw_text(text, x, y, size, color);
drop(d); }
}
pub fn load_texture(&mut self, path: &str) -> Texture2D {
unsafe {
let c_path = std::ffi::CString::new(path).unwrap();
let tex = raylib::ffi::LoadTexture(c_path.as_ptr());
std::mem::transmute(tex)
}
}
pub fn draw_texture(&mut self, _texture: &Texture2D, x: i32, y: i32, color: ColorRydit) {
self.draw_rect(x, y, 32, 32, color);
}
pub fn draw_texture_ex(
&mut self,
_texture: &Texture2D,
x: i32,
y: i32,
scale: f32,
color: ColorRydit,
) {
let size = (32.0 * scale) as i32;
self.draw_rect(x, y, size, size, color);
}
pub fn is_key_pressed(&self, key: Key) -> bool {
self.handle.is_key_pressed(key.to_raylib())
}
pub fn is_key_down(&self, key: Key) -> bool {
self.handle.is_key_down(key.to_raylib())
}
pub fn get_mouse_x(&self) -> i32 {
self.handle.get_mouse_x()
}
pub fn get_mouse_y(&self) -> i32 {
self.handle.get_mouse_y()
}
pub fn get_mouse_position(&self) -> (i32, i32) {
(self.handle.get_mouse_x(), self.handle.get_mouse_y())
}
pub fn is_mouse_button_pressed(&self, button: i32) -> bool {
unsafe {
let ffi_button = button;
raylib::ffi::IsMouseButtonPressed(ffi_button)
}
}
pub fn is_mouse_button_down(&self, button: i32) -> bool {
unsafe {
let ffi_button = button;
raylib::ffi::IsMouseButtonDown(ffi_button)
}
}
pub fn get_mouse_delta(&self) -> (i32, i32) {
let delta = self.handle.get_mouse_delta();
(delta.x as i32, delta.y as i32)
}
pub fn get_mouse_wheel(&self) -> f32 {
self.handle.get_mouse_wheel_move()
}
}
impl Drop for RyditGfx {
fn drop(&mut self) {
println!("[RYDIT-GFX]: Cerrando ventana...");
}
}
pub struct DrawHandle<'a> {
pub draw: RaylibDrawHandle<'a>,
}
impl<'a> DrawHandle<'a> {
fn new(draw: RaylibDrawHandle<'a>) -> Self {
Self { draw }
}
pub fn clear(&mut self, color: ColorRydit) {
self.draw.clear_background(color.to_color());
}
pub fn draw_circle(&mut self, x: i32, y: i32, radius: i32, color: ColorRydit) {
self.draw.draw_circle(x, y, radius as f32, color.to_color());
}
pub fn draw_rectangle(&mut self, x: i32, y: i32, w: i32, h: i32, color: ColorRydit) {
self.draw.draw_rectangle(x, y, w, h, color.to_color());
}
pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: ColorRydit) {
self.draw.draw_line(x1, y1, x2, y2, color.to_color());
}
pub fn draw_text(&mut self, text: &str, x: i32, y: i32, size: i32, color: ColorRydit) {
self.draw.draw_text(text, x, y, size, color.to_color());
}
pub fn draw_triangle(
&mut self,
v1: (i32, i32),
v2: (i32, i32),
v3: (i32, i32),
color: ColorRydit,
) {
let v1_raylib = Vector2::new(v1.0 as f32, v1.1 as f32);
let v2_raylib = Vector2::new(v2.0 as f32, v2.1 as f32);
let v3_raylib = Vector2::new(v3.0 as f32, v3.1 as f32);
self.draw
.draw_triangle(v1_raylib, v2_raylib, v3_raylib, color.to_color());
}
pub fn draw_triangle_lines(
&mut self,
v1: (i32, i32),
v2: (i32, i32),
v3: (i32, i32),
color: ColorRydit,
) {
self.draw_line(v1.0, v1.1, v2.0, v2.1, color);
self.draw_line(v2.0, v2.1, v3.0, v3.1, color);
self.draw_line(v3.0, v3.1, v1.0, v1.1, color);
}
pub fn draw_rectangle_lines(&mut self, x: i32, y: i32, w: i32, h: i32, color: ColorRydit) {
self.draw.draw_rectangle_lines(x, y, w, h, color.to_color());
}
pub fn draw_ring(
&mut self,
center: (i32, i32),
_inner_radius: i32,
outer_radius: i32,
color: ColorRydit,
) {
self.draw
.draw_circle(center.0, center.1, outer_radius as f32, color.to_color());
}
pub fn draw_ellipse(
&mut self,
center: (i32, i32),
radius_h: i32,
radius_v: i32,
color: ColorRydit,
) {
self.draw.draw_ellipse(
center.0,
center.1,
radius_h as f32,
radius_v as f32,
color.to_color(),
);
}
pub fn draw_line_thick(
&mut self,
start_pos: (i32, i32),
end_pos: (i32, i32),
thick: f32,
color: ColorRydit,
) {
let start = Vector2::new(start_pos.0 as f32, start_pos.1 as f32);
let end = Vector2::new(end_pos.0 as f32, end_pos.1 as f32);
self.draw.draw_line_ex(start, end, thick, color.to_color());
}
pub fn draw_rectangle_pro(
&mut self,
x: i32,
y: i32,
width: i32,
height: i32,
angle: f32,
color: ColorRydit,
) {
let origin = Vector2::new(width as f32 / 2.0, height as f32 / 2.0);
let rect = Rectangle::new(x as f32, y as f32, width as f32, height as f32);
self.draw
.draw_rectangle_pro(rect, origin, angle, color.to_color());
}
pub fn draw_texture_ex(
&mut self,
texture: &Texture2D,
position: Vector2,
rotation: f32,
scale: f32,
color: Color,
) {
self.draw
.draw_texture_ex(texture, position, rotation, scale, color);
}
}
impl<'a> Drop for DrawHandle<'a> {
fn drop(&mut self) {
}
}
pub struct Assets {
textures: HashMap<String, Texture2D>,
}
impl Assets {
pub fn new() -> Self {
Self {
textures: HashMap::new(),
}
}
pub fn load_texture_from_path(path: &str) -> Result<Texture2D, String> {
use std::ffi::CString;
use std::path::Path;
if Path::new(path).exists() {
unsafe {
let c_path =
CString::new(path).map_err(|e| format!("Error convirtiendo path: {}", e))?;
let ffi_texture = raylib::ffi::LoadTexture(c_path.as_ptr());
if ffi_texture.id != 0 {
Ok(Texture2D::from_raw(ffi_texture))
} else {
Err(format!("Error cargando textura '{}'", path))
}
}
} else {
Err(format!("Archivo '{}' no encontrado", path))
}
}
pub fn insert_texture(&mut self, id: String, texture: Texture2D) {
self.textures.insert(id, texture);
}
pub fn get_texture(&self, id: &str) -> Option<&Texture2D> {
self.textures.get(id)
}
pub fn unload_texture(&mut self, id: &str) -> bool {
self.textures.remove(id).is_some()
}
#[allow(clippy::too_many_arguments)]
pub fn draw_texture(
&self,
d: &mut RaylibDrawHandle,
id: &str,
x: f32,
y: f32,
_w: f32,
_h: f32,
color: Color,
) {
if let Some(texture) = self.textures.get(id) {
d.draw_texture_ex(texture, Vector2::new(x, y), 0.0, 1.0, color);
}
}
pub fn draw_texture_scaled(
&self,
d: &mut RaylibDrawHandle,
id: &str,
x: f32,
y: f32,
scale: f32,
color: Color,
) {
if let Some(texture) = self.textures.get(id) {
d.draw_texture_ex(texture, Vector2::new(x, y), 0.0, scale, color);
}
}
pub fn draw_texture_ex_by_id(
&self,
d: &mut RaylibDrawHandle,
id: &str,
x: f32,
y: f32,
scale: f32,
rotation: f32,
color: ColorRydit,
) {
if let Some(texture) = self.textures.get(id) {
d.draw_texture_ex(
texture,
Vector2::new(x, y),
rotation,
scale,
color.to_color(),
);
}
}
pub fn draw_texture_rec(
&self,
d: &mut RaylibDrawHandle,
id: &str,
source: Rectangle,
dest: Rectangle,
color: Color,
) {
if let Some(texture) = self.textures.get(id) {
d.draw_texture_rec(texture, source, Vector2::new(dest.x, dest.y), color);
}
}
pub fn has_texture(&self, id: &str) -> bool {
self.textures.contains_key(id)
}
pub fn texture_count(&self) -> usize {
self.textures.len()
}
pub fn clear(&mut self) {
self.textures.clear();
}
pub fn load_texture_sdl2<'a>(
path: &str,
texture_creator: &'a sdl2::render::TextureCreator<sdl2::video::WindowContext>,
) -> Result<sdl2::render::Texture<'a>, String> {
use crate::sdl2_ffi::TextureFFI;
use sdl2::surface::Surface;
use std::path::Path;
if !Path::new(path).exists() {
return Err(format!("Archivo '{}' no encontrado", path));
}
let texture_ffi = TextureFFI::load(path)?;
let surface_ptr = texture_ffi.surface();
unsafe {
let sdl_surface = Surface::from_ll(surface_ptr as *mut sdl2::sys::SDL_Surface);
let texture = texture_creator
.create_texture_from_surface(&sdl_surface)
.map_err(|e| format!("Error creando textura SDL2: {}", e))?;
Ok(texture)
}
}
pub fn draw_texture_sdl2(
canvas: &mut sdl2::render::Canvas<sdl2::video::Window>,
texture: &sdl2::render::Texture,
x: i32,
y: i32,
width: u32,
height: u32,
) -> Result<(), String> {
let rect = sdl2::rect::Rect::new(x, y, width, height);
canvas
.copy(texture, None, rect)
.map_err(|e| format!("Error dibujando textura SDL2: {}", e))?;
Ok(())
}
}
impl Default for Assets {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "migui")]
impl MiguiBackend for RyditGfx {
fn clear(&mut self, color: MiguiColor) {
let color_rydit = ColorRydit::from_migui(color);
let mut d = self.begin_draw();
d.clear(color_rydit);
}
fn draw_rect(&mut self, rect: MiguiRect, color: MiguiColor) {
let color_rydit = ColorRydit::from_migui(color);
let mut d = self.begin_draw();
d.draw_rectangle(
rect.x as i32,
rect.y as i32,
rect.w as i32,
rect.h as i32,
color_rydit,
);
}
fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: MiguiColor) {
let color_rydit = ColorRydit::from_migui(color);
let mut d = self.begin_draw();
d.draw_text(text, x as i32, y as i32, size as i32, color_rydit);
}
fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: MiguiColor, thickness: f32) {
let color_rydit = ColorRydit::from_migui(color);
let mut d = self.begin_draw();
d.draw.draw_line_ex(
Vector2::new(x1, y1),
Vector2::new(x2, y2),
thickness,
color_rydit.to_color(),
);
}
}
#[cfg(feature = "migui")]
impl RyditGfx {
pub fn render_migui_frame(&mut self, commands: &[migui::DrawCommand]) {
let mut d = self.begin_draw();
d.clear(ColorRydit::Negro);
for cmd in commands {
match cmd {
migui::DrawCommand::Clear { color } => {
d.clear(ColorRydit::from_migui(*color));
}
migui::DrawCommand::DrawRect { rect, color } => {
d.draw_rectangle(
rect.x as i32,
rect.y as i32,
rect.w as i32,
rect.h as i32,
ColorRydit::from_migui(*color),
);
}
migui::DrawCommand::DrawText {
text,
x,
y,
size,
color,
} => {
d.draw_text(
text,
*x as i32,
*y as i32,
*size as i32,
ColorRydit::from_migui(*color),
);
}
migui::DrawCommand::DrawLine {
x1,
y1,
x2,
y2,
color,
thickness,
} => {
d.draw.draw_line_ex(
Vector2::new(*x1, *y1),
Vector2::new(*x2, *y2),
*thickness,
ColorRydit::from_migui(*color).to_color(),
);
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_color_from_str() {
assert_eq!(ColorRydit::from_str("rojo").unwrap(), ColorRydit::Rojo);
assert_eq!(ColorRydit::from_str("RED").unwrap(), ColorRydit::Rojo);
assert_eq!(ColorRydit::from_str("verde").unwrap(), ColorRydit::Verde);
assert_eq!(ColorRydit::from_str("azul").unwrap(), ColorRydit::Azul);
assert_eq!(
ColorRydit::from_str("amarillo").unwrap(),
ColorRydit::Amarillo
);
assert_eq!(ColorRydit::from_str("blanco").unwrap(), ColorRydit::Blanco);
assert_eq!(ColorRydit::from_str("negro").unwrap(), ColorRydit::Negro);
assert_eq!(
ColorRydit::from_str("desconocido").unwrap(),
ColorRydit::Blanco
);
}
#[test]
fn test_key_to_raylib() {
let _ = Key::Escape.to_raylib();
let _ = Key::Space.to_raylib();
let _ = Key::A.to_raylib();
let _ = Key::Num0.to_raylib();
}
#[test]
fn test_color_to_color() {
let color = ColorRydit::Rojo.to_color();
assert_eq!(color.r, 230);
assert_eq!(color.g, 41);
assert_eq!(color.b, 55);
assert_eq!(color.a, 255);
}
#[test]
fn test_draw_circle_colores() {
let colores = vec!["rojo", "verde", "azul", "amarillo", "blanco", "negro"];
for color_str in colores {
let color_rydit = ColorRydit::from_str(color_str).unwrap();
let color = color_rydit.to_color();
assert_eq!(color.a, 255, "Color {} debe tener alpha 255", color_str);
}
}
#[test]
fn test_draw_rect_dimensiones() {
let x: i32 = 100;
let y: i32 = 200;
let ancho: i32 = 50;
let alto: i32 = 75;
assert_eq!(x, 100);
assert_eq!(y, 200);
assert_eq!(ancho, 50);
assert_eq!(alto, 75);
let rect = raylib::prelude::Rectangle::new(x as f32, y as f32, ancho as f32, alto as f32);
assert_eq!(rect.x, 100.0);
assert_eq!(rect.y, 200.0);
assert!((rect.width - 50.0).abs() < 0.01);
assert!((rect.height - 75.0).abs() < 0.01);
}
#[test]
fn test_mouse_functions_exist() {
let _ = RyditGfx::new("Test", 800, 600);
}
#[test]
fn test_mouse_button_mapping() {
assert_eq!(0, 0); assert_eq!(1, 1); assert_eq!(2, 2); }
#[cfg(feature = "migui")]
#[test]
fn test_migui_backend_exists() {
let _ = RyditGfx::new("Test", 800, 600);
}
}