diff options
author | neonloop | 2021-04-02 14:32:47 +0000 |
---|---|---|
committer | neonloop | 2021-04-02 14:32:47 +0000 |
commit | c6d6e8c60dcbdf977597f6df89511b4ac4fa0a38 (patch) | |
tree | b0f1321bbc31b07d2f29b2913d4232132c857cf1 /frontend | |
parent | ab945e9e1baba5fbb691444b79b36930afb2a179 (diff) | |
download | picogpsp-c6d6e8c60dcbdf977597f6df89511b4ac4fa0a38.tar.gz picogpsp-c6d6e8c60dcbdf977597f6df89511b4ac4fa0a38.tar.bz2 picogpsp-c6d6e8c60dcbdf977597f6df89511b4ac4fa0a38.zip |
Adds a "smooth subpixel" upscaler
Thanks to drowsnug for the original implementation of a subpixel
scaler. This scaler uses the core of that one, but smooths the
transition in the new pixels added during scaling.
If you think of the scaler as 4x integer scaling of the GBA screen,
and assigning each of those pixels to a subpixel, each subpixel takes
the value of 50% the pixel assigned, 25% of the pixel to its left, and
25% of the pixel to its right.
With the pixels:
BGRBGRBGRBGR
AAAABBBBCCCC
^--- this subpixel will be 1/4 A[G] + 1/2 B[G] + 1/4 B[G]
The first and last pixels in each batch are not blended with the
previous / next batch to keep them sharp.
Diffstat (limited to 'frontend')
-rw-r--r-- | frontend/scale.c | 55 |
1 files changed, 52 insertions, 3 deletions
diff --git a/frontend/scale.c b/frontend/scale.c index 24f8a5a..3f471b7 100644 --- a/frontend/scale.c +++ b/frontend/scale.c @@ -381,6 +381,56 @@ static inline void gba_nofilter_upscale(uint16_t *dst, uint16_t *src, int h) } } +#define EXTRACT(c, mask, offset) ((c >> offset) & mask) +#define BLENDCHANNEL(cl, cm, cr, mask, offset) ((((EXTRACT(cl, mask, offset) + 2 * EXTRACT(cm, mask, offset) + EXTRACT(cr, mask, offset)) >> 2) & mask) << offset) +#define BLENDB(cl, cm, cr) BLENDCHANNEL(cl, cm, cr, 0b0000000000011111, 0) +#define BLENDG(cl, cm, cr) BLENDCHANNEL(cl, cm, cr, 0b0000011111100000, 0) +#define BLENDR(cl, cm, cr) BLENDCHANNEL(cl, cm, cr, 0b0011111000000000, 2) +static inline void gba_smooth_subpx_upscale(uint16_t *dst, uint16_t *src, int h) +{ + int Eh = 0; + int dh = 0; + int width = 240; + int vf = 0; + + dst += ((240-h)/2) * 320; // blank upper border. h=240(full) or h=214(aspect) + + int x, y; + for (y = 0; y < h; y++) + { + int source = dh * width; + for (x = 0; x < 320/4; x++) + { + register uint16_t a, b, c; + + a = src[source]; + b = src[source+1]; + c = src[source+2]; + + if(vf == 1){ + a = AVERAGE16(a, src[source+width]); + b = AVERAGE16(b, src[source+width+1]); + c = AVERAGE16(c, src[source+width+2]); + } + + *dst++ = a; + *dst++ = BLENDB(a, a, b) | BLENDG(a, b, b) | BLENDR(b, b, b); + *dst++ = BLENDB(b, b, b) | BLENDG(b, b, c) | BLENDR(b, c, c); + *dst++ = c; + + source+=3; + } + Eh += 160; + if(Eh >= h) { + Eh -= h; + dh++; + vf = 0; + } + else + vf = 1; + } +} + void video_clear_msg(uint16_t *dst, uint32_t h, uint32_t pitch) { memset(dst + (h - 10) * pitch, 0, 10 * pitch * sizeof(uint16_t)); @@ -403,14 +453,13 @@ void video_scale(uint16_t *dst, uint32_t h, uint32_t pitch) { gba_nofilter_upscale(dst, gba_screen_pixels_buf, 214); break; case SCALING_ASPECT_SMOOTH: - dst += ((h - (GBA_SCREEN_HEIGHT * 4 / 3)) / 2 * pitch); - gba_upscale_aspect(dst, gba_screen_pixels_buf, GBA_SCREEN_WIDTH, GBA_SCREEN_HEIGHT, GBA_SCREEN_PITCH * 2, pitch * 2); + gba_smooth_subpx_upscale(dst, gba_screen_pixels_buf, 214); break; case SCALING_FULL_SHARP: gba_nofilter_upscale(dst, gba_screen_pixels_buf, 240); break; case SCALING_FULL_SMOOTH: - gba_upscale(dst, gba_screen_pixels_buf, GBA_SCREEN_WIDTH, GBA_SCREEN_HEIGHT, GBA_SCREEN_PITCH * 2, pitch * 2); + gba_smooth_subpx_upscale(dst, gba_screen_pixels_buf, 240); break; default: gba_nofilter_noscale(dst, h, pitch, gba_screen_pixels_buf); |