use crate::vec2::Vec2; use crate::{HexMap, Rect, Tileset}; use std::fs; use std::fs::File; use std::rc::Rc; //todo: make dynamically different bitdepths pub struct Image { data: Vec, size: Vec2, } impl Image { pub fn new(size: Vec2) -> Self { Image { data: vec![0u8; size.size()], size, } } pub fn load(path: &str) -> Rc { Self::load_data(fs::read(path).unwrap().as_slice()) } pub fn load_data(data: &[u8]) -> Rc { let mut options = gif::DecodeOptions::new(); options.set_color_output(gif::ColorOutput::Indexed); let mut decoder = options.read_info(data).unwrap(); let x = decoder.width(); let y = decoder.height(); let mut data = vec![0u8; (x * y) as usize]; decoder.next_frame_info().unwrap(); decoder.read_into_buffer(&mut data).unwrap(); Image { data, size: Vec2 { x: x as i32, y: y as i32, }, } .into() } pub fn clear(&mut self) { self.fill(0); } pub fn data_mut(&mut self) -> &mut [u8] { self.data.as_mut_slice() } pub fn data(&mut self) -> &[u8] { self.data.as_slice() } pub fn draw_hexmap(&mut self, pos: Vec2, hexmap: &HexMap) { for i in hexmap.size().to_rect().iter() { if i.x % 1 == 0 { hexmap.draw_tile_to_image(self, i, pos); } } } pub fn draw_image(&mut self, pos: Vec2, image: &Image) { self.draw_image_partial( pos, image, Rect { pos: Vec2::zero(), size: image.size, }, ); } pub fn draw_image_partial(&mut self, pos: Vec2, image: &Image, src_rect: Rect) { //todo: write proper implementation later for i in Vec2::zero().iter_to(src_rect.size) { //todo: implement better(very stupid to do per pixel) if self.size.to_rect().contains(i + pos) { let p = image.get_pixel(i + src_rect.pos); if p > 0 { self.set_pixel(i + pos, p); } } } } pub fn draw_line(&mut self, pos1: Vec2, pos2: Vec2, color: u8) { let (x1, y1, x2, y2) = (pos1.x, pos1.y, pos2.x, pos2.y); let mut x = x1 as f32; let mut y = y1 as f32; let xdiff = (x2 - x1) as f32; let ydiff = (y2 - y1) as f32; let step = if xdiff.abs() > ydiff.abs() { xdiff.abs() } else { ydiff.abs() }; let xs = xdiff / step; let ys = ydiff / step; for _ in 1..=(step as i32) { self.set_pixel( Vec2 { x: x as i32, y: y as i32, }, color, ); x += xs; y += ys; } } pub fn draw_string(&mut self, pos: Vec2, str: &str, font: &Tileset) { assert!(str.is_ascii()); let array = str.as_bytes(); for i in 0..array.len() { self.draw_image( Vec2 { x: pos.x + font.tile_size().x * i as i32, y: pos.y, }, font.get(array[i] as i32), ); } } pub fn fill(&mut self, color: u8) { self.data.fill(color); } pub fn fill_rect(&mut self, rect: Rect, color: u8) { for pos in rect.iter() { self.set_pixel(pos, color); } } pub fn get_pixel(&self, pos: Vec2) -> u8 { self.data[(pos.x + self.size.x * pos.y) as usize] } pub fn set_pixel(&mut self, pos: Vec2, color: u8) { self.data[(pos.x + self.size.x * pos.y) as usize] = color; } pub fn size(&self) -> Vec2 { self.size } }