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<Texture>,
pub sprite_data: SpriteFrame,
}
impl Asset for Sprite {
const NAME: &'static str = "Sprite";
type Data = Self;
type HandleStorage = VecStorage<Handle<Self>>;
}
impl From<Sprite> for AssetsResult<ProcessingState<Sprite>> {
fn from(sprite: Sprite) -> AssetsResult<ProcessingState<Sprite>> {
Ok(ProcessingState::Loaded(sprite))
}
}
pub struct SpriteFlat2DAssetEncoder;
impl<'a> System<'a> for SpriteFlat2DAssetEncoder {
type SystemData = (
Write<'a, Vec<Flat2DData>>,
ReadStorage<'a, Handle<Sprite>>,
Read<'a, AssetStorage<Sprite>>,
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<Flat2DData>>,
ReadStorage<'a, Handle<Texture>>,
Read<'a, AssetStorage<Texture>>,
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<Flat2DData>,
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: <https://gamedev.stackexchange.com/q/22553>
// * godot: <https://godotengine.org/qa/9784>
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<Flat2DData>,
texture: &Texture,
texture_handle: Handle<Texture>,
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,
});
}