Do rendering via a renderer instead of sdl
authorTomas Wenström <tomas.wenstrom@gmail.com>
Sat, 23 Jan 2021 14:40:14 +0000 (15:40 +0100)
committerTomas Wenström <tomas.wenstrom@gmail.com>
Sat, 23 Jan 2021 14:40:14 +0000 (15:40 +0100)
The access to the canvas is temporary

src/boll.rs
src/core/app.rs
src/core/game.rs
src/core/mod.rs
src/core/render.rs [new file with mode: 0644]

index b8e21a7..abf6c87 100644 (file)
@@ -1,8 +1,5 @@
-use sdl2::pixels::Color;
-use sdl2::rect::Point;
+use core::render::Renderer;
 use sdl2::rect::Rect;
-use sdl2::render::Canvas;
-use sdl2::video::Window;
 
 use common::Point2D;
 use sdl2::gfx::primitives::DrawRenderer;
@@ -10,7 +7,7 @@ use {SCREEN_HEIGHT, SCREEN_WIDTH};
 
 pub trait Boll {
     fn update(&mut self);
-    fn draw(&self, canvas: &mut Canvas<Window>, size: u32);
+    fn draw(&self, renderer: &mut Renderer, size: u32);
 }
 
 pub struct SquareBoll {
@@ -41,16 +38,16 @@ impl Boll for SquareBoll {
         }
     }
 
