153 lines
3.9 KiB
Rust
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
|
|
}
|
|
}
|