@@ -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+
7083static 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)
855879static 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