-    fn draw(&self, canvas: &mut Canvas<Window>, size: u32) {
-        canvas.set_draw_color(Color::RGBA(
+    fn draw(&self, renderer: &mut Renderer, size: u32) {
+        renderer.canvas().set_draw_color((
             255 - std::cmp::min(255, (self.vel.length() * 25.0) as u8),
             (255.0 * (self.pos.x / SCREEN_WIDTH as f64)) as u8,
             (255.0 * (self.pos.y / SCREEN_HEIGHT as f64)) as u8,
             128,
         ));
         let mut r = Rect::new(0, 0, size, size);
-        r.center_on(Point::new(self.pos.x as i32, self.pos.y as i32));
-        canvas.fill_rect(r).unwrap();
+        r.center_on((self.pos.x as i32, self.pos.y as i32));
+        renderer.canvas().fill_rect(r).unwrap();
     }
 }
 
@@ -71,14 +68,15 @@ impl Boll for CircleBoll {
         self.boll.update();
     }
 
-    fn draw(&self, canvas: &mut Canvas<Window>, size: u32) {
+    fn draw(&self, renderer: &mut Renderer, size: u32) {
         let val = 255 - std::cmp::min(255, (self.boll.vel.length() * 20.0) as u8);
-        canvas
+        renderer
+           .canvas()
             .filled_circle(
                 self.boll.pos.x as i16,
                 self.boll.pos.y as i16,
                 size as i16,
-                Color::RGBA(val, val, val, 128),
+                (val, val, val, 128),
             )
             .unwrap();
     }
index cac2a37..99b24ac 100644 (file)
@@ -1,15 +1,13 @@
 use boll::*;
 use common::{Point2D, Rect};
 use core::controller::ControllerManager;
+use core::render::Renderer;
 use point; // defined in common, but loaded from main...
 use rand::Rng;
 use sdl2::event::{Event, WindowEvent};
-use sdl2::gfx::primitives::DrawRenderer;
 use sdl2::keyboard::Keycode;
-use sdl2::pixels::Color;
 use sdl2::rect::Rect as SDLRect;
-use sdl2::render::{BlendMode, Canvas};
-use sdl2::video::{FullscreenType, SwapInterval, Window};
+use sdl2::video::SwapInterval;
 use sdl2::{EventPump, VideoSubsystem};
 use sprites::SpriteManager;
 use std::f32::consts::PI;
@@ -61,20 +59,17 @@ impl AppBuilder {
             .unwrap();
         context.mouse().show_cursor(false);
 
-        let mut canvas = window.into_canvas().build().unwrap();
-        canvas.set_blend_mode(BlendMode::Add);
-        canvas.set_draw_color(Color::RGB(0, 0, 0));
-        canvas.clear();
-        canvas.present();
+        let canvas = window.into_canvas().build().unwrap();
+        let sprites = SpriteManager::new(canvas.texture_creator());
+       let screen = canvas.output_size().unwrap();
+       let renderer = Renderer::new(canvas);
 
         video.gl_set_swap_interval(SwapInterval::VSync)?;
 
         let event_pump = context.event_pump()?;
-        let sprites = SpriteManager::new(canvas.texture_creator());
-       let screen = canvas.output_size().unwrap();
 
         Ok(App {
-            canvas,
+            renderer,
             event_pump,
             sprites,
             state: self.state.unwrap_or_else(|| Box::new(ActiveState::new(screen))),
@@ -124,7 +119,7 @@ impl AppBuilder {
 }
 
 pub struct App {
-    canvas: Canvas<Window>,
+    renderer: Renderer,
     event_pump: EventPump,
     sprites: SpriteManager,
     state: Box<dyn AppState>,
@@ -180,14 +175,7 @@ impl App {
                     keycode: Some(Keycode::F11),
                     ..
                 } => {
-                    match self.canvas.window().fullscreen_state() {
-                        FullscreenType::Off => self
-                            .canvas
-                            .window_mut()
-                            .set_fullscreen(FullscreenType::Desktop),
-                        _ => self.canvas.window_mut().set_fullscreen(FullscreenType::Off),
-                    }
-                    .unwrap();
+                   self.renderer.toggle_fullscreen();
                 }
                 Event::Window {
                     win_event: WindowEvent::Resized(x, y),
@@ -238,10 +226,9 @@ impl App {
     }
 
     fn render(&mut self) {
-        self.canvas.set_draw_color(Color::RGB(0, 0, 0));
-        self.canvas.clear();
-        self.state.render(&mut self.canvas, &mut self.sprites);
-        self.canvas.present();
+       self.renderer.clear();
+        self.state.render(&mut self.renderer, &mut self.sprites);
+        self.renderer.present();
     }
 }
 
@@ -249,7 +236,7 @@ pub trait AppState {
     fn enter(&mut self, ctrl_man: &ControllerManager);
     fn leave(&mut self);
     fn update(&mut self, dt: Duration);
-    fn render(&mut self, canvas: &mut Canvas<Window>, sprites: &SpriteManager);
+    fn render(&mut self, renderer: &mut Renderer, sprites: &SpriteManager);
     fn handle_event(&mut self, event: Event);
 }
 
@@ -313,7 +300,7 @@ impl AppState for ActiveState {
         }
     }
 
-    fn render(&mut self, canvas: &mut Canvas<Window>, sprites: &SpriteManager) {
+    fn render(&mut self, renderer: &mut Renderer, sprites: &SpriteManager) {
         /* draw square of blocks */ {
             let blocks = 20;
             let size = 32;
@@ -323,15 +310,14 @@ impl AppState for ActiveState {
             );
             let block = sprites.get("block");
             for i in 0..blocks {
-                canvas
-                    .copy(
+                renderer
+                    .blit(
                         block,
                         None,
                         SDLRect::new((i) * size + offset.x, offset.y, size as u32, size as u32),
-                    )
-                    .unwrap();
-                canvas
-                    .copy(
+                    );
+                renderer
+                    .blit(
                         block,
                         None,
                         SDLRect::new(
@@ -340,10 +326,9 @@ impl AppState for ActiveState {
                             size as u32,
                             size as u32,
                         ),
-                    )
-                    .unwrap();
-                canvas
-                    .copy(
+                    );
+                renderer
+                    .blit(
                         block,
                         None,
                         SDLRect::new(
@@ -352,10 +337,9 @@ impl AppState for ActiveState {
                             size as u32,
                             size as u32,
                         ),
-                    )
-                    .unwrap();
-                canvas
-                    .copy(
+                    );
+                renderer
+                    .blit(
                         block,
                         None,
                         SDLRect::new(
@@ -364,8 +348,7 @@ impl AppState for ActiveState {
                             size as u32,
                             size as u32,
                         ),
-                    )
-                    .unwrap();
+                    );
             }
         }
 
@@ -378,8 +361,8 @@ impl AppState for ActiveState {
             let radius = 110.0 + size as f32 * 0.5;
             let angle = (self.mario_angle as f32 - 90.0) * PI / 180.0;
             let offset2 = point!((angle.cos() * radius) as i32, (angle.sin() * radius) as i32);
-            canvas
-                .copy_ex(
+            renderer
+                .blit_ex(
                     sprites.get("mario"),
                     None,
                     SDLRect::new(
@@ -392,29 +375,20 @@ impl AppState for ActiveState {
                     sdl2::rect::Point::new(size / 2, size / 2),
                     false,
                     false,
-                )
-                .unwrap();
+                );
            self.mario_angle = (self.mario_angle + 1.0) % 360.0;
         }
 
         /* draw circles and ellipses*/ {
             let p = point!((self.screen.width / 2) as i16, (self.screen.height / 2) as i16);
-            canvas
-                .circle(p.x, p.y, 100, Color::RGB(255, 255, 255))
-                .unwrap();
-            canvas
-                .aa_circle(p.x, p.y, 110, Color::RGB(255, 255, 255))
-                .unwrap();
-            canvas
-                .ellipse(p.x, p.y, 50, 100, Color::RGB(255, 255, 255))
-                .unwrap();
-            canvas
-                .aa_ellipse(p.x, p.y, 110, 55, Color::RGB(255, 255, 255))
-                .unwrap();
+            renderer.circle(p, 100, (255, 255, 255));
+            renderer.circle(p, 110, (255, 255, 255));
+            renderer.ellipse(p, (50, 100), (255, 255, 255));
+            renderer.ellipse(p, (110, 55), (255, 255, 255));
         }
 
         for b in &self.bolls {
-            b.draw(canvas, self.boll_size);
+            b.draw(renderer, self.boll_size);
         }
     }
 
index f48d9b3..e5e2aa6 100644 (file)
@@ -1,13 +1,12 @@
 use AppState;
-use sdl2::joystick::PowerLevel;
 use common::Point2D;
 use core::controller::Controller;
 use core::controller::ControllerManager;
+use core::render::Renderer;
 use point;
 use sdl2::event::Event;
+use sdl2::joystick::PowerLevel;
 use sdl2::rect::Rect;
-use sdl2::render::Canvas;
-use sdl2::video::Window;
 use sprites::SpriteManager;
 use std::cell::RefCell;
 use std::rc::Rc;
@@ -41,8 +40,8 @@ impl AppState for GameState {
        self.world.update(dt);
     }
 
-    fn render(&mut self, canvas: &mut Canvas<Window>, sprites: &SpriteManager) {
-       self.world.render(canvas, sprites);
+    fn render(&mut self, renderer: &mut Renderer, sprites: &SpriteManager) {
+       self.world.render(renderer, sprites);
     }
 
     fn handle_event(&mut self, _event: Event) {}
@@ -81,10 +80,10 @@ impl World {
        }
     }
 
-    pub fn render(&mut self, canvas: &mut Canvas<Window>, sprites: &SpriteManager) {
-       self.level.render(canvas, sprites);
+    pub fn render(&mut self, renderer: &mut Renderer, sprites: &SpriteManager) {
+       self.level.render(renderer, sprites);
        for o in &mut self.objects {
-           o.render(canvas, sprites);
+           o.render(renderer, sprites);
        }
     }
 
@@ -102,12 +101,12 @@ pub struct Level {
 }
 
 impl Level {
-    pub fn render(&mut self, canvas: &mut Canvas<Window>, _sprites: &SpriteManager) {
-       let w = canvas.viewport().width() as i32;
+    pub fn render(&mut self, renderer: &mut Renderer, _sprites: &SpriteManager) {
+       let w = renderer.viewport().0 as i32;
        for i in 1..11 {
            let y = (i * i - 1) as i32 + self.ground as i32;
-           canvas.set_draw_color((255 - i * 20, 255 - i * 20, 0));
-           canvas.draw_line((0, y), (w, y)).unwrap();
+           renderer.canvas().set_draw_color((255 - i * 20, 255 - i * 20, 0));
+           renderer.canvas().draw_line((0, y), (w, y)).unwrap();
        }
     }
 }
@@ -118,7 +117,7 @@ type Objects = Vec<Box<dyn Object>>;
 
 pub trait Object {
     fn update(&mut self, objects: &mut Objects, lvl: &Level, dt: Duration) -> ObjectState;
-    fn render(&self, _canvas: &mut Canvas<Window>, _sprites: &SpriteManager) {}
+    fn render(&self, _renderer: &mut Renderer, _sprites: &SpriteManager) {}
 }
 
 #[derive(PartialEq)]
@@ -198,35 +197,32 @@ impl Object for Character {
        Alive
     }
 
-    fn render(&self, canvas: &mut Canvas<Window>, sprites: &SpriteManager) {
+    fn render(&self, renderer: &mut Renderer, sprites: &SpriteManager) {
         let block = sprites.get("mario");
        let size = 32;
-        canvas.copy(block, None, Rect::new(self.pos.x as i32 - size as i32 / 2, self.pos.y as i32 - size as i32, size, size)).unwrap();
+        renderer.blit(block, None, Rect::new(self.pos.x as i32 - size as i32 / 2, self.pos.y as i32 - size as i32, size, size));
 
        let ctrl = &self.ctrl.borrow();
        let l = 300.0;
        let pos = (self.pos.x as i32, self.pos.y as i32);
        // axis values
        let p = (self.pos + ctrl.aim.to_axis_point() * l).to_i32().into();
-       canvas.set_draw_color((0, 255, 0));
-       canvas.draw_line(pos, p).unwrap();
-       draw_cross(canvas, p);
+       renderer.draw_line(pos, p, (0, 255, 0));
+       draw_cross(renderer, p);
        // values limited to unit vector
        let p = (self.pos + ctrl.aim.to_point() * l).to_i32().into();
-       canvas.set_draw_color((255, 0, 0));
-       canvas.draw_line(pos, p).unwrap();
-       draw_cross(canvas, p);
+       renderer.draw_line(pos, p, (255, 0, 0));
+       draw_cross(renderer, p);
        // circle values
        let p = (self.pos + Point2D::from(ctrl.aim.a) * l).to_i32().into();
-       canvas.set_draw_color((0, 0, 255));
-       canvas.draw_line(pos, p).unwrap();
-       draw_cross(canvas, p);
+       renderer.draw_line(pos, p, (0, 0, 255));
+       draw_cross(renderer, p);
     }
 }
 
-fn draw_cross(canvas: &mut Canvas<Window>, p: (i32, i32)) {
-    canvas.draw_line((p.0 - 5, p.1), (p.0 + 5, p.1)).unwrap();
-    canvas.draw_line((p.0, p.1 - 5), (p.0, p.1 + 5)).unwrap();
+fn draw_cross(renderer: &mut Renderer, p: (i32, i32)) {
+    renderer.canvas().draw_line((p.0 - 5, p.1), (p.0 + 5, p.1)).unwrap();
+    renderer.canvas().draw_line((p.0, p.1 - 5), (p.0, p.1 + 5)).unwrap();
 }
 
 ////////// BOLL ////////////////////////////////////////////////////////////////
@@ -267,11 +263,11 @@ impl Object for Boll {
        Alive
     }
 
-    fn render(&self, canvas: &mut Canvas<Window>, _sprites: &SpriteManager) {
+    fn render(&self, renderer: &mut Renderer, _sprites: &SpriteManager) {
         let block = _sprites.get("block");
        let size = 4 + self.bounces * 6;
-        canvas.copy(block, None, Rect::new(self.pos.x as i32 - size as i32 / 2, self.pos.y as i32 - size as i32 / 2, size as u32, size as u32)).unwrap();
-       // canvas.set_draw_color((0, self.bounces * 100, 255));
-       // canvas.draw_point((self.pos.x as i32, self.pos.y as i32)).unwrap();
+        renderer.blit(block, None, Rect::new(self.pos.x as i32 - size as i32 / 2, self.pos.y as i32 - size as i32 / 2, size as u32, size as u32));
+       // renderer.set_draw_color((0, self.bounces * 100, 255));
+       // renderer.draw_point((self.pos.x as i32, self.pos.y as i32)).unwrap();
     }
 }
index 9bcbe0c..c2a1f0a 100644 (file)
@@ -1,3 +1,4 @@
 pub mod app;
 pub mod controller;
 pub mod game;
+pub mod render;
diff --git a/src/core/render.rs b/src/core/render.rs
new file mode 100644 (file)
index 0000000..7932d55
--- /dev/null
@@ -0,0 +1,97 @@
+use sdl2::gfx::primitives::DrawRenderer;
+use sdl2::pixels::Color;
+use sdl2::rect::{Point, Rect};
+use sdl2::render::{BlendMode, Canvas, Texture};
+use sdl2::video::{FullscreenType, Window};
+
+pub struct Renderer {
+    canvas: Canvas<Window>,
+}
+
+impl Renderer {
+    pub fn new(mut canvas: Canvas<Window>) -> Self {
+        canvas.set_blend_mode(BlendMode::Add);
+        canvas.set_draw_color((0, 0, 0));
+        canvas.clear();
+        canvas.present();
+       Renderer { canvas }
+    }
+
+    pub fn canvas(&mut self) -> &mut Canvas<Window> {
+       &mut self.canvas
+    }
+
+    pub fn viewport(&self) -> (u16, u16) {
+       let vp = self.canvas.viewport();
+       (vp.width() as u16, vp.height() as u16)
+    }
+
+    pub fn toggle_fullscreen(&mut self) {
+        match self.canvas.window().fullscreen_state() {
+            FullscreenType::Off => self
+                .canvas
+                .window_mut()
+                .set_fullscreen(FullscreenType::Desktop),
+            _ => self.canvas.window_mut().set_fullscreen(FullscreenType::Off),
+        }
+        .unwrap();
+    }
+
+    pub fn clear(&mut self) {
+        self.canvas.set_draw_color((0, 0, 0));
+        self.canvas.clear();
+    }
+
+    pub fn present(&mut self) {
+        self.canvas.present();
+    }
+
+    pub fn blit<R1, R2>(&mut self, texture: &Texture, src: R1, dst: R2)
+    where R1: Into<Option<Rect>>,
+          R2: Into<Option<Rect>>
+    {
+       self.canvas.copy(texture, src, dst).unwrap();
+    }
+
+    pub fn blit_ex<R1, R2, P>(&mut self,
+                              texture: &Texture,
+                              src: R1,
+                              dst: R2,
+                              angle: f64,
+                              center: P,
+                              flip_horizontal: bool,
+                              flip_vertical: bool)
+    where R1: Into<Option<Rect>>,
+          R2: Into<Option<Rect>>,
+          P: Into<Option<Point>>
+    {
+       self.canvas.copy_ex(texture, src, dst, angle, center, flip_horizontal, flip_vertical).unwrap();
+    }
+
+    pub fn circle<P, C>(&self, pos: P, rad: i16, col: C)
+    where P: Into<(i16, i16)>,
+         C: Into<Color>,
+    {
+       let pos = pos.into();
+       self.canvas.aa_circle(pos.0, pos.1, rad, col.into()).unwrap();
+    }
+
+    pub fn ellipse<P, R, C>(&self, pos: P, rad: R, col: C)
+    where P: Into<(i16, i16)>,
+         R: Into<(i16, i16)>,
+         C: Into<Color>,
+    {
+       let pos = pos.into();
+       let rad = rad.into();
+       self.canvas.aa_ellipse(pos.0, pos.1, rad.0, rad.1, col.into()).unwrap();
+    }
+
+    pub fn draw_line<P1, P2, C>(&mut self, start: P1, end: P2, col: C)
+    where P1: Into<Point>,
+         P2: Into<Point>,
+         C: Into<Color>,
+    {
+       self.canvas.set_draw_color(col);
+       self.canvas.draw_line(start, end).unwrap();
+    }
+}