mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-22 05:33:45 -04: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
|
static void
|
||||||
draw_box_drawings_light_arc(wchar_t wc, struct buf *buf)
|
draw_box_drawings_light_arc(wchar_t wc, struct buf *buf)
|
||||||
{
|
{
|
||||||
if (pixman_image_get_format(buf->pix) == PIXMAN_a8) {
|
const pixman_format_code_t fmt = pixman_image_get_format(buf->pix);
|
||||||
/*
|
const int supersample = fmt == PIXMAN_a8 ? 4 : 1;
|
||||||
* Hack until we’ve implemented ARCs with pixman
|
const int height = buf->height * supersample;
|
||||||
*
|
const int width = buf->width * supersample;
|
||||||
* Replace the a8 buffer with a a1 buffer, and use our “old”
|
const int stride = fmt == PIXMAN_a8
|
||||||
* non-antialiased technique to draw arcs.
|
? stride_for_format_and_width(PIXMAN_a8, width) : buf->stride;
|
||||||
*/
|
uint8_t *data = supersample > 1 ? xcalloc(height * stride, 1) : buf->data;
|
||||||
change_buffer_format(buf, PIXMAN_a1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int thick = thickness(LIGHT);
|
const int thick = thickness(LIGHT) * supersample;
|
||||||
|
|
||||||
double a = (buf->width - thick) / 2;
|
const bool thick_is_odd = (thick / supersample) % 2;
|
||||||
double b = (buf->height - thick) / 2;
|
const bool height_is_odd = buf->height % 2;
|
||||||
|
const bool width_is_odd = buf->width % 2;
|
||||||
|
|
||||||
double a2 = a * a;
|
const double a = (width - thick) / 2;
|
||||||
double b2 = b * b;
|
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++) {
|
for (int i = 0; i < num_samples; i++) {
|
||||||
double y = i / 16.;
|
double y = i / 16.;
|
||||||
double x = sqrt(a2 * (1. - y * y / b2));
|
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) {
|
switch (wc) {
|
||||||
case L'╭':
|
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;
|
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;
|
col_start = col_end - thick;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L'╮':
|
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;
|
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;
|
col_end = col_start + thick;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L'╰':
|
case L'╰':
|
||||||
row_start = row;
|
row_start = row - ((thick_is_odd ^ height_is_odd) ? supersample / 2 : 0);
|
||||||
row_end = row_start + thick;
|
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;
|
col_start = col_end - thick;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L'╯':
|
case L'╯':
|
||||||
row_start = row;
|
row_start = row - ((thick_is_odd ^ height_is_odd) ? supersample / 2 : 0);
|
||||||
row_end = row_start + thick;
|
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;
|
col_end = col_start + thick;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1341,11 +1344,14 @@ draw_box_drawings_light_arc(wchar_t wc, struct buf *buf)
|
||||||
xassert(row_end > row_start);
|
xassert(row_end > row_start);
|
||||||
xassert(col_end > col_start);
|
xassert(col_end > col_start);
|
||||||
|
|
||||||
for (int r = max(row_start, 0); r < max(min(row_end, buf->height), 0); r++) {
|
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, buf->width), 0); c++) {
|
for (int c = max(col_start, 0); c < max(min(col_end, width), 0); c++) {
|
||||||
size_t idx = c / 8;
|
if (fmt == PIXMAN_a1) {
|
||||||
size_t bit_no = c % 8;
|
size_t idx = c / 8;
|
||||||
buf->data[r * buf->stride + idx] |= 1 << bit_no;
|
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'╰') {
|
if (wc == L'╭' || wc == L'╰') {
|
||||||
for (int y = 0; y < thick; y++) {
|
for (int y = 0; y < thick; y++) {
|
||||||
int row = (buf->height - thick) / 2 + y;
|
int row = (height - thick) / 2 + y - ((thick_is_odd ^ height_is_odd) ? supersample / 2 : 0);
|
||||||
int col = buf->width - 1;
|
for (int col = width - supersample; col < width; col++) {
|
||||||
if (row >= 0 && row < buf->height && col >= 0 && col < buf->width) {
|
if (row >= 0 && row < height && col >= 0) {
|
||||||
size_t ofs = col / 8;
|
if (fmt == PIXMAN_a1) {
|
||||||
size_t bit_no = col % 8;
|
size_t ofs = col / 8;
|
||||||
buf->data[row * buf->stride + ofs] |= 1 << bit_no;
|
size_t bit_no = col % 8;
|
||||||
|
data[row * stride + ofs] |= 1 << bit_no;
|
||||||
|
} else
|
||||||
|
data[row * stride + col] = 0xff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wc == L'╭' || wc == L'╮') {
|
if (wc == L'╭' || wc == L'╮') {
|
||||||
for (int x = 0; x < thick; x++) {
|
for (int x = 0; x < thick; x++) {
|
||||||
int row = buf->height - 1;
|
int col = (width - thick) / 2 + x - ((thick_is_odd ^ width_is_odd) ? supersample / 2 : 0);
|
||||||
int col = (buf->width - thick) / 2 + x;
|
for (int row = height - supersample; row < height; row++) {
|
||||||
if (row >= 0 && row < buf->height && col >= 0 && col < buf->width) {
|
if (row >= 0 && col >= 0 && col < width) {
|
||||||
size_t ofs = col / 8;
|
if (fmt == PIXMAN_a1) {
|
||||||
size_t bit_no = col % 8;
|
size_t ofs = col / 8;
|
||||||
buf->data[row * buf->stride + ofs] |= 1 << bit_no;
|
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
|
static void
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue