sprite.rs
@@ -0,0 +1,196 @@
+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,
+ });
+}