@@ -57,12 +57,31 @@ void pntr_clear(painter_t *p)
57
57
if (!p -> target -> data )
58
58
return ;
59
59
60
- uint32_t * begin = p -> target -> data ;
61
- uint32_t * end = p -> target -> data + p -> target -> height * (p -> target -> pitch >> 2 );
62
60
uint32_t color = p -> background ;
63
61
64
- while (begin < end )
65
- * begin ++ = color ;
62
+ if (p -> clip .x == 0 && p -> clip .width == p -> target -> width
63
+ && p -> clip .y == 0 && p -> clip .height == p -> target -> height )
64
+ {
65
+ // this loop might be optimized by the compiler in comparison with
66
+ // the alternative loop below.
67
+ uint32_t * begin = p -> target -> data ;
68
+ uint32_t * end = p -> target -> data + p -> target -> height * (p -> target -> pitch >> 2 );
69
+ while (begin < end )
70
+ {
71
+ * begin ++ = color ;
72
+ }
73
+ }
74
+ else
75
+ {
76
+ // less efficient loop than above, but can handle clipping rect.
77
+ for (uint32_t x = MAX (0 , p -> clip .x ); x < MIN (p -> clip .x + p -> clip .width , p -> target -> width ); ++ x )
78
+ {
79
+ for (uint32_t y = MAX (0 , p -> clip .y ); y < MAX (p -> clip .y + p -> clip .height , y < p -> target -> height ); ++ y )
80
+ {
81
+ p -> target -> data [x + y * (p -> target -> pitch >> 2 )] = color ;
82
+ }
83
+ }
84
+ }
66
85
}
67
86
68
87
@@ -333,29 +352,114 @@ void pntr_draw(painter_t *p, const bitmap_t *bmp, const rect_t *src_rect, const
333
352
rect_t srect = * src_rect , drect = * dst_rect ;
334
353
335
354
drect .x += p -> trans -> tx ;
336
- drect .y += p -> trans -> ty ;
355
+ drect .y -= p -> trans -> ty ;
356
+
357
+ #ifdef HAVE_TRANSFORM
358
+ // stored as 0 or 0xffffffff for masking properties.
359
+ const uint32_t is_x_reversed = (p -> trans -> sx < 0 ) ? 0xffffffff : 0 ;
360
+ const uint32_t is_y_reversed = (p -> trans -> sy < 0 ) ? 0xffffffff : 0 ;
361
+
362
+ float abs_sx = is_x_reversed ? - p -> trans -> sx : p -> trans -> sx ;
363
+ float abs_sy = is_y_reversed ? - p -> trans -> sy : p -> trans -> sy ;
364
+
365
+ drect .width = srect .width * abs_sx ;
366
+ drect .height = srect .height * abs_sy ;
367
+
368
+ const uint32_t k_binexp = 16 ;
369
+ const uint32_t k_binexp_center = (1 << (k_binexp - 1 ));
370
+
371
+ // give up if scaling is small enough that division becomes untenable
372
+ if (abs_sx < 1.0 /k_binexp_center || abs_sy < 1.0 /k_binexp_center )
373
+ return ;
374
+
375
+ const uint32_t inv_scale_x = (1 << k_binexp ) / abs_sx ;
376
+ const uint32_t inv_scale_y = (1 << k_binexp ) / abs_sy ;
377
+
378
+ #define SCALE_DST_TO_SRC (axis , a ) (((a) * inv_scale_##axis + k_binexp_center) >> k_binexp)
337
379
338
- /* scaling not supported */
380
+ // negative scaling reverses the top-left and bottom-right corners like so:
381
+ if (is_x_reversed )
382
+ {
383
+ drect .x -= drect .width ;
384
+ }
385
+ if (is_y_reversed )
386
+ {
387
+ drect .y -= drect .height ;
388
+ }
389
+ #else
339
390
drect .width = srect .width ;
340
391
drect .height = srect .height ;
341
392
393
+ #define SCALE_DST_TO_SRC (axis , a ) (a)
394
+ #define is_x_reversed 0
395
+ #define is_y_reversed 0
396
+ #endif
397
+
398
+ // crop source rect to destination
342
399
if (drect .x < 0 )
343
400
{
344
- srect .x += - drect .x ;
345
- srect .width += drect .x ;
401
+ srect .width += SCALE_DST_TO_SRC (x , drect .x );
402
+ if (!is_x_reversed )
403
+ {
404
+ // (crop from left side of source)
405
+ srect .x += SCALE_DST_TO_SRC (x , - drect .x );
406
+ }
407
+ drect .width += drect .x ;
408
+ drect .x = 0 ;
346
409
}
347
410
348
411
if (drect .y < 0 )
349
412
{
350
- srect .y += - drect .y ;
351
- srect .height += drect .y ;
413
+ srect .height += SCALE_DST_TO_SRC (y , drect .y );
414
+ if (!is_y_reversed )
415
+ {
416
+ // (crop from top of source)
417
+ srect .y += SCALE_DST_TO_SRC (y , - drect .y );
418
+ }
419
+ drect .height += drect .y ;
420
+ drect .y = 0 ;
352
421
}
353
422
354
- drect = rect_intersect (& drect , & p -> clip );
355
- drect .width = MIN (drect .width , srect .width );
356
- drect .height = MIN (drect .height , srect .height );
423
+ rect_t drect_clipped = rect_intersect (& drect , & p -> clip );
424
+
425
+ // (note: this can never be negative, so srect.x, srect.y remain positive)
426
+ srect .x += SCALE_DST_TO_SRC (x , drect_clipped .x - drect .x );
427
+ srect .width -= SCALE_DST_TO_SRC (x , drect .width - drect_clipped .width );
428
+ srect .y += SCALE_DST_TO_SRC (y , drect_clipped .y - drect .y );
429
+ srect .height -= SCALE_DST_TO_SRC (y , drect .height - drect_clipped .height );
357
430
358
- if (rect_is_null (& drect ) || rect_is_null (& srect ))
431
+ drect = drect_clipped ;
432
+
433
+ // ensure source rect is cropped to source bounds
434
+ if (srect .x + srect .width > bmp -> width )
435
+ {
436
+ srect .width = bmp -> width - srect .x ;
437
+ }
438
+ if (srect .y + srect .height > bmp -> height )
439
+ {
440
+ srect .height = bmp -> height - srect .y ;
441
+ }
442
+
443
+ // ensure we won't exceed the bitmap's data during the upcoming blit:
444
+ #ifdef HAVE_TRANSFORM
445
+ // temporary implementation
446
+ // TODO: replace this.
447
+ if (srect .x >= bmp -> width || srect .y >= bmp -> height )
448
+ return ;
449
+ while (srect .x + SCALE_DST_TO_SRC (x , drect .width ) > bmp -> width )
450
+ {
451
+ drect .width -- ;
452
+ }
453
+ while (srect .y + SCALE_DST_TO_SRC (y , drect .height ) > bmp -> height )
454
+ {
455
+ drect .height -- ;
456
+ }
457
+ #else
458
+ drect .width = MIN (drect .width , srect .width );
459
+ drect .height = MIN (drect .height , srect .height );
460
+ #endif
461
+
462
+ if (rect_is_null (& drect ) || rect_is_null (& srect ) || p -> trans -> sx == 0 || p -> trans -> sy == 0 )
359
463
return ;
360
464
361
465
size_t dst_skip = p -> target -> pitch >> 2 ;
@@ -368,39 +472,47 @@ void pntr_draw(painter_t *p, const bitmap_t *bmp, const rect_t *src_rect, const
368
472
int cols = drect .width ;
369
473
int x = 0 ;
370
474
475
+ #ifdef HAVE_TRANSFORM
476
+ uint32_t y = 0 ;
477
+ #endif
371
478
#ifdef HAVE_COMPOSITION
372
479
uint32_t sa , sr , sg , sb , da , dr , dg , db , s , d ;
480
+ #else
481
+ uint32_t s ;
482
+ #endif
373
483
while (rows_left -- )
374
484
{
375
485
for (x = 0 ; x < cols ; ++ x )
376
486
{
487
+ #ifdef HAVE_TRANSFORM
488
+ uint32_t xo = (x & ~is_x_reversed ) | ((cols - x - 1 ) & is_x_reversed );
489
+ uint32_t yo = (y & ~is_y_reversed ) | ((drect .height - y - 1 ) & is_y_reversed );
490
+ uint32_t xi = SCALE_DST_TO_SRC (x , xo );
491
+ uint32_t yi = SCALE_DST_TO_SRC (y , yo );
492
+ s = src [xi + yi * src_skip ];
493
+ #else
377
494
s = src [x ];
495
+ #endif
496
+ #ifdef HAVE_COMPOSITION
378
497
d = dst [x ];
379
498
sa = s >> 24 ;
380
499
da = d >> 24 ;
381
500
DISASSEMBLE_RGB (s , sr , sg , sb );
382
501
DISASSEMBLE_RGB (d , dr , dg , db );
383
502
dst [x ] = ((sa + da * (255 - sa )) << 24 ) | (COMPOSE_FAST (sr , dr , sa ) << 16 ) | (COMPOSE_FAST (sg , dg , sa ) << 8 ) | (COMPOSE_FAST (sb , db , sa ));
384
- }
385
-
386
- dst += dst_skip ;
387
- src += src_skip ;
388
- }
389
503
#else
390
- uint32_t c ;
391
- while (rows_left -- )
392
- {
393
- for (x = 0 ; x < cols ; ++ x )
394
- {
395
- c = src [x ];
396
- if (c & 0xff000000 )
397
- dst [x ] = c ;
504
+ if (s & 0xff000000 )
505
+ dst [x ] = s ;
506
+ #endif
398
507
}
399
508
400
509
dst += dst_skip ;
510
+ #ifdef HAVE_TRANSFORM
511
+ y += 1 ;
512
+ #else
401
513
src += src_skip ;
402
- }
403
514
#endif
515
+ }
404
516
}
405
517
406
518
@@ -453,14 +565,14 @@ void pntr_print(painter_t *p, int x, int y, const char *text, int limit)
453
565
if (limit > 0 && drect .x - x > limit )
454
566
{
455
567
drect .x = x ;
456
- drect .y += atlas -> height ;
457
- }
568
+ drect .y += atlas -> height ;
569
+ }
458
570
459
- if (c == '\n' )
460
- {
571
+ if (c == '\n' )
572
+ {
461
573
drect .x = x ;
462
- drect .y += atlas -> height ;
463
- }
574
+ drect .y += atlas -> height ;
575
+ }
464
576
}
465
577
466
578
if (utf32 != buf )
0 commit comments