Skip to content

Commit

Permalink
one-offs: implemented individual vs. texture draw example
Browse files Browse the repository at this point in the history
  • Loading branch information
thlorenz committed Jul 23, 2020
1 parent 8e6aba2 commit 18cc4b3
Show file tree
Hide file tree
Showing 5 changed files with 389 additions and 0 deletions.
61 changes: 61 additions & 0 deletions one-offs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions one-offs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "one-offs"
version = "0.1.0"
authors = ["Thorsten Lorenz <thlorenz@gmx.de>"]
edition = "2018"

[dependencies]
[dependencies.sdl2]
version="0.34.2"
default-features = false
features = ["image"]

[[bin]]
name = "draw_to_texture"
path = "src/draw_to_texture.rs"
Binary file added one-offs/assets/floor-tiles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
160 changes: 160 additions & 0 deletions one-offs/src/draw_to_texture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
use one_offs::{init_renderer, Sprite};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect};
use sdl2::render::{Texture, WindowCanvas};
use sdl2::Sdl;
use std::error::Error;

const TILES_WIDTH: u32 = 512;
const TILES_HEIGHT: u32 = 512;
const TILES_PER_ROW: u32 = 8;
const TILES_PER_COL: u32 = 8;
const TILE_WIDTH: u32 = TILES_WIDTH / TILES_PER_COL;
const TILE_HEIGHT: u32 = TILES_HEIGHT / TILES_PER_ROW;

fn get_clip(col: u32, row: u32) -> Rect {
Rect::new(
(col * TILE_WIDTH) as i32,
(row * TILE_HEIGHT) as i32,
TILE_WIDTH,
TILE_HEIGHT,
)
}

struct Tile {
pub position: Point,
pub clip: Rect,
}

fn render_tiles(
canvas: &mut WindowCanvas,
floor_tiles_sprite: &Sprite,
tiles: &Vec<Tile>,
offset: &Point,
render_all: bool,
) -> Result<(), String> {
let (width, height) = canvas.window().size();
let padded_window_rect = Rect::new(
-(TILE_WIDTH as i32),
-(TILE_HEIGHT as i32),
width + TILE_WIDTH,
height + TILE_HEIGHT,
);
for tile in tiles {
let x = tile.position.x - offset.x;
let y = tile.position.y - offset.y;
if render_all || padded_window_rect.contains_point(Point::new(x, y)) {
floor_tiles_sprite.render(canvas, x, y, tile.clip)?;
}
}
Ok(())
}

fn render_texture(
canvas: &mut WindowCanvas,
texture: &Texture,
offset: &Point,
) -> Result<(), String> {
let (width, height) = canvas.window().size();
let src = Rect::new(offset.x, offset.y, width, height);
canvas.copy(texture, src, None)
}

fn run(sdl_context: &Sdl, canvas: &mut WindowCanvas) -> Result<(), Box<dyn Error>> {
let mut event_pump = sdl_context
.event_pump()
.expect("FATAL: failed to init event_pump");

let texture_creator = canvas.texture_creator();
let floor_tiles_sprite =
Sprite::load_from_file("assets/floor-tiles.png".as_ref(), &texture_creator)?;

let mut clip_row = 0;
let mut clip_col = 0;
let mut tiles: Vec<Tile> = Vec::new();
let mut speed = Point::new(0, 0);
let mut offset = Point::new(100 * TILE_WIDTH as i32, 100 * TILE_HEIGHT as i32);

eprintln!("Use WASD to move the tiles and Space to render using texture target to see 4-5x drop in CPU usage.");

for row in 0..200 {
for col in 0..200 {
let position = Point::new((col * TILE_WIDTH) as i32, (row * TILE_HEIGHT) as i32);
let clip = get_clip(clip_col, clip_row);
tiles.push(Tile { position, clip });
clip_col += 1;
if clip_col == TILES_PER_COL {
clip_col = 0;
clip_row += 1;
};
if clip_row == TILES_PER_ROW {
clip_row = 0
};
}
}

let texture_width = 200 * TILE_WIDTH;
let texture_height = 200 * TILE_HEIGHT;
let mut tgt_texture = texture_creator.create_texture_target(
canvas.default_pixel_format(),
texture_width,
texture_height,
)?;
let mut use_texture: bool = false;

canvas.with_texture_canvas(&mut tgt_texture, |texture_canvas| {
render_tiles(
texture_canvas,
&floor_tiles_sprite,
&tiles,
&Point::new(0, 0),
true,
)
.expect("FATAL: failed to render to target texture");
})?;

'running: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => break 'running,
Event::KeyDown { keycode: k, .. } => match k {
Some(Keycode::W) => speed.y -= 1,
Some(Keycode::S) => speed.y += 1,
Some(Keycode::A) => speed.x -= 1,
Some(Keycode::D) => speed.x += 1,
Some(Keycode::Space) => {
use_texture = !use_texture;
eprintln!("using texture {}", use_texture);
}
_ => {}
},
_ => {}
}
}

