use wasm4fun_core::{blit, blit_sub, BLIT_FLIP_X, BLIT_FLIP_Y, BLIT_ROTATE};
#[derive(Copy, Clone)]
pub enum Rotation {
Rotate0,
Rotate90,
Rotate180,
Rotate270,
}
impl Rotation {
pub const fn add(&self, other: Rotation) -> Self {
match (self, other) {
(Self::Rotate0, other) => other,
(self2, Self::Rotate0) => *self2,
(Self::Rotate90, Self::Rotate90) => Self::Rotate180,
(Self::Rotate90, Self::Rotate180) => Self::Rotate270,
(Self::Rotate90, Self::Rotate270) => Self::Rotate0,
(Self::Rotate180, Self::Rotate90) => Self::Rotate270,
(Self::Rotate180, Self::Rotate180) => Self::Rotate0,
(Self::Rotate180, Self::Rotate270) => Self::Rotate90,
(Self::Rotate270, Self::Rotate90) => Self::Rotate0,
(Self::Rotate270, Self::Rotate180) => Self::Rotate90,
(Self::Rotate270, Self::Rotate270) => Self::Rotate180,
}
}
}
#[derive(Clone, Copy)]
pub struct SpriteViewImpl<'a> {
sprite: &'a Sprite<'a>,
rotation: Rotation,
src_x: u32,
src_y: u32,
width: u32,
height: u32,
flip_horizontal: bool,
flip_vertical: bool,
}
impl<'a> SpriteViewImpl<'a> {
pub const fn new(sprite: &'a Sprite) -> Self {
Self {
sprite,
rotation: Rotation::Rotate0,
src_x: 0,
src_y: 0,
width: sprite.width,
height: sprite.height,
flip_horizontal: false,
flip_vertical: false,
}
}
pub const fn width(&self) -> u32 {
self.width
}
pub const fn height(&self) -> u32 {
self.height
}
pub const fn rotate(&self, rotation: Rotation) -> Self {
let mut new = *self;
new.rotation = new.rotation.add(rotation);
new
}
pub const fn flip_horizontally(&self, flip_horizontally: bool) -> Self {
let mut new = *self;
new.flip_horizontal = flip_horizontally;
new
}
pub const fn flip_vertically(&self, flip_vertically: bool) -> Self {
let mut new = *self;
new.flip_vertical = flip_vertically;
new
}
pub const fn clip(&self, src_x: u32, src_y: u32, width: u32, height: u32) -> Self {
let mut new = *self;
new.src_x += src_x;
new.src_y += src_y;
new.width = width;
new.height = height;
new
}
pub fn blit(&self, x: i32, y: i32) {
let flags = match (&self.rotation, &self.flip_horizontal, &self.flip_vertical) {
(Rotation::Rotate0, false, false) => 0,
(Rotation::Rotate90, false, false) => BLIT_FLIP_X | BLIT_FLIP_Y | BLIT_ROTATE,
(Rotation::Rotate180, false, false) => BLIT_FLIP_X | BLIT_FLIP_Y,
(Rotation::Rotate270, false, false) => BLIT_ROTATE,
(Rotation::Rotate0, false, true) => BLIT_FLIP_Y,
(Rotation::Rotate90, false, true) => BLIT_FLIP_X | BLIT_ROTATE,
(Rotation::Rotate180, false, true) => BLIT_FLIP_X,
(Rotation::Rotate270, false, true) => BLIT_FLIP_Y | BLIT_ROTATE,
(Rotation::Rotate0, true, false) => BLIT_FLIP_X,
(Rotation::Rotate90, true, false) => BLIT_FLIP_Y | BLIT_ROTATE,
(Rotation::Rotate180, true, false) => BLIT_FLIP_Y,
(Rotation::Rotate270, true, false) => BLIT_FLIP_X | BLIT_ROTATE,
(Rotation::Rotate0, true, true) => BLIT_FLIP_X | BLIT_FLIP_Y,
(Rotation::Rotate90, true, true) => BLIT_ROTATE,
(Rotation::Rotate180, true, true) => 0,
(Rotation::Rotate270, true, true) => BLIT_FLIP_X | BLIT_FLIP_Y | BLIT_ROTATE,
};
self.sprite.blit_sub_with_flags(
x,
y,
self.width,
self.height,
self.src_x,
self.src_y,
flags,
);
}
}
impl<'a> From<&'a Sprite<'a>> for SpriteViewImpl<'a> {
fn from(sprite: &'a Sprite) -> Self {
Self::new(sprite)
}
}
#[derive(Clone, Debug)]
pub struct Sprite<'a> {
width: u32,
height: u32,
flags: u32,
data: &'a [u8],
}
impl<'a> Sprite<'a> {
pub const fn new(width: u32, height: u32, flags: u32, data: &'a [u8]) -> Self {
Self {
width,
height,
flags,
data,
}
}
pub const fn width(&self) -> u32 {
self.width
}
pub const fn height(&self) -> u32 {
self.height
}
pub const fn rotate(&self, rotation: Rotation) -> SpriteViewImpl {
let view = SpriteViewImpl::new(self);
SpriteViewImpl::rotate(&view, rotation)
}
pub fn flip_horizontally(&self, flip_horizontally: bool) -> SpriteViewImpl {
let view = SpriteViewImpl::new(self);
SpriteViewImpl::flip_horizontally(&view, flip_horizontally)
}
pub const fn flip_vertically(&self, flip_vertically: bool) -> SpriteViewImpl {
let view = SpriteViewImpl::new(self);
SpriteViewImpl::flip_vertically(&view, flip_vertically)
}
pub const fn clip(&self, src_x: u32, src_y: u32, width: u32, height: u32) -> SpriteViewImpl {
let view = SpriteViewImpl::new(self);
SpriteViewImpl::clip(&view, src_x, src_y, width, height)
}
pub fn blit(&self, x: i32, y: i32) {
blit(self.data, x, y, self.width, self.height, self.flags);
}
#[allow(clippy::too_many_arguments)]
fn blit_sub_with_flags(
&self,
x: i32,
y: i32,
width: u32,
height: u32,
src_x: u32,
src_y: u32,
flags: u32,
) {
blit_sub(
self.data,
x,
y,
width,
height,
src_x,
src_y,
self.width,
self.flags | flags,
);
}
}
pub trait SpriteView<'a> {
fn width(&self) -> u32;
fn height(&self) -> u32;
fn rotate(&'a self, rotation: Rotation) -> SpriteViewImpl<'a>;
fn flip_horizontally(&'a self, flip_horizontally: bool) -> SpriteViewImpl<'a>;
fn flip_vertically(&'a self, flip_vertically: bool) -> SpriteViewImpl<'a>;
fn clip(&'a self, src_x: u32, src_y: u32, width: u32, height: u32) -> SpriteViewImpl<'a>;
fn blit(&self, x: i32, y: i32);
}
impl<'a> SpriteView<'a> for SpriteViewImpl<'a> {
fn width(&self) -> u32 {
SpriteViewImpl::width(self)
}
fn height(&self) -> u32 {
SpriteViewImpl::height(self)
}
fn rotate(&'a self, rotation: Rotation) -> SpriteViewImpl<'a> {
SpriteViewImpl::rotate(self, rotation)
}
fn flip_horizontally(&'a self, flip_horizontally: bool) -> SpriteViewImpl<'a> {
SpriteViewImpl::flip_horizontally(self, flip_horizontally)
}
fn flip_vertically(&'a self, flip_vertically: bool) -> SpriteViewImpl<'a> {
SpriteViewImpl::flip_vertically(self, flip_vertically)
}
fn clip(&'a self, src_x: u32, src_y: u32, width: u32, height: u32) -> SpriteViewImpl<'a> {
SpriteViewImpl::clip(self, src_x, src_y, width, height)
}
fn blit(&self, x: i32, y: i32) {
SpriteViewImpl::blit(self, x, y)
}
}
impl<'a> SpriteView<'a> for Sprite<'a> {
fn width(&self) -> u32 {
Sprite::width(self)
}
fn height(&self) -> u32 {
Sprite::height(self)
}
fn rotate(&'a self, rotation: Rotation) -> SpriteViewImpl<'a> {
Sprite::rotate(self, rotation)
}
fn flip_horizontally(&'a self, flip_horizontally: bool) -> SpriteViewImpl<'a> {
Sprite::flip_horizontally(self, flip_horizontally)
}
fn flip_vertically(&'a self, flip_vertically: bool) -> SpriteViewImpl<'a> {
Sprite::flip_vertically(self, flip_vertically)
}
fn clip(&'a self, src_x: u32, src_y: u32, width: u32, height: u32) -> SpriteViewImpl<'a> {
Sprite::clip(self, src_x, src_y, width, height)
}
fn blit(&self, x: i32, y: i32) {
Sprite::blit(self, x, y)
}
}