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));
}
|