game: implement sprite color tinting (fixes )

This commit is contained in:
SeanOMik 2025-04-10 12:59:55 -04:00
parent d44eb3b5cf
commit b74cd7f30b
Signed by: SeanOMik
GPG key ID: FEC9E2FC15235964
6 changed files with 59 additions and 18 deletions
crates
lyra-game/src
lyra-scripting/src/lua/wrappers/sprite

View file

@ -415,19 +415,27 @@ impl Node for SpritePass {
} }
} }
// Get the transform accounting for the sprite pivot
let pivot = atlas_sprite let pivot = atlas_sprite
.as_ref()
.map(|ats| ats.0.pivot) .map(|ats| ats.0.pivot)
// unwrap is safe since its either AtlasSprite or Sprite. // unwrap is safe since its either AtlasSprite or Sprite.
.unwrap_or_else(|| sprite.unwrap().pivot) .unwrap_or_else(|| sprite.as_ref().unwrap().pivot)
.as_vec(); .as_vec();
let pivot_pos = dim.as_vec2() * (pivot - Vec2::splat(0.5)); let pivot_pos = dim.as_vec2() * (pivot - Vec2::splat(0.5));
let transform = let transform =
*transform + lyra_math::Transform::from_translation(pivot_pos.extend(0.0)); *transform + lyra_math::Transform::from_translation(pivot_pos.extend(0.0));
let tint = sprite
.map(|s| s.color)
.or_else(|| atlas_sprite.map(|(ats, _)| ats.color))
.unwrap_or(Vec3::ONE);
let inst = SpriteInstance { let inst = SpriteInstance {
atlas_frame: rect.unwrap_or(URect::ZERO), atlas_frame: rect.unwrap_or(URect::ZERO),
transform: transform.calculate_mat4(), transform: transform.calculate_mat4(),
color_tint: tint,
_padding: 0,
}; };
sprite_instances.push(inst); sprite_instances.push(inst);
let inst_id = sprite_instances.len() as u64 - 1; let inst_id = sprite_instances.len() as u64 - 1;
@ -555,4 +563,6 @@ impl Node for SpritePass {
struct SpriteInstance { struct SpriteInstance {
atlas_frame: URect, atlas_frame: URect,
transform: glam::Mat4, transform: glam::Mat4,
color_tint: glam::Vec3,
_padding: u32,
} }

View file

@ -26,6 +26,7 @@ struct URect {
struct SpriteInstance { struct SpriteInstance {
atlas_frame: URect, atlas_frame: URect,
transform: mat4x4<f32>, transform: mat4x4<f32>,
color: vec3<f32>,
} }
struct CameraUniform { struct CameraUniform {
@ -82,10 +83,13 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
region_coords /= dim; region_coords /= dim;
} }
let object_color: vec4<f32> = textureSample(t_diffuse, s_diffuse, region_coords); var object_color: vec4<f32> = textureSample(t_diffuse, s_diffuse, region_coords);
if (object_color.a < ALPHA_CUTOFF) { if (object_color.a < ALPHA_CUTOFF) {
discard; discard;
} }
// apply color tint
object_color = vec4<f32>(object_color.rgb * sprite.color.rgb, object_color.a);
return object_color; return object_color;
} }

View file

@ -38,7 +38,13 @@ impl SpriteAnimation {
/// * `frame_time` - The time per frame of the animation. /// * `frame_time` - The time per frame of the animation.
/// * `atlas` - The texture atlas that this animation is from, used to acquire `self.frames`. /// * `atlas` - The texture atlas that this animation is from, used to acquire `self.frames`.
/// * `sprites` are the rect indexes in the atlas for this animation. /// * `sprites` are the rect indexes in the atlas for this animation.
pub fn from_atlas<I>(name: &str, frame_time: f32, atlas: &TextureAtlas, auto_loop: bool, sprites: I) -> Self pub fn from_atlas<I>(
name: &str,
frame_time: f32,
atlas: &TextureAtlas,
auto_loop: bool,
sprites: I,
) -> Self
where where
I: Iterator<Item = u32>, I: Iterator<Item = u32>,
{ {
@ -96,14 +102,18 @@ impl AtlasAnimations {
pub fn from_animations( pub fn from_animations(
atlas: ResHandle<TextureAtlas>, atlas: ResHandle<TextureAtlas>,
animations: Vec<SpriteAnimation>, animations: Vec<SpriteAnimation>,
sprite_pivot: Pivot sprite_pivot: Pivot,
) -> Self { ) -> Self {
let animations = animations let animations = animations
.into_iter() .into_iter()
.map(|a| (a.name.clone(), a)) .map(|a| (a.name.clone(), a))
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
Self { atlas, animations, sprite_pivot } Self {
atlas,
animations,
sprite_pivot,
}
} }
/// Helper for creating [`AtlasAnimations`]. /// Helper for creating [`AtlasAnimations`].
@ -140,7 +150,11 @@ impl AtlasAnimations {
.collect::<HashMap<_, _>>() .collect::<HashMap<_, _>>()
}; };
Self { atlas, animations, sprite_pivot } Self {
atlas,
animations,
sprite_pivot,
}
} }
/// Get the [`ActiveAtlasAnimation`] for an animation with `name`. /// Get the [`ActiveAtlasAnimation`] for an animation with `name`.
@ -282,6 +296,7 @@ fn system_animation_entity_impl(
atlas: animations.atlas.clone(), atlas: animations.atlas.clone(),
sprite: rect, sprite: rect,
pivot: animations.sprite_pivot, pivot: animations.sprite_pivot,
..Default::default()
}; };
commands.insert(en, sprite); commands.insert(en, sprite);
@ -313,6 +328,7 @@ fn system_animation_entity_impl(
atlas: animations.atlas.clone(), atlas: animations.atlas.clone(),
sprite: rect, sprite: rect,
pivot: animations.sprite_pivot, pivot: animations.sprite_pivot,
..Default::default()
}; };
let sprite = sprite.as_mut().unwrap(); let sprite = sprite.as_mut().unwrap();

