|
@@ -0,0 +1,164 @@
|
|
|
+
|
|
|
+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<WindowContext>) -> 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<WindowContext>) -> 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();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|