use crate::pass::encoded_2d::Flat2DData; use amethyst::{ assets::{Asset, AssetStorage, Handle, ProcessingState, Result as AssetsResult}, core::{ nalgebra::{Point3, Vector4}, GlobalTransform, }, ecs::{Join, Read, ReadStorage, System, VecStorage, Write}, renderer::{ ActiveCamera, Camera, Flipped, Hidden, HiddenPropagate, Sprite as SpriteFrame, Texture, Transparent, }, }; #[derive(Debug, PartialEq)] pub struct Sprite { pub texture: Handle, pub sprite_data: SpriteFrame, } impl Asset for Sprite { const NAME: &'static str = "Sprite"; type Data = Self; type HandleStorage = VecStorage>; } impl From for AssetsResult> { fn from(sprite: Sprite) -> AssetsResult> { Ok(ProcessingState::Loaded(sprite)) } } pub struct SpriteFlat2DAssetEncoder; impl<'a> System<'a> for SpriteFlat2DAssetEncoder { type SystemData = ( Write<'a, Vec>, ReadStorage<'a, Handle>, Read<'a, AssetStorage>, ReadStorage<'a, GlobalTransform>, ReadStorage<'a, Flipped>, ReadStorage<'a, Transparent>, ReadStorage<'a, Hidden>, ReadStorage<'a, HiddenPropagate>, ); fn run( &mut self, (mut buffer, handles, storage, transforms, flips, transparent, hidden, hidden_prop): Self::SystemData, ) { for (handle, transform, flip, transparent, _, _) in ( &handles, &transforms, flips.maybe(), transparent.maybe(), !&hidden, !&hidden_prop, ) .join() { if let Some(sprite) = storage.get(handle) { encode_sprite( &mut buffer, &sprite, &transform, flip, transparent.is_some(), ); } } } } pub struct ImageFlat2DAssetEncoder; impl<'a> System<'a> for ImageFlat2DAssetEncoder { type SystemData = ( Write<'a, Vec>, ReadStorage<'a, Handle>, Read<'a, AssetStorage>, ReadStorage<'a, GlobalTransform>, ReadStorage<'a, Flipped>, ReadStorage<'a, Transparent>, ReadStorage<'a, Hidden>, ReadStorage<'a, HiddenPropagate>, ); fn run( &mut self, (mut buffer, handles, storage, transforms, flips, transparent, hidden, hidden_prop): Self::SystemData, ) { for (handle, transform, flip, transparent, _, _) in ( &handles, &transforms, flips.maybe(), transparent.maybe(), !&hidden, !&hidden_prop, ) .join() { if let Some(tex) = storage.get(handle) { encode_image( &mut buffer, tex, handle.clone(), transform, flip, transparent.is_some(), ); } } } } fn encode_sprite( buffer: &mut Vec, sprite: &Sprite, transform: &GlobalTransform, flip: Option<&Flipped>, transparent: bool, ) { let sprite_data = &sprite.sprite_data; let (flip_horizontal, flip_vertical) = match flip { Some(Flipped::Horizontal) => (true, false), Some(Flipped::Vertical) => (false, true), Some(Flipped::Both) => (true, true), _ => (false, false), }; let tex_coords = &sprite_data.tex_coords; let (uv_left, uv_right) = if flip_horizontal { (tex_coords.right, tex_coords.left) } else { (tex_coords.left, tex_coords.right) }; let (uv_bottom, uv_top) = if flip_vertical { (tex_coords.top, tex_coords.bottom) } else { (tex_coords.bottom, tex_coords.top) }; let dir_x = transform.0.column(0) * sprite_data.width; let dir_y = transform.0.column(1) * sprite_data.height; // The offsets are negated to shift the sprite left and down relative to the entity, in // regards to pivot points. This is the convention adopted in: // // * libgdx: // * godot: let pos = transform.0 * Vector4::new(-sprite_data.offsets[0], -sprite_data.offsets[1], 0.0, 1.0); buffer.push(Flat2DData { texture: sprite.texture.clone(), dir_x, dir_y, pos, uv_left, uv_right, uv_top, uv_bottom, transparent, }); } fn encode_image( buffer: &mut Vec, texture: &Texture, texture_handle: Handle, transform: &GlobalTransform, flip: Option<&Flipped>, transparent: bool, ) { let (width, height) = texture.size(); let (uv_left, uv_right, uv_bottom, uv_top) = match flip { Some(Flipped::Horizontal) => (1.0, 0.0, 0.0, 1.0), Some(Flipped::Vertical) => (0.0, 1.0, 1.0, 0.0), Some(Flipped::Both) => (1.0, 0.0, 1.0, 0.0), _ => (0.0, 1.0, 0.0, 1.0), }; let dir_x = transform.0.column(0) * (width as f32); let dir_y = transform.0.column(1) * (height as f32); let pos = transform.0 * Vector4::new(1.0, 1.0, 0.0, 1.0); buffer.push(Flat2DData { texture: texture_handle, dir_x, dir_y, pos, uv_left, uv_right, uv_top, uv_bottom, transparent, }); }