View file

@ -1,4 +1,4 @@
use glam::UVec2; use glam::{UVec2, Vec3};
use lyra_ecs::Component; use lyra_ecs::Component;
use lyra_math::URect; use lyra_math::URect;
use lyra_reflect::Reflect; use lyra_reflect::Reflect;
@ -15,7 +15,7 @@ pub struct TextureAtlas {
impl TextureAtlas { impl TextureAtlas {
/// Create a texture atlas with rectangles of a grid. /// Create a texture atlas with rectangles of a grid.
/// ///
/// Parameters: /// Parameters:
/// * `texture` - The asset handle of the texture to get the sprites from. /// * `texture` - The asset handle of the texture to get the sprites from.
/// * `grid_size` - The number of the cells in the grid (i.e., 9x7 grid). /// * `grid_size` - The number of the cells in the grid (i.e., 9x7 grid).
@ -40,7 +40,7 @@ impl TextureAtlas {
if y > 0 { if y > 0 {
p.y = padding.y; p.y = padding.y;
} }
for x in 0..grid_size.x { for x in 0..grid_size.x {
if x > 0 { if x > 0 {
p.x = padding.x; p.x = padding.x;
@ -49,12 +49,7 @@ impl TextureAtlas {
let start = (cell_size + padding) * UVec2::new(x, y) + offset; let start = (cell_size + padding) * UVec2::new(x, y) + offset;
let end = start + cell_size; let end = start + cell_size;
let r = URect::new( let r = URect::new(start.x, start.y, end.x, end.y);
start.x,
start.y,
end.x,
end.y,
);
frames.push(r); frames.push(r);
} }
} }
@ -83,6 +78,18 @@ pub struct AtlasSprite {
pub atlas: ResHandle<TextureAtlas>, pub atlas: ResHandle<TextureAtlas>,
pub sprite: URect, pub sprite: URect,
pub pivot: Pivot, pub pivot: Pivot,
pub color: Vec3,
}
impl Default for AtlasSprite {
fn default() -> Self {
Self {
atlas: Default::default(),
sprite: Default::default(),
pivot: Default::default(),
color: Vec3::ONE,
}
}
} }
impl AtlasSprite { impl AtlasSprite {
@ -102,6 +109,7 @@ impl AtlasSprite {
atlas: atlas.clone(), atlas: atlas.clone(),
sprite: rect, sprite: rect,
pivot, pivot,
color: Vec3::ONE,
} }
} }
} }

View file

@ -152,6 +152,7 @@ pub fn system_tilemap_update(
atlas: atlas_handle.clone(), atlas: atlas_handle.clone(),
sprite: *frame, sprite: *frame,
pivot: super::Pivot::TopLeft, pivot: super::Pivot::TopLeft,
..Default::default()
}; };
commands.insert(en, sprite); commands.insert(en, sprite);
@ -171,6 +172,7 @@ pub fn system_tilemap_update(
atlas: atlas_handle.clone(), atlas: atlas_handle.clone(),
sprite: *frame, sprite: *frame,
pivot: super::Pivot::TopLeft, pivot: super::Pivot::TopLeft,
..Default::default()
}; };
let grid = tile.tile.position * tile_size; let grid = tile.tile.position * tile_size;

View file

@ -4,7 +4,7 @@ use lyra_scripting_derive::{to_lua_convert, wrap_lua_struct};
use super::LuaImageHandle; use super::LuaImageHandle;
use crate as lyra_scripting; use crate as lyra_scripting;
use crate::lua::wrappers::LuaVec2; use crate::lua::wrappers::{LuaVec2, LuaVec3};
use crate::{ use crate::{
lua::wrappers::{helpers, LuaRect}, lua::wrappers::{helpers, LuaRect},
lyra_engine, ScriptEntity, lyra_engine, ScriptEntity,
@ -65,6 +65,7 @@ to_lua_convert!(
atlas: wrap(LuaTextureAtlasHandle), atlas: wrap(LuaTextureAtlasHandle),
(sprite, wrap_with=helpers::wrap_urect_using_luarect), (sprite, wrap_with=helpers::wrap_urect_using_luarect),
(pivot, wrap_with=super::wrap_pivot_enum), (pivot, wrap_with=super::wrap_pivot_enum),
color: wrap(LuaVec3),
} }
); );