Cleaned up drawing

master
Mark 2023-12-20 20:31:09 -08:00
parent fb63a02d31
commit 0f5da721ed
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
3 changed files with 83 additions and 92 deletions

View File

@ -1,4 +1,3 @@
use sdl2::rect::{Point, Rect};
use sdl2::render::Canvas;
use sdl2::video::Window;
@ -26,49 +25,9 @@ impl Drawable for Doodad {
sa: &SpriteAtlas,
c: &Camera,
) -> Result<(), String> {
let win_size = PhysVec::from(canvas.window().size());
let draw_pos = self.screen_position(canvas, &c);
// Don't draw if off screen
if draw_pos.x < 0.0
|| draw_pos.x > win_size.x
|| draw_pos.y < 0.0
|| draw_pos.y > win_size.y
{
return Ok(());
}
let pos = self.screen_position(canvas, c);
let sprite = sa.get(&self.sprite);
let mut dest_rect_0 = Rect::new(
0,
0,
sprite.rect.width() / self.scale,
sprite.rect.height() / self.scale,
);
dest_rect_0.center_on(Point::new(
sprite.rect.width() as i32 / (2 * self.scale) as i32,
sprite.rect.height() as i32 / (2 * self.scale) as i32,
));
// set the current frame for time
dest_rect_0.set_x(draw_pos.x.round() as i32);
dest_rect_0.set_y(draw_pos.y.round() as i32);
// copy the frame to the canvas
canvas.copy_ex(
&sprite.texture,
Some(sprite.rect),
Some(dest_rect_0),
self.angle.to_degrees(), // angle
Point::new(
sprite.rect.width() as i32 / (2 * self.scale) as i32,
sprite.rect.width() as i32 / (2 * self.scale) as i32,
), // center
false,
false,
)?;
sprite.draw(canvas, pos, self.angle)?;
return Ok(());
}
}

View File

@ -1,4 +1,3 @@
use sdl2::rect::{Point, Rect};
use sdl2::render::Canvas;
use sdl2::video::Window;
@ -12,7 +11,6 @@ use crate::SpriteAtlas;
pub struct Ship {
pub body: PhysBody,
kind: ShipKind,
scale: u32,
}
impl Ship {
@ -20,7 +18,6 @@ impl Ship {
Ship {
body: PhysBody::new(),
kind,
scale: 2,
}
}
}
@ -36,40 +33,9 @@ impl Drawable for Ship {
sa: &SpriteAtlas,
c: &Camera,
) -> Result<(), String> {
let win_size = PhysVec::from(canvas.window().size());
let draw_pos = self.screen_position(canvas, &c);
// Don't draw if off screen
if draw_pos.x < 0.0
|| draw_pos.x > win_size.x
|| draw_pos.y < 0.0
|| draw_pos.y > win_size.y
{
return Ok(());
}
let pos = self.screen_position(canvas, c);
let sprite = sa.get(self.kind.sprite());
let mut dest_rect_0 = Rect::new(0, 0, 120 / self.scale, 270 / self.scale);
dest_rect_0.center_on(Point::new(
120 / (2 * self.scale) as i32,
270 / (2 * self.scale) as i32,
));
// set the current frame for time
dest_rect_0.set_x(draw_pos.x.round() as i32);
dest_rect_0.set_y(draw_pos.y.round() as i32);
// copy the frame to the canvas
canvas.copy_ex(
&sprite.texture,
Some(sprite.rect),
Some(dest_rect_0),
self.body.angle.to_degrees(), // angle
Point::new(120 / (2 * self.scale) as i32, 270 / (2 * self.scale) as i32), // center
false,
false,
)?;
sprite.draw(canvas, pos, self.body.angle.to_degrees())?;
return Ok(());
}
}

View File

