#![allow(non_upper_case_globals, non_snake_case, dead_code, improper_ctypes)]
#[link(name = "SDL2_image")]
extern "C" {
fn IMG_Init(flags: c_int) -> c_int;
fn IMG_Quit();
fn IMG_Load(file: *const c_char) -> *mut SDL_Surface;
}
const IMG_INIT_PNG: c_int = 0x00000002;
const IMG_INIT_JPG: c_int = 0x00000004;
#[link(name = "SDL2_ttf")]
extern "C" {
fn TTF_Init() -> c_int;
fn TTF_Quit();
fn TTF_OpenFont(file: *const c_char, ptsize: c_int) -> *mut TTF_Font;
fn TTF_CloseFont(font: *mut TTF_Font);
fn TTF_RenderText_Solid(
font: *mut TTF_Font,
text: *const c_char,
fg: SDL_Color,
) -> *mut SDL_Surface;
fn TTF_RenderText_Blended(
font: *mut TTF_Font,
text: *const c_char,
fg: SDL_Color,
) -> *mut SDL_Surface;
}
#[link(name = "SDL2_mixer")]
extern "C" {
pub fn Mix_Init(flags: c_int) -> c_int;
pub fn Mix_Quit();
pub fn Mix_OpenAudio(frequency: c_int, format: u16, channels: c_int, chunksize: c_int)
-> c_int;
pub fn Mix_CloseAudio();
pub fn Mix_LoadWAV(file: *const c_char) -> *mut Mix_Chunk;
pub fn Mix_LoadMUS(file: *const c_char) -> *mut Mix_Music;
pub fn Mix_PlayChannel(channel: c_int, chunk: *mut Mix_Chunk, loops: c_int) -> c_int;
pub fn Mix_PlayMusic(music: *mut Mix_Music, loops: c_int) -> c_int;
pub fn Mix_HaltMusic();
pub fn Mix_HaltChannel(channel: c_int);
pub fn Mix_VolumeMusic(volume: c_int) -> c_int;
pub fn Mix_Volume(channel: c_int, volume: c_int) -> c_int;
}
const MIX_INIT_OGG: c_int = 0x00000002;
const MIX_INIT_MP3: c_int = 0x00000008;
#[repr(C)]
pub struct SDL_Surface {
pub flags: u32,
pub format: *mut SDL_PixelFormat,
pub w: c_int,
pub h: c_int,
pub pitch: c_int,
pub pixels: *mut c_void,
}
#[repr(C)]
pub struct SDL_PixelFormat {
}
#[repr(C)]
pub struct SDL_Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
#[repr(C)]
pub struct TTF_Font {
}
#[repr(C)]
pub struct Mix_Chunk {
}
#[repr(C)]
pub struct Mix_Music {
}
use std::ffi::CString;
use std::os::raw::{c_char, c_int, c_void};
pub struct TextureFFI {
surface: *mut SDL_Surface,
}
impl TextureFFI {
pub fn init() -> Result<(), String> {
unsafe {
let result = IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG);
if result == 0 {
Err("Error inicializando SDL2_image".to_string())
} else {
Ok(())
}
}
}
pub fn load(path: &str) -> Result<Self, String> {
unsafe {
let c_path = CString::new(path).map_err(|e| e.to_string())?;
let surface = IMG_Load(c_path.as_ptr());
if surface.is_null() {
Err(format!("Error cargando textura: {}", path))
} else {
Ok(TextureFFI { surface })
}
}
}
pub fn dimensions(&self) -> (i32, i32) {
unsafe { ((*self.surface).w, (*self.surface).h) }
}
pub fn surface(&self) -> *mut SDL_Surface {
self.surface
}
}
impl Drop for TextureFFI {
fn drop(&mut self) {
if !self.surface.is_null() {
}
}
}
pub struct AudioFFI {
initialized: bool,
}
impl AudioFFI {
pub fn init() -> Result<Self, String> {
unsafe {
let result = Mix_Init(MIX_INIT_OGG | MIX_INIT_MP3);
if result == 0 {
return Err("Error inicializando SDL2_mixer".to_string());
}
let audio_result = Mix_OpenAudio(44100, 0x8010, 2, 1024);
if audio_result != 0 {
Mix_Quit();
return Err("Error abriendo audio".to_string());
}
Ok(AudioFFI { initialized: true })
}
}
pub fn load_sound(&self, path: &str) -> Result<*mut Mix_Chunk, String> {
unsafe {
let c_path = CString::new(path).map_err(|e| e.to_string())?;
let chunk = Mix_LoadWAV(c_path.as_ptr());
if chunk.is_null() {
Err(format!("Error cargando sonido: {}", path))
} else {
Ok(chunk)
}
}
}
pub fn load_music(&self, path: &str) -> Result<*mut Mix_Music, String> {
unsafe {
let c_path = CString::new(path).map_err(|e| e.to_string())?;
let music = Mix_LoadMUS(c_path.as_ptr());
if music.is_null() {
Err(format!("Error cargando música: {}", path))
} else {
Ok(music)
}
}
}
pub unsafe fn play_sound(&self, chunk: *mut Mix_Chunk) -> Result<(), String> {
unsafe {
let result = Mix_PlayChannel(-1, chunk, 0);
if result == -1 {
Err("Error reproduciendo sonido".to_string())
} else {
Ok(())
}
}
}
pub unsafe fn play_music(&self, music: *mut Mix_Music, loops: i32) -> Result<(), String> {
unsafe {
let result = Mix_PlayMusic(music, loops as c_int);
if result == -1 {
Err("Error reproduciendo música".to_string())
} else {
Ok(())
}
}
}
pub fn stop_music(&self) {
unsafe {
Mix_HaltMusic();
}
}
}
impl Drop for AudioFFI {
fn drop(&mut self) {
if self.initialized {
unsafe {
Mix_CloseAudio();
Mix_Quit();
}
}
}
}
pub struct FontFFI {
font: *mut TTF_Font,
}
impl FontFFI {
pub fn init() -> Result<(), String> {
unsafe {
let result = TTF_Init();
if result == -1 {
Err("Error inicializando SDL2_ttf".to_string())
} else {
Ok(())
}
}
}
pub fn load(path: &str, size: i32) -> Result<Self, String> {
unsafe {
let c_path = CString::new(path).map_err(|e| e.to_string())?;
let font = TTF_OpenFont(c_path.as_ptr(), size as c_int);
if font.is_null() {
Err(format!("Error cargando fuente: {}", path))
} else {
Ok(FontFFI { font })
}
}
}
pub fn render_text(&self, text: &str, r: u8, g: u8, b: u8) -> Result<*mut SDL_Surface, String> {
unsafe {
let c_text = CString::new(text).map_err(|e| e.to_string())?;
let color = SDL_Color { r, g, b, a: 255 };
let surface = TTF_RenderText_Solid(self.font, c_text.as_ptr(), color);
if surface.is_null() {
Err("Error renderizando texto".to_string())
} else {
Ok(surface)
}
}
}
pub fn render_text_blended(
&self,
text: &str,
r: u8,
g: u8,
b: u8,
) -> Result<*mut SDL_Surface, String> {
unsafe {
let c_text = CString::new(text).map_err(|e| e.to_string())?;
let color = SDL_Color { r, g, b, a: 255 };
let surface = TTF_RenderText_Blended(self.font, c_text.as_ptr(), color);
if surface.is_null() {
Err("Error renderizando texto".to_string())
} else {
Ok(surface)
}
}
}
pub fn font_ptr(&self) -> *mut TTF_Font {
self.font
}
}
impl Drop for FontFFI {
fn drop(&mut self) {
unsafe {
if !self.font.is_null() {
TTF_CloseFont(self.font);
}
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_texture_ffi_init() {
}
}