extern crate sdl2; use sdl2::Sdl; use sdl2::video::{Window, WindowContext}; use sdl2::render::{TextureCreator, Texture}; use sdl2::surface::Surface; use sdl2::rect::Rect; use sdl2::event::Event; use sdl2::keyboard::Keycode; use std::path::Path; // using a different window size than lazyfoo, due to high-density screen const WIDTH:u32 = 1280; const HEIGHT:u32 = 960; // need the window (blit settings) as well as the canvas // and still the context for the event pump // // splitting canvas out for now due to compilation reasons fn init() -> (Sdl, Window) { let context = match sdl2::init() { Ok(context) => context, Err(err) => panic!("Could not initialize SDL2. Error: {}", err), }; let video = match context.video() { Ok(video) => video, Err(err) => panic!("Could not gain access to the SDL2 video subsystem. Error: {}", err), }; let window = match video.window("SDL Tutorial, lesson 05", WIDTH, HEIGHT) .position_centered() .opengl() .build() { Ok(window) => window, Err(err) => panic!("Could not create window. Error: {}", err), }; return (context, window) } // we need to manipulate the surface post-load, so separating these functions out fn load_surface(path: &str) -> Surface { let surface = match Surface::load_bmp(&Path::new(path)) { Ok(surface) => surface, Err(err) => panic!("Could not load image: {}", err) }; return surface; } fn surface_to_texture<'a>(surface: &Surface, tc: &'a TextureCreator) -> Texture<'a> { let texture = match tc.create_texture_from_surface(&surface) { Ok(texture) => texture, Err(err) => panic!("Could not slap surface into a texture: {}", err) }; return texture; } // And this becomes much simpler // although it's unused in this lesson fn load_texture<'a>(path: &'static str, tc: &'a TextureCreator) -> Texture<'a> { return surface_to_texture(&load_surface(path), &tc); } fn main() { let mut running: bool = true; let (context, window) = init(); let starting_surface = load_surface("../assets/stretch.bmp"); // okay, now to modify the surface // this, afaict, has no perceivable benefit for this example // but should optimize things for future tight loops, etc // // // ... though we do create three separate surfaces in this process let pixel_format = window.window_pixel_format(); let sf_pixel_format = starting_surface.pixel_format(); let optimized_surface = match starting_surface .convert(&sf_pixel_format) { Ok(surface) => surface, Err(err) => panic!("Could not convert surface: {}", err) }; // Now stretch the optimized surface to the dimensions we want let dst_rect = Rect::new(0, 0, WIDTH, HEIGHT); let mut stretched_surface = match Surface::new(WIDTH, HEIGHT, pixel_format) { Ok(surface) => surface, Err(err) => panic!("Could not create surface: {}", err) }; // blit_scaled does not return anything, but it does return an SdlResult, so // we unwrap to trigger the panic if we can't blit. optimized_surface.blit_scaled(None, &mut stretched_surface, Some(dst_rect)).unwrap(); // couldn't figure out how to wrap the canvas creation in a function, // since it involves borrowing `window`. Short enough to handle from // here, but still frustrating. let mut canvas = match window.into_canvas() .build() { Ok(canvas) => canvas, Err(err) => panic!("Could not create canvas from window. Error: {}", err), }; let tc = canvas.texture_creator(); let texture = surface_to_texture(&stretched_surface, &tc); let mut pump = match context.event_pump() { Ok(pump) => pump, Err(err) => panic!("Could not start pumping: {}", err) }; while running { // pull all pending events for event in pump.poll_iter() { match event { // apparently '{..}' means "with whatever fields" Event::Quit {..} => { running = false }, Event::KeyDown { keycode: k, .. } => match k { Some(Keycode::Escape) | Some(Keycode::Q) => { running = false }, Some(_) => {}, None => {} }, _ => {} } } //canvas.clear(); match canvas.copy(&texture, None, None) { Ok(()) => (), // no return value == success Err(err) => panic!("Could not render texture: {}", err), }; canvas.present(); } }