canvas.set_draw_color(Color::RGBA(0xff, 0xff, 0xff, 0xff));
canvas.clear();
if use_texture {
render_texture(canvas, &tgt_texture, &offset)?;
} else {
render_tiles(canvas, &floor_tiles_sprite, &tiles, &offset, false)?;
}
canvas.present();

offset.x += speed.x;
offset.y += speed.y;
}
Ok(())
}

fn main() {
let (sdl_context, mut canvas) =
init_renderer().expect("FATAL: failed to initialize window and canvas.");
run(&sdl_context, &mut canvas).expect("FATAL: something failed in the game loop");
}
153 changes: 153 additions & 0 deletions one-offs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use sdl2::image::LoadSurface;
use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect};
use sdl2::render::{BlendMode, Texture, TextureCreator, WindowCanvas};
use sdl2::surface::Surface;
use sdl2::video::WindowContext;
use sdl2::Sdl;
use std::error::Error;
use std::path::Path;

pub fn init_renderer() -> Result<(Sdl, WindowCanvas), Box<dyn Error>> {
let sdl_context: Sdl = sdl2::init()?;
let video = sdl_context.video()?;

let window = video
.window("SDL One Offs", 1280, 960)
// .position(-600, 0)
.position_centered()
.resizable()
.build()?;

let canvas = window.into_canvas().accelerated().present_vsync().build()?;

Ok((sdl_context, canvas))
}

pub fn load_media<'a>(
path: &'a str,
texture_creator: &'a TextureCreator<WindowContext>,
) -> Result<Texture<'a>, Box<dyn Error>> {
let surface = Surface::load_bmp(path)?;
let texture = texture_creator.create_texture_from_surface(surface)?;
Ok(texture)
}

pub enum Flip {
None,
Horizontal,
Vertical,
}

pub struct Sprite<'a> {
texture: Texture<'a>,
width: u32,
height: u32,
}

impl<'a> Sprite<'a> {
pub fn from_surface(
surface: Surface,
texture_creator: &'a TextureCreator<WindowContext>,
) -> Result<Self, Box<dyn Error>> {
let width = surface.width();
let height = surface.height();
let texture = texture_creator.create_texture_from_surface(surface)?;

Ok(Sprite {
texture,
width,
height,
})
}

pub fn load_from_file(
image_path: &Path,
texture_creator: &'a TextureCreator<WindowContext>,
) -> Result<Self, Box<dyn Error>> {
let mut surface = Surface::from_file(image_path)
.unwrap_or_else(|_| panic!("FATAL: unable to load surface from file {:?}", image_path));

surface.set_color_key(true, Color::RGB(0, 0xff, 0xff))?;
Sprite::from_surface(surface, texture_creator)
}

pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}

pub fn set_alpha(&mut self, alpha: u8) {
self.texture.set_alpha_mod(alpha)
}

pub fn set_blend_mode(&mut self, blend_mode: BlendMode) {
self.texture.set_blend_mode(blend_mode)
}

pub fn set_color(&mut self, r: u8, g: u8, b: u8) {
self.texture.set_color_mod(r, g, b);
}

pub fn render<R2>(
&self,
canvas: &mut WindowCanvas,
x: i32,
y: i32,
clip: R2,
) -> Result<(), String>
where
R2: Into<Option<Rect>>,
{
self.render_ex(canvas, x, y, clip, 0.0, None, &Flip::None)
}

pub fn render_ex<R2, P>(
&self,
canvas: &mut WindowCanvas,
x: i32,
y: i32,
clip: R2,
angle: f64,
center: P,
flip: &Flip,
) -> Result<(), String>
where
R2: Into<Option<Rect>>,
P: Into<Option<Point>>,
{
let (flip_horizontal, flip_vertical) = match flip {
Flip::None => (false, false),
Flip::Horizontal => (true, false),
Flip::Vertical => (false, true),
};
match clip.into() {
None => {
let rect = Rect::new(x, y, self.width, self.height);
canvas.copy_ex(
&self.texture,
None,
rect,
angle,
center,
flip_horizontal,
flip_vertical,
)
}
Some(clip) => {
let rect = Rect::new(x, y, clip.width(), clip.height());
canvas.copy_ex(
&self.texture,
clip,
rect,
angle,
center,
flip_horizontal,
flip_vertical,
)
}
}
}
}

0 comments on commit 18cc4b3

Please sign in to comment.