-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
one-offs: implemented individual vs. texture draw example
- Loading branch information
Showing
5 changed files
with
389 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
) | ||
} | ||
} | ||
} | ||
} |