diff --git a/src/conio/scale.c b/src/conio/scale.c index 880822e38cbbdb387631ce314054354c2e03165b..fa92ebdabdb4127320a7d540a7507747759610de 100644 --- a/src/conio/scale.c +++ b/src/conio/scale.c @@ -8,6 +8,7 @@ static int r2y_inited; static void pointy_scale3(uint32_t* src, uint32_t* dest, int width, int height); static void pointy_scale5(uint32_t* src, uint32_t* dest, int width, int height); static void interpolate_height(uint32_t* src, uint32_t* dst, int width, int height, int newheight); +static void interpolate_width(uint32_t* src, uint32_t* dst, int width, int height, int newwidth); static void multiply_scale(uint32_t* src, uint32_t* dst, int width, int height, int xmult, int ymult); static struct graphics_buffer *free_list; @@ -104,6 +105,7 @@ do_scale(struct rectlist* rect, int* xscale, int* yscale, double ratio) struct graphics_buffer *csrc; uint32_t* nt; int fheight; + int fwidth; switch (*xscale) { case 1: @@ -172,10 +174,18 @@ do_scale(struct rectlist* rect, int* xscale, int* yscale, double ratio) } // Calculate the scaled height from ratio... - fheight = lround((double)(rect->rect.height * (*yscale)) / ratio); + if (ratio < 1) + fheight = lround((double)(rect->rect.height * (*yscale)) / ratio); + else + fheight = rect->rect.height * *yscale; + + if (ratio > 1) + fwidth = lround((double)(rect->rect.width * (*xscale)) / ratio); + else + fwidth = rect->rect.width * *xscale; // Now make sure target is big enough... - size_t needsz = rect->rect.width * (*xscale) * fheight * sizeof(uint32_t); + size_t needsz = fwidth * fheight * sizeof(uint32_t); if (needsz > ret1->sz) { nt = realloc(ret1->data, needsz); if (nt == NULL) @@ -259,7 +269,7 @@ do_scale(struct rectlist* rect, int* xscale, int* yscale, double ratio) } // And finally, interpolate if needed - if (ratio != 1) { + if (ratio < 1) { interpolate_height(csrc->data, ctarget->data, csrc->w, csrc->h, fheight); ctarget->h = fheight; ctarget->w = csrc->w; @@ -270,6 +280,17 @@ do_scale(struct rectlist* rect, int* xscale, int* yscale, double ratio) ctarget = ret1; } + if (ratio > 1) { + interpolate_width(csrc->data, ctarget->data, csrc->w, csrc->h, fwidth); + ctarget->h = csrc->h; + ctarget->w = fwidth; + csrc = ctarget; + if (ctarget == ret1) + ctarget = ret2; + else + ctarget = ret1; + } + *xscale = newscale; *yscale = newscale; release_buffer(ctarget); @@ -495,6 +516,46 @@ uint32_t blend(const uint32_t c1, const uint32_t c2, const double weight) return y2r[(y<<16)|(u<<8)|v]; } +/* + * This does non-integer *width* scaling. It does not scale in the other + * direction. This does the interpolation using Y'UV to prevent dimming of + * pixels. + */ +static void +interpolate_width(uint32_t* src, uint32_t* dst, int width, int height, int newwidth) +{ + int x, y; + const double mult = (double)width / newwidth; + + for (y = 0; y < height; y++) { + for (x = 0; x < newwidth; x++) { + // First, calculate which two pixels this is between. + const double xpos = mult * x; + const int xposi = xpos; + if (x == xpos) { + // Exact match! + *dst = src[width * y + x]; + } + else { + const double weight = xpos - xposi; + // Now pick the two pixels + const uint32_t pix1 = src[y * width + xposi] & 0xffffff; + uint32_t pix2; + if (xposi < width - 1) + pix2 = src[y * width + xposi + 1] & 0xffffff; + else + pix2 = src[y * width + xposi] & 0xffffff; + if (pix1 == pix2) + *dst = pix1; + else { + *dst = blend(pix1, pix2, weight); + } + } + dst++; + } + } +} + /* * This does non-integer *height* scaling. It does not scale in the other * direction. This does the interpolation using Y'UV to prevent dimming of diff --git a/src/conio/vidmodes.c b/src/conio/vidmodes.c index f804377efd66aa056685a866b9425216ebfb938e..463fd00711a144746e6f49ce2ac85b0c4481c5ed 100644 --- a/src/conio/vidmodes.c +++ b/src/conio/vidmodes.c @@ -67,7 +67,7 @@ struct video_params vparams[] = { /* BW 80x28 */ {BW80X28, GREYSCALE_PALETTE, 80, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 640, 392}, /* BW 80x43 */ - {BW80X43, GREYSCALE_PALETTE, 80, 43, 7, 7, 14, 8, 1, 7, 0, 1, 1, 640, 350}, + {BW80X43, GREYSCALE_PALETTE, 80, 43, 7, 7, 14, 8, 1, 7, 0, 729, 1000, 640, 350}, /* BW 80x50 */ {BW80X50, GREYSCALE_PALETTE, 80, 50, 7, 7, 8, 8, 1, 7, 0, 833, 1000, 640, 400}, /* BW 80x60 */ @@ -87,11 +87,11 @@ struct video_params vparams[] = { /* Magical C4350 Mode */ {C4350, COLOUR_PALETTE, 80, 50, 7, 7, 8, 8, 1, 7, 0, 833, 1000, 640, 400}, /* Commodore 64 40x25 mode */ - {C64_40X25, C64_PALETTE, 40, 25, 0, 7, 8, 8, 1, 0x6e, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 1, 1, 320, 200}, + {C64_40X25, C64_PALETTE, 40, 25, 0, 7, 8, 8, 1, 0x6e, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 240, 312, 320, 200}, /* Commodore 128 40x25 mode */ - {C128_40X25, C64_PALETTE, 40, 25, 0, 7, 8, 8, 1, 0xbd, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 1, 1, 320, 200}, + {C128_40X25, C64_PALETTE, 40, 25, 0, 7, 8, 8, 1, 0xbd, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 240, 312, 320, 200}, /* Commodore 128 80x25 mode */ - {C128_80X25, COLOUR_PALETTE, 80, 25, 0, 7, 8, 8, 2, 7, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 1, 1, 640, 200}, + {C128_80X25, COLOUR_PALETTE, 80, 25, 0, 7, 8, 8, 2, 7, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 240, 312, 640, 200}, /* Atari 800 40x24 mode */ {ATARI_40X24, ATARI_PALETTE, 40, 24, 0, 7, 8, 8, 1, 7, 0, 1, 1, 320, 192}, /* Atari 800 XEP80 80x25 mode */