Revisions for ⁨Sprite encoding⁩

View the changes made to this paste.

unlisted ⁨1⁩ ⁨file⁩ 2018-12-30 14:40:37 UTC

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,
+    });
+}