about summary refs log tree commit diff
path: root/src/griph/mod.rs
blob: 6b842336c13bd6081f55ca2a94127414ce9eed24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use gifed::{writer::ImageBuilder, Gif, StandardGif};

#[rustfmt::skip]
pub const DARK_PALETTE: &[u8] = &[
	  0,   0,   0, // Background - Black
	192, 192, 192, // Graphline - Mostly White
	 64,  64,  64, // Gridlines - Dark gray
	 32,  32,  32, // Minor Gridlines - Darker gray
	144, 144, 255, // Primary 2 Colour - Blue
	 48, 192,  48, // Secondary 2 Colour - Green
	 96,  96, 224, // Primary Underfill - Light Blue
	 48, 128,  48, // Secondary Underfill - Lesser Green
];

const BACKGROUND: u8 = 0;
const LINE: u8 = 1;
const GRIDLINE: u8 = 2;
const MINOR_GRIDLINE: u8 = 3;
const LINE1: u8 = 4;
const LINE2: u8 = 5;
const LINE1_FILL: u8 = 6;
const LINE2_FILL: u8 = 7;

const WIDTH: usize = 256;
const HEIGHT: usize = 160;
const SIZE: usize = WIDTH * HEIGHT;

pub fn make_1line(min: usize, max: usize, values: &[usize]) -> Gif {
	let range = max - min;
	// this assumes a range of values that is >1 per pixel
	let vpp = range / HEIGHT;

	let mut raster = vec![0; SIZE];
	draw_grid(&mut raster);
	draw_line(&mut raster, values, vpp, LINE);

	let mut standard = Gif::new(WIDTH as u16, HEIGHT as u16);
	standard.set_palette(Some(DARK_PALETTE[0..12].try_into().unwrap()));
	standard.push(
		ImageBuilder::new(WIDTH as u16, HEIGHT as u16)
			.build(raster)
			.unwrap(),
	);

	standard
}

pub fn make_2line(min: usize, max: usize, values1: &[usize], values2: &[usize]) -> Gif {
	let range = max - min;
	// this assumes a range of values that is >1 per pixel
	let vpp = range / HEIGHT;

	let mut raster = vec![0; SIZE];
	draw_grid(&mut raster);
	draw_line_underfill(&mut raster, values1, vpp, LINE1, LINE1_FILL);
	draw_line_underfill(&mut raster, values2, vpp, LINE2, LINE2_FILL);

	let mut standard = Gif::new(WIDTH as u16, HEIGHT as u16);
	standard.set_palette(Some(DARK_PALETTE.try_into().unwrap()));
	standard.push(
		ImageBuilder::new(WIDTH as u16, HEIGHT as u16)
			.build(raster)
			.unwrap(),
	);

	standard
}

fn draw_grid(raster: &mut [u8]) {
	// Draw Divisions
	// we want a gridline every 16 pixels, but not the bottom
	// or top, so only 8.
	for div in 1..=9 {
		let y_val = div * 16;

		let grid = if div % 2 == 0 {
			GRIDLINE
		} else {
			MINOR_GRIDLINE
		};

		for x in 0..WIDTH {
			raster[y_val * WIDTH + x] = grid;
		}
	}
}

fn draw_line(raster: &mut [u8], values: &[usize], vpp: usize, colour: u8) {
	// Draw Line
	// this will be discontinuous and i think that's okay. we
	// could make it a proper line by keeping track what value
	// was last and drawing the whole vertical there
	for (x, value) in values.iter().enumerate() {
		let value_height = value / vpp;
		if value_height > (HEIGHT - 1) {
			continue;
		}
		let y_val = (HEIGHT - 1) - value_height;

		raster[y_val * WIDTH + x] = colour;
	}
}

fn draw_line_underfill(
	raster: &mut [u8],
	values: &[usize],
	vpp: usize,
	colour: u8,
	colour_fill: u8,
) {
	for (x, value) in values.iter().enumerate() {
		let value_height = value / vpp;
		if value_height > (HEIGHT - 1) {
			continue;
		}
		let y_val = (HEIGHT - 1) - value_height;

		for y in y_val + 1..HEIGHT {
			raster[y * WIDTH + x] = colour_fill;
		}
		raster[y_val * WIDTH + x] = colour;
	}
}