@ -1,23 +1,85 @@
use image::io::Reader as ImageReader;
use sdl2::{
rect::Rect,
render::{Texture, TextureCreator},
video::WindowContext,
rect::{Point, Rect},
render::{Canvas, Texture, TextureCreator},
video::{Window, WindowContext},
};
use std::collections::HashMap;
use crate::physics::PhysVec;
/// A handle for a sprite inside a SpriteAtlas
pub struct Sprite<'a> {
pub texture: &'a Texture<'a>,
pub rect: Rect,
texture: &'a Texture<'a>,
rect: Rect,
scale: f64,
}
impl<'a> Sprite<'a> {
/// Draw this sprite on the screen.
///
/// Position represents on-screen position,
/// NOT world position.
pub fn draw(
&self,
canvas: &mut Canvas<Window>,
position: PhysVec,
angle: f64,
) -> Result<(), String> {
let win_size = PhysVec::from(canvas.window().size());
let width = self.rect.width();
let height = self.rect.height();
// Don't draw if we're not on the screen.
// An offset is included to ensure we're completely
// off the screen. We add the whole width intentionally.
if position.x < -1.0 * (width as f64)
|| position.x > win_size.x + width as f64
|| position.y < -1.0 * (height as f64)
|| position.y > win_size.y + height as f64
{
return Ok(());
}
let mut dest = Rect::new(
0,
0,
(width as f64 / self.scale) as u32,
(height as f64 / self.scale) as u32,
);
dest.center_on(Point::new(
(width as f64 / (2.0 * self.scale)) as i32,
(height as f64 / (2.0 * self.scale)) as i32,
));
// set the current frame for time
dest.set_x(position.x.round() as i32);
dest.set_y(position.y.round() as i32);
// copy the frame to the canvas
canvas.copy_ex(
&self.texture,
Some(self.rect),
Some(dest),
angle, // angle
Point::new(
(width as f64 / (2.0 * self.scale)) as i32,
(height as f64 / (2.0 * self.scale)) as i32,
), // center
false,
false,
)?;
return Ok(());
}
}
/// A cache of textures we use when drawing the screen.
///
/// This is implemented very carefully, since SDL2 textures have tricky lifetimes.
pub struct SpriteAtlas<'a> {
data: HashMap<String, (Texture<'a>, Rect)>,
data: HashMap<String, (Texture<'a>, Rect, f64)>,
}
impl<'a> SpriteAtlas<'a> {
@ -26,18 +88,19 @@ impl<'a> SpriteAtlas<'a> {
data: HashMap::new(),
};
b.load_one(texture_creator, "gypsum.png")?;
b.load_one(texture_creator, "a0.png")?;
b.load_one(texture_creator, "small.png")?;
b.load_one(texture_creator, "earth.png")?;
b.load_one(texture_creator, "gypsum.png", 1.5)?;
b.load_one(texture_creator, "a0.png", 1.0)?;
b.load_one(texture_creator, "small.png", 1.0)?;
b.load_one(texture_creator, "earth.png", 1.0)?;
return Ok(b);
}
pub fn get(&'a self, name: &str) -> Sprite<'a> {
let (texture, rect) = self.data.get(name).unwrap();
let (texture, rect, scale) = self.data.get(name).unwrap();
return Sprite {
texture,
scale: scale.clone(),
rect: rect.clone(),
};
}
@ -46,6 +109,7 @@ impl<'a> SpriteAtlas<'a> {
&mut self,
texture_creator: &'a TextureCreator<WindowContext>,
s: &str,
scale: f64,
) -> Result<(), String> {
let im = ImageReader::open(format!("assets/{s}"))
.unwrap()
@ -67,8 +131,10 @@ impl<'a> SpriteAtlas<'a> {
.create_texture_from_surface(&surface)
.map_err(|e| e.to_string())?;
self.data
.insert(s.to_owned(), (texture, Rect::new(0, 0, width, height)));
self.data.insert(
s.to_owned(),
(texture, Rect::new(0, 0, width, height), scale),
);
return Ok(());
}