1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use cty::c_int;
use ndless::prelude::*;

use crate::get_error;
use crate::video::ll::SDL_RWFromConstMem;
use crate::video::Surface;

pub mod ll {
	#![allow(non_camel_case_types)]

	use cty::{c_char, c_int, c_uint};

	use crate::video::ll::{SDL_RWops, SDL_Surface};

	pub type IMG_InitFlags = c_uint;

	pub const IMG_INIT_JPG: IMG_InitFlags = 1;
	pub const IMG_INIT_PNG: IMG_InitFlags = 2;
	pub const IMG_INIT_TIF: IMG_InitFlags = 4;
	pub const IMG_INIT_WEBP: IMG_InitFlags = 8;

	extern "C" {
		pub fn IMG_Init(flags: c_int) -> c_int;
		pub fn IMG_Quit();
		pub fn IMG_Load(file: *const c_char) -> *mut SDL_Surface;
		pub fn IMG_LoadGIF_RW(src: *mut SDL_RWops) -> *mut SDL_Surface;
		pub fn IMG_LoadLBM_RW(src: *mut SDL_RWops) -> *mut SDL_Surface;
		pub fn IMG_LoadPCX_RW(src: *mut SDL_RWops) -> *mut SDL_Surface;
		pub fn IMG_LoadPNM_RW(src: *mut SDL_RWops) -> *mut SDL_Surface;
		pub fn IMG_LoadTGA_RW(src: *mut SDL_RWops) -> *mut SDL_Surface;
		pub fn IMG_LoadXCF_RW(src: *mut SDL_RWops) -> *mut SDL_Surface;
	}
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum InitFlag {
	JPG = ll::IMG_INIT_JPG as isize,
	PNG = ll::IMG_INIT_PNG as isize,
	TIF = ll::IMG_INIT_TIF as isize,
}

pub fn init(flags: &[InitFlag]) -> Vec<InitFlag> {
	let bitflags = unsafe {
		ll::IMG_Init(
			flags
				.iter()
				.fold(0i32, |flags, &flag| flags | flag as c_int),
		)
	};

	let flags = [InitFlag::JPG, InitFlag::PNG, InitFlag::TIF];

	flags
		.iter()
		.filter_map(|&flag| {
			if bitflags & (flag as c_int) != 0 {
				Some(flag)
			} else {
				None
			}
		})
		.collect()
}

pub fn load_file(file: impl Into<String>) -> Result<Surface, String> {
	let cfile = ndless::cstr!(file.into());
	unsafe {
		let raw = ll::IMG_Load(cfile.as_ptr());

		if raw.is_null() {
			Err(get_error())
		} else {
			Ok(Surface { raw, owned: true })
		}
	}
}

macro_rules! load_typed {
	($name: ident, $function: ident) => {
		pub fn $name(buffer: &[u8]) -> Result<Surface, String> {
			unsafe {
				let mem =
					SDL_RWFromConstMem(buffer.as_ptr() as *const cty::c_void, buffer.len() as i32);
				if mem.is_null() {
					return Err(get_error());
				}

				let raw = ll::$function(mem);

				if raw.is_null() {
					Err(get_error())
				} else {
					Ok(Surface { raw, owned: true })
				}
			}
		}
	};
}

load_typed!(load_mem_gif, IMG_LoadGIF_RW);
load_typed!(load_mem_lbm, IMG_LoadLBM_RW);
load_typed!(load_mem_pcx, IMG_LoadPCX_RW);
// PNM disabled for now due to possible link-time errors
//load_typed!(load_mem_pnm, IMG_LoadPNM_RW);
load_typed!(load_mem_tga, IMG_LoadTGA_RW);
load_typed!(load_mem_xcf, IMG_LoadXCF_RW);

pub fn quit() {
	unsafe {
		ll::IMG_Quit();
	}
}