aboutsummaryrefslogtreecommitdiff
path: root/pixel-client/src/render/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'pixel-client/src/render/mod.rs')
-rw-r--r--pixel-client/src/render/mod.rs158
1 files changed, 158 insertions, 0 deletions
diff --git a/pixel-client/src/render/mod.rs b/pixel-client/src/render/mod.rs
new file mode 100644
index 00000000..a2aea365
--- /dev/null
+++ b/pixel-client/src/render/mod.rs
@@ -0,0 +1,158 @@
+/*
+ Hurry Curry! - a game about cooking
+ Copyright 2024 metamuffin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, version 3 of the License only.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+*/
+pub mod misc;
+pub mod sprite;
+
+use hurrycurry_protocol::glam::Vec2;
+use sdl2::{
+ pixels::PixelFormatEnum,
+ rect::{FRect, Rect},
+ render::{BlendMode, Canvas, Texture, TextureAccess, TextureCreator},
+ video::{Window, WindowContext},
+};
+use sprite::SpriteDraw;
+use std::collections::HashMap;
+
+pub struct SpriteRenderer<'a> {
+ metadata: AtlasLayout,
+
+ pub size: Vec2,
+ texture: Texture<'a>,
+
+ view_scale: Vec2,
+ view_offset: Vec2,
+
+ sprites: Vec<SpriteDraw>,
+}
+
+pub type AtlasLayout = HashMap<String, Rect>;
+
+impl<'a> SpriteRenderer<'a> {
+ pub fn init(texture_creator: &'a TextureCreator<WindowContext>) -> Self {
+ let palette = include_str!("../../assets/palette.csv")
+ .split('\n')
+ .filter(|l| !l.is_empty())
+ .map(|s| {
+ let mut toks = s.split(",");
+ (
+ toks.next().unwrap().chars().next().unwrap(),
+ [
+ toks.next().unwrap().parse::<u8>().unwrap(),
+ toks.next().unwrap().parse::<u8>().unwrap(),
+ toks.next().unwrap().parse::<u8>().unwrap(),
+ toks.next().unwrap().parse::<u8>().unwrap(),
+ ],
+ )
+ })
+ .collect::<HashMap<_, _>>();
+
+ let mut texels = vec![255; 1024 * 1024 * 4];
+
+ for (y, line) in include_str!("../../assets/atlas.ta").lines().enumerate() {
+ if line.is_empty() {
+ continue;
+ }
+ for (x, char) in line.chars().enumerate() {
+ let color = palette.get(&char).unwrap();
+ texels[(y * 1024 + x) * 4 + 0] = color[3];
+ texels[(y * 1024 + x) * 4 + 1] = color[2];
+ texels[(y * 1024 + x) * 4 + 2] = color[1];
+ texels[(y * 1024 + x) * 4 + 3] = color[0];
+ }
+ }
+
+ let mut texture = texture_creator
+ .create_texture(
+ Some(PixelFormatEnum::RGBA8888),
+ TextureAccess::Streaming,
+ 1024,
+ 1024,
+ )
+ .unwrap();
+
+ texture.update(None, &texels, 1024 * 4).unwrap();
+ texture.set_blend_mode(BlendMode::Blend);
+
+ let metadata = include_str!("../../assets/atlas.meta.csv")
+ .lines()
+ .filter(|l| !l.is_empty())
+ .map(|l| {
+ let mut toks = l.split(",");
+ let x: i32 = toks.next().unwrap().parse().unwrap();
+ let y: i32 = toks.next().unwrap().parse().unwrap();
+ let w: u32 = toks.next().unwrap().parse().unwrap();
+ let h: u32 = toks.next().unwrap().parse().unwrap();
+ let name = toks.next().unwrap().to_string();
+ (name, Rect::new(x, y, w, h))
+ })
+ .collect::<HashMap<_, _>>();
+
+ Self {
+ texture,
+ size: Vec2::ONE,
+ metadata,
+ sprites: vec![],
+ view_offset: Vec2::ZERO,
+ view_scale: Vec2::ZERO,
+ }
+ }
+
+ pub fn set_view(&mut self, offset: Vec2, scale: f32) {
+ self.view_offset = offset;
+ self.view_scale = Vec2::new(32., 24.) * scale;
+ }
+ pub fn get_scale(&self) -> Vec2 {
+ self.view_scale
+ }
+
+ #[inline]
+ pub fn atlas_layout(&self) -> &HashMap<String, Rect> {
+ &self.metadata
+ }
+
+ pub fn set_modulation(&mut self, r: u8, g: u8, b: u8, a: u8) {
+ self.texture.set_alpha_mod(a);
+ self.texture.set_color_mod(r, g, b);
+ }
+ pub fn reset_modulation(&mut self) {
+ self.set_modulation(255, 255, 255, 255)
+ }
+
+ pub fn draw_world(&mut self, sprite: SpriteDraw) {
+ self.sprites.push(SpriteDraw {
+ tint: sprite.tint,
+ z_order: sprite.z_order,
+ src: sprite.src,
+ dst: FRect::new(
+ ((sprite.dst.x + self.view_offset.x) * self.view_scale.x).round(),
+ ((sprite.dst.y + self.view_offset.y) * self.view_scale.y).round(),
+ (sprite.dst.w * self.view_scale.x).round(),
+ (sprite.dst.h * self.view_scale.y).round(),
+ ),
+ })
+ }
+
+ pub fn submit(&mut self, canvas: &mut Canvas<Window>) {
+ self.sprites.sort();
+ for SpriteDraw { src, dst, tint, .. } in self.sprites.drain(..) {
+ self.texture.set_color_mod(tint[0], tint[1], tint[2]);
+ self.texture.set_alpha_mod(tint[3]);
+ canvas.copy_f(&self.texture, src, dst).unwrap();
+ }
+ }
+}