skunk2d/src/image.rs

153 lines
3.9 KiB
Rust

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<u8>,
size: Vec2<i32>,
}
impl Image {
pub fn new(size: Vec2<i32>) -> Self {
Image {
data: vec![0u8; size.size()],
size,
}
}
pub fn load(path: &str) -> Rc<Self> {
Self::load_data(fs::read(path).unwrap().as_slice())
}
pub fn load_data(data: &[u8]) -> Rc<Self> {
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<i32>, 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<i32>, image: &Image) {
self.draw_image_partial(
pos,
image,
Rect {
pos: Vec2::zero(),
size: image.size,
},
);
}
pub fn draw_image_partial(&mut self, pos: Vec2<i32>, image: &Image, src_rect: Rect<i32>) {
//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<i32>, pos2: Vec2<i32>, 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<i32>, 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<i32>, color: u8) {
for pos in rect.iter() {
self.set_pixel(pos, color);
}
}
pub fn get_pixel(&self, pos: Vec2<i32>) -> u8 {
self.data[(pos.x + self.size.x * pos.y) as usize]
}
pub fn set_pixel(&mut self, pos: Vec2<i32>, color: u8) {
self.data[(pos.x + self.size.x * pos.y) as usize] = color;
}
pub fn size(&self) -> Vec2<i32> {
self.size
}
}