diff --git a/sdl2-sys/src/pixels.rs b/sdl2-sys/src/pixels.rs index 091f7805..9ed6c60d 100644 --- a/sdl2-sys/src/pixels.rs +++ b/sdl2-sys/src/pixels.rs @@ -91,4 +91,8 @@ extern "C" { pub fn SDL_PixelFormatEnumToMasks(format: uint32_t, bpp: *mut c_int, rmask: *mut uint32_t, gmask: *mut uint32_t, bmask: *mut uint32_t, amask: *mut uint32_t) -> SDL_bool; pub fn SDL_MasksToPixelFormatEnum(bpp: c_int, rmask: uint32_t, gmask: uint32_t, bmask: uint32_t, amask: uint32_t) -> uint32_t; + + pub fn SDL_AllocPalette(ncolors: c_int) -> *mut SDL_Palette; + pub fn SDL_FreePalette(palette: *mut SDL_Palette); + pub fn SDL_SetPaletteColors(palette: *mut SDL_Palette, colors: *const SDL_Color, firstcolor: c_int, ncolors: c_int) -> c_int; } diff --git a/src/sdl2/pixels.rs b/src/sdl2/pixels.rs index d5d462cd..48cd0472 100644 --- a/src/sdl2/pixels.rs +++ b/src/sdl2/pixels.rs @@ -10,8 +10,81 @@ pub struct Palette { raw: *mut ll::SDL_Palette } +impl Palette { + #[inline] + /// Creates a new, uninitialized palette + pub fn new(mut capacity: usize) -> Result { + use common::*; + + let ncolors = { + // This is kind of a hack. We have to cast twice because + // ncolors is a c_int, and validate_int only takes a u32. + // FIXME: Modify validate_int to make this unnecessary + let u32_max = u32::max_value() as usize; + if capacity > u32_max { capacity = u32_max; } + + match validate_int(capacity as u32, "capacity") { + Ok(len) => len, + Err(e) => return Err(format!("{}", e)), + } + }; + + let raw = unsafe { ll::SDL_AllocPalette(ncolors) }; + + if raw.is_null() { + Err(get_error()) + } else { + Ok(Palette { + raw: raw, + }) + } + } + + /// Creates a palette from the provided colors + pub fn with_colors(colors: &[Color]) -> Result { + let pal = try!(Self::new(colors.len())); + + // Already validated, so don't check again + let ncolors = colors.len() as ::libc::c_int; + + let result = unsafe { + let mut raw_colors: Vec = colors.iter() + .map(|color| color.raw()) + .collect(); + + let pal_ptr = (&mut raw_colors[0]) as *mut ll::SDL_Color; + + ll::SDL_SetPaletteColors(pal.raw, pal_ptr, 0, ncolors) + }; + + if result < 0 { + Err(get_error()) + } else { + Ok(pal) + } + } + + pub fn len(&self) -> usize { + unsafe { (*self.raw).ncolors as usize } + } +} + +// TODO: ll::SDL_FreePalette(...) +// impl Drop for Palette { ... } + impl_raw_accessors!((Palette, *mut ll::SDL_Palette)); +#[test] +fn create_palette() { + let colors: Vec<_> = (0 .. 0xff).map(|u| { + Color::RGB(u, 0, 0xff - u) + }).collect(); + + let palette = Palette::with_colors(&colors).unwrap(); + + assert!(palette.len() == 255); +} + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub enum Color { RGB(u8, u8, u8), @@ -45,6 +118,19 @@ impl Color { &Color::RGBA(r, g, b, _) => (r, g, b) } } + + pub fn rgba(&self) -> (u8, u8, u8, u8) { + match self { + &Color::RGB(r, g, b) => (r, g, b, 0xff), + &Color::RGBA(r, g, b, a) => (r, g, b, a), + } + } + + // Implemented manually and kept private, because reasons + unsafe fn raw(&self) -> ll::SDL_Color { + let (r, g, b, a) = self.rgba(); + ll::SDL_Color { r: r, g: g, b: b, a: a } + } } impl rand::Rand for Color {