|
43 | 43 | #define M_PI 3.14159265358979323846
|
44 | 44 | #endif
|
45 | 45 |
|
| 46 | +/* Pretty good idea from Tom Duff :-). */ |
| 47 | +#ifndef LOOP_UNROLLED4 |
| 48 | +#define LOOP_UNROLLED4(code, n, width) \ |
| 49 | + n = (width + 3) / 4; \ |
| 50 | + switch (width & 3) { \ |
| 51 | + case 0: \ |
| 52 | + do { \ |
| 53 | + code; \ |
| 54 | + case 3: \ |
| 55 | + code; \ |
| 56 | + case 2: \ |
| 57 | + code; \ |
| 58 | + case 1: \ |
| 59 | + code; \ |
| 60 | + } while (--n > 0); \ |
| 61 | + } |
| 62 | +#endif |
| 63 | + |
46 | 64 | /* Macro to create mask objects. This will call the type's tp_new and tp_init.
|
47 | 65 | * Params:
|
48 | 66 | * w: width of mask
|
@@ -770,22 +788,61 @@ set_pixel_color(Uint8 *pixel, Uint8 bpp, Uint32 color)
|
770 | 788 | static void
|
771 | 789 | set_from_threshold(SDL_Surface *surf, bitmask_t *bitmask, int threshold)
|
772 | 790 | {
|
773 |
| - SDL_PixelFormat *format = surf->format; |
774 |
| - Uint8 bpp = PG_FORMAT_BytesPerPixel(format); |
775 |
| - Uint8 *pixel = NULL; |
776 |
| - Uint8 rgba[4]; |
777 |
| - int x, y; |
778 |
| - |
779 |
| - for (y = 0; y < surf->h; ++y) { |
780 |
| - pixel = (Uint8 *)surf->pixels + y * surf->pitch; |
| 791 | + /* This function expects surf to be non-zero sized. */ |
| 792 | + SDL_PixelFormat *fmt = surf->format; |
| 793 | + const Uint8 bpp = PG_FORMAT_BytesPerPixel(fmt); |
| 794 | + int x, y, n; |
| 795 | + Uint8 *srcp; |
| 796 | + const int src_skip = surf->pitch - surf->w * bpp; |
| 797 | + |
| 798 | + if (threshold >= 255) { |
| 799 | + return; |
| 800 | + } |
781 | 801 |
|
782 |
| - for (x = 0; x < surf->w; ++x, pixel += bpp) { |
783 |
| - SDL_GetRGBA(get_pixel_color(pixel, bpp), format, rgba, rgba + 1, |
784 |
| - rgba + 2, rgba + 3); |
785 |
| - if (rgba[3] > threshold) { |
786 |
| - bitmask_setbit(bitmask, x, y); |
| 802 | + if (threshold < 0 || !SDL_ISPIXELFORMAT_ALPHA(fmt->format)) { |
| 803 | + bitmask_fill(bitmask); |
| 804 | + return; |
| 805 | + } |
| 806 | + else if (bpp < 3) { |
| 807 | + Uint8 r, g, b, a; |
| 808 | + srcp = (Uint8 *)surf->pixels; |
| 809 | + for (y = 0; y < surf->h; ++y) { |
| 810 | + for (x = 0; x < surf->w; ++x, srcp += bpp) { |
| 811 | + SDL_GetRGBA(bpp == 1 ? *srcp : *((Uint16 *)srcp), fmt, &r, &g, |
| 812 | + &b, &a); |
| 813 | + if (a > threshold) |
| 814 | + bitmask_setbit(bitmask, x, y); |
787 | 815 | }
|
| 816 | + srcp += src_skip; |
788 | 817 | }
|
| 818 | + return; |
| 819 | + } |
| 820 | + |
| 821 | + /* With this strategy we avoid to get the rgb channels that we don't need |
| 822 | + * and instead we just jump from alpha channel to alpha channel, comparing |
| 823 | + * it with the threshold. */ |
| 824 | + |
| 825 | +#if SDL_BYTEORDER == SDL_LIL_ENDIAN |
| 826 | + const char _a_off = fmt->Ashift >> 3; |
| 827 | +#else |
| 828 | + const char _a_off = 3 - (fmt->Ashift >> 3); |
| 829 | +#endif |
| 830 | + |
| 831 | + srcp = (Uint8 *)surf->pixels + _a_off; |
| 832 | + const Uint8 u_threshold = (Uint8)threshold; |
| 833 | + |
| 834 | + for (y = 0; y < surf->h; ++y) { |
| 835 | + x = 0; |
| 836 | + LOOP_UNROLLED4( |
| 837 | + { |
| 838 | + if ((*srcp) > u_threshold) |
| 839 | + bitmask_setbit(bitmask, x, y); |
| 840 | + srcp += bpp; |
| 841 | + x++; |
| 842 | + }, |
| 843 | + n, surf->w); |
| 844 | + |
| 845 | + srcp += src_skip; |
789 | 846 | }
|
790 | 847 | }
|
791 | 848 |
|
|
0 commit comments