aboutsummaryrefslogtreecommitdiff
path: root/kscurses/canvas.jai
blob: df0b0218da3108661407975266c974731d38294a (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
Canvas :: struct {
	zone : Ibox2;

	count : int;
	pixels_last_draw : []Char;
	pixels_buf : []Char;
	links : []Link;

	diff_count := 0;
	force_full_refresh := true;

	Link :: struct { prev, next : s32; }
}

deinit :: (using canvas : *Canvas) {
	array_free(pixels_last_draw);
	array_free(pixels_buf); pixels_buf = .[];
	array_free(links);
}
resize_clear :: (using canvas : *Canvas, new_zone : Ibox2, filler := Char.{}) {
	if new_zone != zone {
		array_free(pixels_last_draw);
		array_free(pixels_buf);
		array_free(links);

		zone = new_zone;
		count = zone.width * zone.height;

		pixels_last_draw = NewArray(count, Char);
		pixels_buf = NewArray(count, Char);
		links = NewArray(count + 1, Link);
		links[count] = .{xx count, xx count};
	
		if filler != .{} then {
			for * pixels_buf {
				<<it = filler;
			}
		}
		links[count] = .{-1, -1};

		force_full_refresh = true;
	} else {
		for y : 0..zone.height-1 {
			for x : 0..zone.width-1 {
				c_putchar(canvas, filler, .{xx x, xx y});
			}
		}		
	}
}
// add *void to fill_function
resize_fill :: (using canvas : *Canvas, new_zone : Ibox2, fill_function : (coord : ivec2, zone : Ibox2) -> Char) {
	if zone != new_zone {
		array_free(pixels_last_draw);
		array_free(pixels_buf);
		array_free(links);

		zone = new_zone;
		count = zone.width * zone.height;

		pixels_last_draw = NewArray(count, Char);
		pixels_buf = NewArray(count, Char);
		links = NewArray(count + 1, Link);
		links[count] = .{xx count, xx count};
		force_full_refresh = true;
	}

	c_fill(canvas, fill_function);
	// i := 0;
	// for y : 0..zone.height-1 {
	// 	for x : 0..zone.width-1 {
	// 		pixels_buf[i] = fill_function(.{x, y}, zone);
	// 		i += 1;
	// 		diff_count += 1;
	// 	}
	// }

	// for * links {
	// 	<<it = .{-1, -1};
	// }
}
b_draw_canvas :: (builder : *String_Builder, using canvas : *Canvas) {
	if force_full_refresh || diff_count * 4 > zone.width * zone.height {
		i := 0;
		for y : 0..zone.height-1 {
			b_move_cursor(builder, zone.corner + ivec2.{0, y});
			for x : 0..zone.width-1 {
				b_putchar(builder, pixels_buf[i]);
				pixels_last_draw[i] = pixels_buf[i];
				links[i] = .{-1, -1};
				i += 1;
			} 
		}
	} else {
		last_pos := ivec2.{-1, -1};
		current := links[count].next;
		I := 0;

		while current != count {
			assert(I < count);
			assert(current >= 0);

			pos := ivec2.{xx(current % zone.width), xx(current / zone.width)} + zone.corner;
			if pos.x != last_pos.x + 1 || pos.y != last_pos.y {
				b_move_cursor(builder, pos);
			}
			b_putchar(builder, pixels_buf[current]);
			pixels_last_draw[current] = pixels_buf[current];

			next := links[current].next;
			links[current] = .{-1, -1};
			current = next;
			last_pos = pos;
			I += 1;
		}
	}

	diff_count = 0;
	force_full_refresh = false;
	links[count] = .{xx count, xx count};
}
c_putchar :: (using canvas : *Canvas, pixel : Char, pos_local : ivec2) {
	// pos_local := pos - zone.corner;
	if !point_inside(pos_local, .{size = zone.size}) return;
	current := pos_local.x + pos_local.y * zone.width;

	c_last_draw := pixels_last_draw[current];
	pixels_buf[current] = pixel;

	if links[current].prev == -1 {
		assert(links[current].next == -1);
		if c_last_draw != pixel {
			links[current] = .{links[count].prev, xx count};
			links[links[count].prev].next = current;
			links[count].prev = current;
			diff_count += 1;
		}
	} else {
		if c_last_draw == pixel {
			nbs := links[current];
			assert(links[nbs.prev].next == current && links[nbs.next].prev == current);
			links[nbs.prev].next = nbs.next;
			links[nbs.next].prev = nbs.prev;
			links[current] = .{-1, -1};
			diff_count -= 1;
		}
	}
}

c_fill :: (using canvas : *Canvas, fill_function : (coord : ivec2, zone : Ibox2) -> Char) {
	for y : 0..zone.height-1 {
		for x : 0..zone.width-1 {
			char := fill_function(.{x, y}, zone);
			c_putchar(canvas, char, .{x, y});
		}
	}
	// i := 0;
	// for y : 0..zone.height-1 {
	// 	for x : 0..zone.width-1 {
	// 		pixels_buf[i] = fill_function(.{x, y}, zone);
	// 		i += 1;
	// 		diff_count += 1;
	// 	}
	// }
	// refresh_all = true;
}
ks_draw_canvas :: (canvas : *Canvas) {
	builder := String_Builder.{allocator = temp};
	b_draw_canvas(*builder, canvas);
	ks_write(builder_to_string(*builder, allocator = temp));
}