mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
box-drawing: apply antialiasing to LIGHT ARCs
When drawing on an a8 buffer, apply antialiasing to LIGHT ARCs. This is done by supersampling; draw to a 4 times bigger buffer, then downsample, where each downsampled pixel is the average of the corresponding 4x4 pixel from the supersampled buffer. We also need to take supersampling into account while adjusting the row and col when pixel aligning the arcs with the regular horizontal/vertical lines. The shape of the ARCs can still be improved. Still, this is a much needed improvement over the current implementation. Closes #279
This commit is contained in:
parent
3d97b8c113
commit
99a3b034c3
1 changed files with 73 additions and 40 deletions
113
box-drawing.c
113
box-drawing.c
|
|
@ -1242,25 +1242,28 @@ draw_box_drawings_double_vertical_and_horizontal(struct buf *buf)
|
|||
static void
|
||||
draw_box_drawings_light_arc(wchar_t wc, struct buf *buf)
|
||||
{
|
||||
if (pixman_image_get_format(buf->pix) == PIXMAN_a8) {
|
||||
/*
|
||||
* Hack until we’ve implemented ARCs with pixman
|
||||
*
|
||||
* Replace the a8 buffer with a a1 buffer, and use our “old”
|
||||
* non-antialiased technique to draw arcs.
|
||||
*/
|
||||
change_buffer_format(buf, PIXMAN_a1);
|
||||
}
|
||||
const pixman_format_code_t fmt = pixman_image_get_format(buf->pix);
|
||||
const int supersample = fmt == PIXMAN_a8 ? 4 : 1;
|
||||
const int height = buf->height * supersample;
|
||||
const int width = buf->width * supersample;
|
||||
const int stride = fmt == PIXMAN_a8
|
||||
? stride_for_format_and_width(PIXMAN_a8, width) : buf->stride;
|
||||
uint8_t *data = supersample > 1 ? xcalloc(height * stride, 1) : buf->data;
|
||||
|
||||
int thick = thickness(LIGHT);
|
||||
const int thick = thickness(LIGHT) * supersample;
|
||||
|
||||
double a = (buf->width - thick) / 2;
|
||||
double b = (buf->height - thick) / 2;
|
||||
const bool thick_is_odd = (thick / supersample) % 2;
|
||||
const bool height_is_odd = buf->height % 2;
|
||||
const bool width_is_odd = buf->width % 2;
|
||||
|
||||
double a2 = a * a;
|
||||
double b2 = b * b;
|
||||
const double a = (width - thick) / 2;
|
||||
const double b = (height - thick) / 2;
|
||||
|
||||
const double a2 = a * a;
|
||||
const double b2 = b * b;
|
||||
|
||||
const int num_samples = height * 16;
|
||||
|
||||
int num_samples = buf->height * 16;
|
||||
for (int i = 0; i < num_samples; i++) {
|
||||
double y = i / 16.;
|
||||
double x = sqrt(a2 * (1. - y * y / b2));
|
||||
|
|
@ -1310,30 +1313,30 @@ draw_box_drawings_light_arc(wchar_t wc, struct buf *buf)
|
|||
*/
|
||||
switch (wc) {
|
||||
case L'╭':
|
||||
row_end = buf->height - row - (thick % 2 ^ buf->height % 2);
|
||||
row_end = height - row - (thick_is_odd ^ height_is_odd);
|
||||
row_start = row_end - thick;
|
||||
col_end = buf->width - col - (thick % 2 ^ buf->width % 2);
|
||||
col_end = width - col - (thick_is_odd ^ width_is_odd);
|
||||
col_start = col_end - thick;
|
||||
break;
|
||||
|
||||
case L'╮':
|
||||
row_end = buf->height - row - (thick % 2 ^ buf->height % 2);
|
||||
row_end = height - row - (thick_is_odd ^ height_is_odd);
|
||||
row_start = row_end - thick;
|
||||
col_start = col;
|
||||
col_start = col - ((thick_is_odd ^ width_is_odd) ? supersample / 2 : 0);
|
||||
col_end = col_start + thick;
|
||||
break;
|
||||
|
||||
case L'╰':
|
||||
row_start = row;
|
||||
row_start = row - ((thick_is_odd ^ height_is_odd) ? supersample / 2 : 0);
|
||||
row_end = row_start + thick;
|
||||
col_end = buf->width - col - (thick % 2 ^ buf->width % 2);
|
||||
col_end = width - col - (thick_is_odd ^ width_is_odd);
|
||||
col_start = col_end - thick;
|
||||
break;
|
||||
|
||||
case L'╯':
|
||||
row_start = row;
|
||||
row_start = row - ((thick_is_odd ^ height_is_odd) ? supersample / 2 : 0);
|
||||
row_end = row_start + thick;
|
||||
col_start = col;
|
||||
col_start = col - ((thick_is_odd ^ width_is_odd) ? supersample / 2 : 0);
|
||||
col_end = col_start + thick;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1341,11 +1344,14 @@ draw_box_drawings_light_arc(wchar_t wc, struct buf *buf)
|
|||
xassert(row_end > row_start);
|
||||
xassert(col_end > col_start);
|
||||
|
||||
for (int r = max(row_start, 0); r < max(min(row_end, buf->height), 0); r++) {
|
||||
for (int c = max(col_start, 0); c < max(min(col_end, buf->width), 0); c++) {
|
||||
size_t idx = c / 8;
|
||||
size_t bit_no = c % 8;
|
||||
buf->data[r * buf->stride + idx] |= 1 << bit_no;
|
||||
for (int r = max(row_start, 0); r < max(min(row_end, height), 0); r++) {
|
||||
for (int c = max(col_start, 0); c < max(min(col_end, width), 0); c++) {
|
||||
if (fmt == PIXMAN_a1) {
|
||||
size_t idx = c / 8;
|
||||
size_t bit_no = c % 8;
|
||||
data[r * stride + idx] |= 1 << bit_no;
|
||||
} else
|
||||
data[r * stride + c] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1359,27 +1365,54 @@ draw_box_drawings_light_arc(wchar_t wc, struct buf *buf)
|
|||
|
||||
if (wc == L'╭' || wc == L'╰') {
|
||||
for (int y = 0; y < thick; y++) {
|
||||
int row = (buf->height - thick) / 2 + y;
|
||||
int col = buf->width - 1;
|
||||
if (row >= 0 && row < buf->height && col >= 0 && col < buf->width) {
|
||||
size_t ofs = col / 8;
|
||||
size_t bit_no = col % 8;
|
||||
buf->data[row * buf->stride + ofs] |= 1 << bit_no;
|
||||
int row = (height - thick) / 2 + y - ((thick_is_odd ^ height_is_odd) ? supersample / 2 : 0);
|
||||
for (int col = width - supersample; col < width; col++) {
|
||||
if (row >= 0 && row < height && col >= 0) {
|
||||
if (fmt == PIXMAN_a1) {
|
||||
size_t ofs = col / 8;
|
||||
size_t bit_no = col % 8;
|
||||
data[row * stride + ofs] |= 1 << bit_no;
|
||||
} else
|
||||
data[row * stride + col] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wc == L'╭' || wc == L'╮') {
|
||||
for (int x = 0; x < thick; x++) {
|
||||
int row = buf->height - 1;
|
||||
int col = (buf->width - thick) / 2 + x;
|
||||
if (row >= 0 && row < buf->height && col >= 0 && col < buf->width) {
|
||||
size_t ofs = col / 8;
|
||||
size_t bit_no = col % 8;
|
||||
buf->data[row * buf->stride + ofs] |= 1 << bit_no;
|
||||
int col = (width - thick) / 2 + x - ((thick_is_odd ^ width_is_odd) ? supersample / 2 : 0);
|
||||
for (int row = height - supersample; row < height; row++) {
|
||||
if (row >= 0 && col >= 0 && col < width) {
|
||||
if (fmt == PIXMAN_a1) {
|
||||
size_t ofs = col / 8;
|
||||
size_t bit_no = col % 8;
|
||||
data[row * stride + ofs] |= 1 << bit_no;
|
||||
} else
|
||||
data[row * stride + col] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fmt == PIXMAN_a8) {
|
||||
xassert(data != buf->data);
|
||||
|
||||
/* Downsample */
|
||||
for (size_t r = 0; r < buf->height; r++) {
|
||||
for (size_t c = 0; c < buf->width; c++) {
|
||||
uint32_t total = 0;
|
||||
for (size_t i = 0; i < supersample; i++) {
|
||||
for (size_t j = 0; j < supersample; j++)
|
||||
total += data[(r * supersample + i) * stride + c * supersample + j];
|
||||
}
|
||||
uint8_t average = min(total / (supersample * supersample), 0xff);
|
||||
buf->data[r * buf->stride + c] = average;
|
||||
}
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue