Skip to content

Commit 0dd60d1

Browse files
committed
plutovg: Add bilinear filtering to tiled image rendering
1 parent 2cdbfab commit 0dd60d1

File tree

1 file changed

+68
-34
lines changed

1 file changed

+68
-34
lines changed

plutovg/source/plutovg-blend.c

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -55,23 +55,37 @@ static inline uint32_t premultiply_color_with_opacity(const plutovg_color_t* col
5555
return (alpha << 24) | (pr << 16) | (pg << 8) | (pb);
5656
}
5757

58-
static inline uint32_t INTERPOLATE_PIXEL(uint32_t x, uint32_t a, uint32_t y, uint32_t b)
58+
static inline uint32_t INTERPOLATE_PIXEL_255(uint32_t x, uint32_t a, uint32_t y, uint32_t b)
5959
{
6060
uint32_t t = (x & 0xff00ff) * a + (y & 0xff00ff) * b;
6161
t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
6262
t &= 0xff00ff;
63+
6364
x = ((x >> 8) & 0xff00ff) * a + ((y >> 8) & 0xff00ff) * b;
6465
x = (x + ((x >> 8) & 0xff00ff) + 0x800080);
6566
x &= 0xff00ff00;
6667
x |= t;
6768
return x;
6869
}
6970

71+
static inline uint32_t INTERPOLATE_PIXEL_256(uint32_t x, uint32_t a, uint32_t y, uint32_t b)
72+
{
73+
uint32_t t = (x & 0xff00ff) * a + (y & 0xff00ff) * b;
74+
t >>= 8;
75+
t &= 0xff00ff;
76+
77+
x = ((x >> 8) & 0xff00ff) * a + ((y >> 8) & 0xff00ff) * b;
78+
x &= 0xff00ff00;
79+
x |= t;
80+
return x;
81+
}
82+
7083
static inline uint32_t BYTE_MUL(uint32_t x, uint32_t a)
7184
{
7285
uint32_t t = (x & 0xff00ff) * a;
7386
t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
7487
t &= 0xff00ff;
88+
7589
x = ((x >> 8) & 0xff00ff) * a;
7690
x = (x + ((x >> 8) & 0xff00ff) + 0x800080);
7791
x &= 0xff00ff00;
@@ -346,7 +360,7 @@ static void composition_solid_source_in(uint32_t* dest, int length, uint32_t col
346360
uint32_t cia = 255 - const_alpha;
347361
for(int i = 0; i < length; i++) {
348362
uint32_t d = dest[i];
349-
dest[i] = INTERPOLATE_PIXEL(color, plutovg_alpha(d), d, cia);
363+
dest[i] = INTERPOLATE_PIXEL_255(color, plutovg_alpha(d), d, cia);
350364
}
351365
}
352366
}
@@ -372,7 +386,7 @@ static void composition_solid_source_out(uint32_t* dest, int length, uint32_t co
372386
uint32_t cia = 255 - const_alpha;
373387
for(int i = 0; i < length; i++) {
374388
uint32_t d = dest[i];
375-
dest[i] = INTERPOLATE_PIXEL(color, plutovg_alpha(~d), d, cia);
389+
dest[i] = INTERPOLATE_PIXEL_255(color, plutovg_alpha(~d), d, cia);
376390
}
377391
}
378392
}
@@ -394,7 +408,7 @@ static void composition_solid_source_atop(uint32_t* dest, int length, uint32_t c
394408
uint32_t sia = plutovg_alpha(~color);
395409
for(int i = 0; i < length; i++) {
396410
uint32_t d = dest[i];
397-
dest[i] = INTERPOLATE_PIXEL(color, plutovg_alpha(d), d, sia);
411+
dest[i] = INTERPOLATE_PIXEL_255(color, plutovg_alpha(d), d, sia);
398412
}
399413
}
400414

@@ -408,7 +422,7 @@ static void composition_solid_destination_atop(uint32_t* dest, int length, uint3
408422

409423
for(int i = 0; i < length; i++) {
410424
uint32_t d = dest[i];
411-
dest[i] = INTERPOLATE_PIXEL(d, a, color, plutovg_alpha(~d));
425+
dest[i] = INTERPOLATE_PIXEL_255(d, a, color, plutovg_alpha(~d));
412426
}
413427
}
414428

@@ -419,7 +433,7 @@ static void composition_solid_xor(uint32_t* dest, int length, uint32_t color, ui
419433
uint32_t sia = plutovg_alpha(~color);
420434
for(int i = 0; i < length; i++) {
421435
uint32_t d = dest[i];
422-
dest[i] = INTERPOLATE_PIXEL(color, plutovg_alpha(~d), d, sia);
436+
dest[i] = INTERPOLATE_PIXEL_255(color, plutovg_alpha(~d), d, sia);
423437
}
424438
}
425439

@@ -459,7 +473,7 @@ static void composition_source(uint32_t* dest, int length, const uint32_t* src,
459473
} else {
460474
uint32_t ialpha = 255 - const_alpha;
461475
for(int i = 0; i < length; i++) {
462-
dest[i] = INTERPOLATE_PIXEL(src[i], const_alpha, dest[i], ialpha);
476+
dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha);
463477
}
464478
}
465479
}
@@ -475,7 +489,7 @@ static void composition_source_over(uint32_t* dest, int length, const uint32_t*
475489
uint32_t s = src[i];
476490
if(s >= 0xff000000) {
477491
dest[i] = s;
478-
} else if (s != 0) {
492+
} else if(s != 0) {
479493
dest[i] = s + BYTE_MUL(dest[i], plutovg_alpha(~s));
480494
}
481495
}
@@ -514,7 +528,7 @@ static void composition_source_in(uint32_t* dest, int length, const uint32_t* sr
514528
for(int i = 0; i < length; i++) {
515529
uint32_t d = dest[i];
516530
uint32_t s = BYTE_MUL(src[i], const_alpha);
517-
dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(d), d, cia);
531+
dest[i] = INTERPOLATE_PIXEL_255(s, plutovg_alpha(d), d, cia);
518532
}
519533
}
520534
}
@@ -545,7 +559,7 @@ static void composition_source_out(uint32_t* dest, int length, const uint32_t* s
545559
for(int i = 0; i < length; i++) {
546560
uint32_t s = BYTE_MUL(src[i], const_alpha);
547561
uint32_t d = dest[i];
548-
dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(~d), d, cia);
562+
dest[i] = INTERPOLATE_PIXEL_255(s, plutovg_alpha(~d), d, cia);
549563
}
550564
}
551565
}
@@ -571,13 +585,13 @@ static void composition_source_atop(uint32_t* dest, int length, const uint32_t*
571585
for(int i = 0; i < length; i++) {
572586
uint32_t s = src[i];
573587
uint32_t d = dest[i];
574-
dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(d), d, plutovg_alpha(~s));
588+
dest[i] = INTERPOLATE_PIXEL_255(s, plutovg_alpha(d), d, plutovg_alpha(~s));
575589
}
576590
} else {
577591
for(int i = 0; i < length; i++) {
578592
uint32_t s = BYTE_MUL(src[i], const_alpha);
579593
uint32_t d = dest[i];
580-
dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(d), d, plutovg_alpha(~s));
594+
dest[i] = INTERPOLATE_PIXEL_255(s, plutovg_alpha(d), d, plutovg_alpha(~s));
581595
}
582596
}
583597
}
@@ -588,15 +602,15 @@ static void composition_destination_atop(uint32_t* dest, int length, const uint3
588602
for(int i = 0; i < length; i++) {
589603
uint32_t s = src[i];
590604
uint32_t d = dest[i];
591-
dest[i] = INTERPOLATE_PIXEL(d, plutovg_alpha(s), s, plutovg_alpha(~d));
605+
dest[i] = INTERPOLATE_PIXEL_255(d, plutovg_alpha(s), s, plutovg_alpha(~d));
592606
}
593607
} else {
594608
uint32_t cia = 255 - const_alpha;
595609
for(int i = 0; i < length; i++) {
596610
uint32_t s = BYTE_MUL(src[i], const_alpha);
597611
uint32_t d = dest[i];
598612
uint32_t a = plutovg_alpha(s) + cia;
599-
dest[i] = INTERPOLATE_PIXEL(d, a, s, plutovg_alpha(~d));
613+
dest[i] = INTERPOLATE_PIXEL_255(d, a, s, plutovg_alpha(~d));
600614
}
601615
}
602616
}
@@ -607,13 +621,13 @@ static void composition_xor(uint32_t* dest, int length, const uint32_t* src, uin
607621
for(int i = 0; i < length; i++) {
608622
uint32_t d = dest[i];
609623
uint32_t s = src[i];
610-
dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(~d), d, plutovg_alpha(~s));
624+
dest[i] = INTERPOLATE_PIXEL_255(s, plutovg_alpha(~d), d, plutovg_alpha(~s));
611625
}
612626
} else {
613627
for(int i = 0; i < length; i++) {
614628
uint32_t d = dest[i];
615629
uint32_t s = BYTE_MUL(src[i], const_alpha);
616-
dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(~d), d, plutovg_alpha(~s));
630+
dest[i] = INTERPOLATE_PIXEL_255(s, plutovg_alpha(~d), d, plutovg_alpha(~s));
617631
}
618632
}
619633
}
@@ -852,14 +866,23 @@ static void blend_untransformed_tiled_argb(plutovg_surface_t* surface, plutovg_o
852866
}
853867
}
854868

869+
static inline uint32_t interpolate_4_pixels(uint32_t tl, uint32_t tr, uint32_t bl, uint32_t br, uint32_t distx, uint32_t disty)
870+
{
871+
uint32_t idistx = 256 - distx;
872+
uint32_t idisty = 256 - disty;
873+
uint32_t xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
874+
uint32_t xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
875+
return INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
876+
}
877+
878+
#define HALF_POINT (1 << 15)
855879
static void blend_transformed_tiled_argb(plutovg_surface_t* surface, plutovg_operator_t op, const texture_data_t* texture, const plutovg_span_buffer_t* span_buffer)
856880
{
857881
composition_function_t func = composition_table[op];
858882
uint32_t buffer[BUFFER_SIZE];
859883

860884
int image_width = texture->width;
861885
int image_height = texture->height;
862-
const int scanline_offset = texture->stride / 4;
863886

864887
int fdx = (int)(texture->matrix.a * FIXED_SCALE);
865888
int fdy = (int)(texture->matrix.b * FIXED_SCALE);
@@ -868,35 +891,46 @@ static void blend_transformed_tiled_argb(plutovg_surface_t* surface, plutovg_ope
868891
const plutovg_span_t* spans = span_buffer->spans.data;
869892
while(count--) {
870893
uint32_t* target = (uint32_t*)(surface->data + spans->y * surface->stride) + spans->x;
871-
const uint32_t* image_bits = (const uint32_t*)texture->data;
872894

873895
const float cx = spans->x + 0.5f;
874896
const float cy = spans->y + 0.5f;
875897

876-
int x = (int)((texture->matrix.c * cy + texture->matrix.a * cx + texture->matrix.e) * FIXED_SCALE);
877-
int y = (int)((texture->matrix.d * cy + texture->matrix.b * cx + texture->matrix.f) * FIXED_SCALE);
898+
int fx = (int)((texture->matrix.c * cy + texture->matrix.a * cx + texture->matrix.e) * FIXED_SCALE);
899+
int fy = (int)((texture->matrix.d * cy + texture->matrix.b * cx + texture->matrix.f) * FIXED_SCALE);
900+
901+
fx -= HALF_POINT;
902+
fy -= HALF_POINT;
878903

879904
const int coverage = (spans->coverage * texture->const_alpha) >> 8;
880905
int length = spans->len;
881906
while(length) {
882907
int l = plutovg_min(length, BUFFER_SIZE);
883908
const uint32_t* end = buffer + l;
884909
uint32_t* b = buffer;
885-
while(b < end) {
886-
int px = x >> 16;
887-
int py = y >> 16;
888-
px %= image_width;
889-
py %= image_height;
890-
if(px < 0) px += image_width;
891-
if(py < 0) py += image_height;
892-
int y_offset = py * scanline_offset;
910+
while (b < end) {
911+
int x1 = (fx >> 16) % image_width;
912+
int y1 = (fy >> 16) % image_height;
893913

894-
assert(px >= 0 && px < image_width);
895-
assert(py >= 0 && py < image_height);
914+
if(x1 < 0) x1 += image_width;
915+
if(y1 < 0) y1 += image_height;
896916

897-
*b = image_bits[y_offset + px];
898-
x += fdx;
899-
y += fdy;
917+
int x2 = (x1 + 1) % image_width;
918+
int y2 = (y1 + 1) % image_height;
919+
920+
const uint32_t* s1 = (const uint32_t*)(texture->data + y1 * texture->stride);
921+
const uint32_t* s2 = (const uint32_t*)(texture->data + y2 * texture->stride);
922+
923+
uint32_t tl = s1[x1];
924+
uint32_t tr = s1[x2];
925+
uint32_t bl = s2[x1];
926+
uint32_t br = s2[x2];
927+
928+
int distx = (fx & 0x0000ffff) >> 8;
929+
int disty = (fy & 0x0000ffff) >> 8;
930+
*b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
931+
932+
fx += fdx;
933+
fy += fdy;
900934
++b;
901935
}
902936

@@ -965,7 +999,7 @@ static void plutovg_blend_gradient(plutovg_canvas_t* canvas, const plutovg_gradi
965999
t = (fpos - curr->offset) * delta;
9661000
dist = (uint32_t)(255 * t);
9671001
idist = 255 - dist;
968-
data.colortable[pos] = INTERPOLATE_PIXEL(curr_color, idist, next_color, dist);
1002+
data.colortable[pos] = INTERPOLATE_PIXEL_255(curr_color, idist, next_color, dist);
9691003
++pos;
9701004
fpos += incr;
9711005
}

0 commit comments

Comments
 (0)