/*
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 .
*/
use hurrycurry_protocol::{
glam::{IVec2, Vec2},
ClientGamedata, ItemIndex, TileIndex,
};
use sdl2::{
pixels::PixelFormatEnum,
rect::{FRect, Rect},
render::{BlendMode, Canvas, Texture, TextureAccess, TextureCreator},
video::{Window, WindowContext},
};
use std::collections::HashMap;
pub struct SpriteRenderer<'a> {
texture: Texture<'a>,
tiles: Vec,
items: Vec,
view_scale: Vec2,
view_offset: Vec2,
sprites: Vec,
}
pub struct DrawItem {
z_order: i32,
src: Rect,
dst: FRect,
}
impl<'a> SpriteRenderer<'a> {
pub fn init(texture_creator: &'a TextureCreator) -> Self {
let palette = include_str!("../textures/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::().unwrap(),
toks.next().unwrap().parse::().unwrap(),
toks.next().unwrap().parse::().unwrap(),
toks.next().unwrap().parse::().unwrap(),
],
)
})
.collect::>();
let mut texels = vec![255; 1024 * 1024 * 4];
for (y, line) in include_str!("../textures/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);
Self {
texture,
items: vec![],
tiles: vec![],
sprites: vec![],
view_offset: Vec2::ZERO,
view_scale: Vec2::splat(4.),
}
}
pub fn set_sprite_map(&mut self, data: ClientGamedata) {
let meta = include_str!("../textures/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::>();
self.items = data
.item_names
.iter()
.map(|i| meta.get(i).copied().unwrap_or(Rect::new(0, 0, 0, 0)))
.collect();
self.tiles = data
.tile_names
.iter()
.map(|i| meta.get(i).copied().unwrap_or(Rect::new(0, 0, 0, 0)))
.collect();
}
pub fn draw_tile(&mut self, TileIndex(i): TileIndex, position: IVec2) {
let p = self.view_offset + position.as_vec2();
let src = self.tiles[i];
self.sprites.push(DrawItem {
z_order: position.y,
src,
dst: FRect::new(
(p.x * 32.) * self.view_scale.x,
(p.y * 24. + 24. - src.height() as f32) * self.view_scale.y,
src.width() as f32 * self.view_scale.x,
src.height() as f32 * self.view_scale.y,
),
});
}
pub fn draw_item(&mut self, ItemIndex(_i): ItemIndex, _position: Vec2) {
todo!()
}
pub fn submit(&mut self, canvas: &mut Canvas) {
self.sprites.sort();
for DrawItem { src, dst, .. } in self.sprites.drain(..) {
canvas.copy_f(&self.texture, src, dst).unwrap();
}
}
}
impl Ord for DrawItem {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.z_order.cmp(&other.z_order)
}
}
impl PartialOrd for DrawItem {
fn partial_cmp(&self, other: &Self) -> Option {
Some(self.cmp(&other))
}
}
impl Eq for DrawItem {}
impl PartialEq for DrawItem {
fn eq(&self, other: &Self) -> bool {
self.z_order == other.z_order && self.src == other.src && self.dst == other.dst
}
}