mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-16 02:12:28 -06:00
feat: atlas tile color modulation
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
//! This module provides a simple animation and atlas system for textures.
|
||||
use anyhow::Result;
|
||||
use sdl2::render::WindowCanvas;
|
||||
use sdl2::{pixels::Color, render::WindowCanvas};
|
||||
|
||||
use crate::texture::sprite::AtlasTile;
|
||||
|
||||
@@ -34,16 +34,16 @@ impl AnimatedTexture {
|
||||
self.ticker += 1;
|
||||
}
|
||||
|
||||
pub fn current_tile(&self) -> &AtlasTile {
|
||||
pub fn current_tile(&mut self) -> &mut AtlasTile {
|
||||
if self.ticks_per_frame == 0 {
|
||||
return &self.frames[0];
|
||||
return &mut self.frames[0];
|
||||
}
|
||||
let frame_index = (self.ticker / self.ticks_per_frame) as usize % self.frames.len();
|
||||
&self.frames[frame_index]
|
||||
&mut self.frames[frame_index]
|
||||
}
|
||||
|
||||
pub fn render(&self, canvas: &mut WindowCanvas, dest: sdl2::rect::Rect) -> Result<()> {
|
||||
let tile = self.current_tile();
|
||||
pub fn render(&mut self, canvas: &mut WindowCanvas, dest: sdl2::rect::Rect) -> Result<()> {
|
||||
let mut tile = self.current_tile();
|
||||
tile.render(canvas, dest)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ impl BlinkingTexture {
|
||||
}
|
||||
|
||||
/// Renders the blinking texture.
|
||||
pub fn render(&self, canvas: &mut WindowCanvas, dest: sdl2::rect::Rect) -> Result<()> {
|
||||
pub fn render(&mut self, canvas: &mut WindowCanvas, dest: sdl2::rect::Rect) -> Result<()> {
|
||||
if self.visible {
|
||||
self.animation.render(canvas, dest)
|
||||
} else {
|
||||
|
||||
@@ -37,28 +37,28 @@ impl DirectionalAnimatedTexture {
|
||||
|
||||
pub fn render(&mut self, canvas: &mut WindowCanvas, dest: sdl2::rect::Rect, direction: Direction) -> Result<()> {
|
||||
let frames = match direction {
|
||||
Direction::Up => &self.up,
|
||||
Direction::Down => &self.down,
|
||||
Direction::Left => &self.left,
|
||||
Direction::Right => &self.right,
|
||||
Direction::Up => &mut self.up,
|
||||
Direction::Down => &mut self.down,
|
||||
Direction::Left => &mut self.left,
|
||||
Direction::Right => &mut self.right,
|
||||
};
|
||||
|
||||
let frame_index = (self.ticker / self.ticks_per_frame) as usize % frames.len();
|
||||
let tile = &frames[frame_index];
|
||||
let tile = &mut frames[frame_index];
|
||||
|
||||
tile.render(canvas, dest)
|
||||
}
|
||||
|
||||
pub fn render_stopped(&mut self, canvas: &mut WindowCanvas, dest: sdl2::rect::Rect, direction: Direction) -> Result<()> {
|
||||
let frames = match direction {
|
||||
Direction::Up => &self.up,
|
||||
Direction::Down => &self.down,
|
||||
Direction::Left => &self.left,
|
||||
Direction::Right => &self.right,
|
||||
Direction::Up => &mut self.up,
|
||||
Direction::Down => &mut self.down,
|
||||
Direction::Left => &mut self.left,
|
||||
Direction::Right => &mut self.right,
|
||||
};
|
||||
|
||||
// Show the last frame (full sprite) when stopped
|
||||
let tile = &frames[1];
|
||||
let tile = &mut frames[1];
|
||||
|
||||
tile.render(canvas, dest)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::texture::sprite::{AtlasTile, SpriteAtlas};
|
||||
@@ -8,6 +9,6 @@ pub mod directional;
|
||||
pub mod sprite;
|
||||
pub mod text;
|
||||
|
||||
pub fn get_atlas_tile(atlas: &Rc<SpriteAtlas>, name: &str) -> AtlasTile {
|
||||
pub fn get_atlas_tile(atlas: &Rc<RefCell<SpriteAtlas>>, name: &str) -> AtlasTile {
|
||||
SpriteAtlas::get_tile(atlas, name).unwrap_or_else(|| panic!("Could not find tile {}", name))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use anyhow::Result;
|
||||
use glam::U16Vec2;
|
||||
use sdl2::pixels::Color;
|
||||
use sdl2::rect::Rect;
|
||||
use sdl2::render::{Canvas, RenderTarget, Texture};
|
||||
use serde::Deserialize;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -21,15 +23,30 @@ pub struct MapperFrame {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AtlasTile {
|
||||
pub atlas: Rc<SpriteAtlas>,
|
||||
pub atlas: Rc<RefCell<SpriteAtlas>>,
|
||||
pub pos: U16Vec2,
|
||||
pub size: U16Vec2,
|
||||
pub color: Option<Color>,
|
||||
}
|
||||
|
||||
impl AtlasTile {
|
||||
pub fn render<C: RenderTarget>(&self, canvas: &mut Canvas<C>, dest: Rect) -> Result<()> {
|
||||
pub fn render<C: RenderTarget>(&mut self, canvas: &mut Canvas<C>, dest: Rect) -> Result<()> {
|
||||
let color = self
|
||||
.color
|
||||
.unwrap_or(self.atlas.borrow().default_color.unwrap_or(Color::WHITE));
|
||||
self.render_with_color(canvas, dest, color)
|
||||
}
|
||||
|
||||
pub fn render_with_color<C: RenderTarget>(&mut self, canvas: &mut Canvas<C>, dest: Rect, color: Color) -> Result<()> {
|
||||
let src = Rect::new(self.pos.x as i32, self.pos.y as i32, self.size.x as u32, self.size.y as u32);
|
||||
canvas.copy(&self.atlas.texture, src, dest).map_err(anyhow::Error::msg)?;
|
||||
|
||||
let mut atlas = self.atlas.borrow_mut();
|
||||
if atlas.last_modulation != Some(color) {
|
||||
atlas.texture.set_color_mod(color.r, color.g, color.b);
|
||||
atlas.last_modulation = Some(color);
|
||||
}
|
||||
|
||||
canvas.copy(&atlas.texture, src, dest).map_err(anyhow::Error::msg)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -37,6 +54,8 @@ impl AtlasTile {
|
||||
pub struct SpriteAtlas {
|
||||
texture: Texture<'static>,
|
||||
tiles: HashMap<String, MapperFrame>,
|
||||
default_color: Option<Color>,
|
||||
last_modulation: Option<Color>,
|
||||
}
|
||||
|
||||
impl SpriteAtlas {
|
||||
@@ -44,17 +63,25 @@ impl SpriteAtlas {
|
||||
Self {
|
||||
texture,
|
||||
tiles: mapper.frames,
|
||||
default_color: None,
|
||||
last_modulation: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_tile(atlas: &Rc<SpriteAtlas>, name: &str) -> Option<AtlasTile> {
|
||||
atlas.tiles.get(name).map(|frame| AtlasTile {
|
||||
atlas: atlas.clone(),
|
||||
pub fn get_tile(atlas: &Rc<RefCell<SpriteAtlas>>, name: &str) -> Option<AtlasTile> {
|
||||
let atlas_ref = atlas.borrow();
|
||||
atlas_ref.tiles.get(name).map(|frame| AtlasTile {
|
||||
atlas: Rc::clone(atlas),
|
||||
pos: U16Vec2::new(frame.x, frame.y),
|
||||
size: U16Vec2::new(frame.width, frame.height),
|
||||
color: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_color(&mut self, color: Color) {
|
||||
self.default_color = Some(color);
|
||||
}
|
||||
|
||||
pub fn texture(&self) -> &Texture<'static> {
|
||||
&self.texture
|
||||
}
|
||||
|
||||
@@ -48,8 +48,10 @@
|
||||
|
||||
use anyhow::Result;
|
||||
use glam::UVec2;
|
||||
use sdl2::pixels::Color;
|
||||
use sdl2::rect::Rect;
|
||||
use sdl2::render::{Canvas, RenderTarget};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -57,14 +59,14 @@ use crate::texture::sprite::{AtlasTile, SpriteAtlas};
|
||||
|
||||
/// A text texture that renders characters from the atlas.
|
||||
pub struct TextTexture {
|
||||
atlas: Rc<SpriteAtlas>,
|
||||
atlas: Rc<RefCell<SpriteAtlas>>,
|
||||
char_map: HashMap<char, AtlasTile>,
|
||||
scale: f32,
|
||||
}
|
||||
|
||||
impl TextTexture {
|
||||
/// Creates a new text texture with the given atlas and scale.
|
||||
pub fn new(atlas: Rc<SpriteAtlas>, scale: f32) -> Self {
|
||||
pub fn new(atlas: Rc<RefCell<SpriteAtlas>>, scale: f32) -> Self {
|
||||
Self {
|
||||
atlas,
|
||||
char_map: HashMap::new(),
|
||||
@@ -107,13 +109,13 @@ impl TextTexture {
|
||||
}
|
||||
|
||||
/// Renders a string of text at the given position.
|
||||
pub fn render<C: RenderTarget>(&mut self, canvas: &mut Canvas<C>, text: &str, position: UVec2) -> Result<()> {
|
||||
pub fn render<C: RenderTarget>(&mut self, canvas: &mut Canvas<C>, text: &str, position: UVec2, color: Color) -> Result<()> {
|
||||
let mut x_offset = 0;
|
||||
let char_width = (8.0 * self.scale) as u32;
|
||||
let char_height = (8.0 * self.scale) as u32;
|
||||
|
||||
for c in text.chars() {
|
||||
if let Some(tile) = self.get_char_tile(c) {
|
||||
if let Some(mut tile) = self.get_char_tile(c) {
|
||||
let dest = sdl2::rect::Rect::new((position.x + x_offset) as i32, position.y as i32, char_width, char_height);
|
||||
tile.render(canvas, dest)?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user