Commits (1)
...@@ -120,41 +120,44 @@ do_scale(struct rectlist* rect, int xscale, int yscale, double ratio) ...@@ -120,41 +120,44 @@ do_scale(struct rectlist* rect, int xscale, int yscale, double ratio)
xscale = 1; xscale = 1;
total_yscaling = yscale; total_yscaling = yscale;
yscale = 1; yscale = 1;
if (!(cio_api.options & CONIO_OPT_BLOCKY_SCALING)) { // If x/y scaling isn't a simple multiple, block scale everything...
if ((total_xscaling & 1) == 1 && (total_xscaling == total_yscaling || (total_yscaling % total_xscaling == 0))) { if ((total_yscaling % total_xscaling) == 0) {
pointymult = total_xscaling; if (!(cio_api.options & CONIO_OPT_BLOCKY_SCALING)) {
total_xscaling /= pointymult; if ((total_xscaling & 1) == 1 && total_xscaling > 5) {
xscale *= pointymult; pointymult = total_xscaling;
total_yscaling /= pointymult; total_xscaling /= pointymult;
yscale *= pointymult; xscale *= pointymult;
} total_yscaling /= pointymult;
while (total_xscaling > 1 && ((total_xscaling % 5) == 0) && ((total_yscaling % 5) == 0)) { yscale *= pointymult;
pointy5++; }
total_xscaling /= 5; while (total_xscaling > 1 && ((total_xscaling % 5) == 0) && ((total_yscaling % 5) == 0)) {
xscale *= 5; pointy5++;
total_yscaling /= 5; total_xscaling /= 5;
yscale *= 5; xscale *= 5;
} total_yscaling /= 5;
while (total_xscaling > 1 && ((total_xscaling % 3) == 0) && ((total_yscaling % 3) == 0)) { yscale *= 5;
pointy3++; }
total_xscaling /= 3; while (total_xscaling > 1 && ((total_xscaling % 3) == 0) && ((total_yscaling % 3) == 0)) {
xscale *= 3; pointy3++;
total_yscaling /= 3; total_xscaling /= 3;
yscale *= 3; xscale *= 3;
} total_yscaling /= 3;
while (total_xscaling > 1 && ((total_xscaling % 4) == 0) && ((total_yscaling % 4) == 0)) { yscale *= 3;
xbr4++; }
total_xscaling /= 4; while (total_xscaling > 1 && ((total_xscaling % 4) == 0) && ((total_yscaling % 4) == 0)) {
xscale *= 4; xbr4++;
total_yscaling /= 4; total_xscaling /= 4;
yscale *= 4; xscale *= 4;
} total_yscaling /= 4;
while (total_xscaling > 1 && ((total_xscaling % 2) == 0) && ((total_yscaling % 2) == 0)) { yscale *= 4;
xbr2++; }
total_xscaling /= 2; while (total_xscaling > 1 && ((total_xscaling % 2) == 0) && ((total_yscaling % 2) == 0)) {
xscale *= 2; xbr2++;
total_yscaling /= 2; total_xscaling /= 2;
yscale *= 2; xscale *= 2;
total_yscaling /= 2;
yscale *= 2;
}
} }
} }
...@@ -215,6 +218,18 @@ do_scale(struct rectlist* rect, int xscale, int yscale, double ratio) ...@@ -215,6 +218,18 @@ do_scale(struct rectlist* rect, int xscale, int yscale, double ratio)
csrc->w = rect->rect.width; csrc->w = rect->rect.width;
csrc->h = rect->rect.height; csrc->h = rect->rect.height;
#if 0
fprintf(stderr, "Plan:\n"
"pointymulti: %d\n"
"pointy5: %d\n"
"pointy3: %d\n"
"xBR4: %d\n"
"xBR2: %d\n"
"Multiply: %dx%d\n"
"hinterp: %zu -> %zu\n"
"winterp: %zu -> %zu\n",
pointymult, pointy5, pointy3, xbr4, xbr2, xmult, ymult, csrc->h * yscale, ratio < 1 ? fheight : csrc->h * yscale, csrc->w * xscale, ratio > 1 ? fwidth : csrc->w * xscale);
#endif
// And scale... // And scale...
if (ymult != 1 || xmult != 1) { if (ymult != 1 || xmult != 1) {
multiply_scale(csrc->data, ctarget->data, csrc->w, csrc->h, xmult, ymult); multiply_scale(csrc->data, ctarget->data, csrc->w, csrc->h, xmult, ymult);
...@@ -683,33 +698,29 @@ static void ...@@ -683,33 +698,29 @@ static void
interpolate_height(uint32_t* src, uint32_t* dst, int width, int height, int newheight) interpolate_height(uint32_t* src, uint32_t* dst, int width, int height, int newheight)
{ {
int x, y; int x, y;
bool em = false;
const double mult = (double)height / newheight; const double mult = (double)height / newheight;
for (y = 0; y < newheight; y++) { for (y = 0; y < newheight; y++) {
for (x = 0; x < width; x++) { const double ypos = mult * y;
// First, calculate which two pixels this is between. const int yposi = ypos;
const double ypos = mult * y; em = (y == ypos || yposi >= height - 1);
const int yposi = ypos; if (em) {
if (y == ypos) { memcpy(dst, &src[yposi * width], width * sizeof(dst[0]));
// Exact match! dst += width;
*dst = src[width * yposi + x]; }
} else {
else { const double weight = ypos - yposi;
const double weight = ypos - yposi; for (x = 0; x < width; x++) {
// Now pick the two pixels // Now pick the two pixels
const uint32_t pix1 = src[yposi * width + x] & 0xffffff; const uint32_t pix1 = src[yposi * width + x] & 0xffffff;
uint32_t pix2; const uint32_t pix2 = src[(yposi + 1) * width + x] & 0xffffff;
if (yposi < height - 1)
pix2 = src[(yposi + 1) * width + x] & 0xffffff;
else
pix2 = src[yposi * width + x] & 0xffffff;
if (pix1 == pix2) if (pix1 == pix2)
*dst = pix1; *dst = pix1;
else { else
*dst = blend(pix1, pix2, weight); *dst = blend(pix1, pix2, weight);
} dst++;
} }
dst++;
} }
} }
} }
...@@ -717,8 +728,6 @@ interpolate_height(uint32_t* src, uint32_t* dst, int width, int height, int newh ...@@ -717,8 +728,6 @@ interpolate_height(uint32_t* src, uint32_t* dst, int width, int height, int newh
static void static void
multiply_scale(uint32_t* src, uint32_t* dst, int width, int height, int xmult, int ymult) multiply_scale(uint32_t* src, uint32_t* dst, int width, int height, int xmult, int ymult)
{ {
int nheight = height * ymult;
int nwidth = width * xmult;
int x, y; int x, y;
int mx, my; int mx, my;
uint32_t* slstart; uint32_t* slstart;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "vidmodes.h" #include "vidmodes.h"
#define BITMAP_CIOLIB_DRIVER #define BITMAP_CIOLIB_DRIVER
#include "bitmap_con.h" #include "bitmap_con.h"
#include "scale.h"
#include "SDL.h" #include "SDL.h"
...@@ -38,6 +39,8 @@ unsigned char sdl_keynext=0; /* Index into keybuf for next free position */ ...@@ -38,6 +39,8 @@ unsigned char sdl_keynext=0; /* Index into keybuf for next free position */
int sdl_exitcode=0; int sdl_exitcode=0;
bool internal_scaling = true; // Protected by the win mutex
SDL_Window *win=NULL; SDL_Window *win=NULL;
SDL_Cursor *curs=NULL; SDL_Cursor *curs=NULL;
SDL_Renderer *renderer=NULL; SDL_Renderer *renderer=NULL;
...@@ -565,12 +568,14 @@ static void setup_surfaces_locked(void) ...@@ -565,12 +568,14 @@ static void setup_surfaces_locked(void)
vmultiplier = cvstat.vmultiplier; vmultiplier = cvstat.vmultiplier;
idealh = roundl((long double)cvstat.winwidth * cvstat.scale_denominator / cvstat.scale_numerator * cvstat.scrnheight / cvstat.scrnwidth); idealh = roundl((long double)cvstat.winwidth * cvstat.scale_denominator / cvstat.scale_numerator * cvstat.scrnheight / cvstat.scrnwidth);
idealmh = roundl((long double)cvstat.scrnwidth * cvstat.scale_denominator / cvstat.scale_numerator * cvstat.scrnheight / cvstat.scrnwidth); idealmh = roundl((long double)cvstat.scrnwidth * cvstat.scale_denominator / cvstat.scale_numerator * cvstat.scrnheight / cvstat.scrnwidth);
internal_scaling = true;
sdl.SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
if (win == NULL) { if (win == NULL) {
// SDL2: This is slow sometimes... not sure why. // SDL2: This is slow sometimes... not sure why.
if (sdl.CreateWindowAndRenderer(cvstat.winwidth, idealh, flags, &win, &renderer) == 0) { if (sdl.CreateWindowAndRenderer(cvstat.winwidth, idealh, flags, &win, &renderer) == 0) {
sdl.RenderClear(renderer); sdl.RenderClear(renderer);
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.scrnwidth, cvstat.scrnheight); newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.winwidth, idealh);
if (texture) if (texture)
sdl.DestroyTexture(texture); sdl.DestroyTexture(texture);
...@@ -582,9 +587,9 @@ static void setup_surfaces_locked(void) ...@@ -582,9 +587,9 @@ static void setup_surfaces_locked(void)
} }
} }
else { else {
sdl.SetWindowMinimumSize(win, cvstat.scrnwidth, idealh); sdl.SetWindowMinimumSize(win, cvstat.scrnwidth, idealmh);
sdl.SetWindowSize(win, cvstat.winwidth, idealh); sdl.SetWindowSize(win, cvstat.winwidth, idealh);
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.scrnwidth, cvstat.scrnheight); newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.winwidth, idealh);
sdl.RenderClear(renderer); sdl.RenderClear(renderer);
if (texture) if (texture)
sdl.DestroyTexture(texture); sdl.DestroyTexture(texture);
...@@ -969,16 +974,23 @@ void sdl_video_event_thread(void *data) ...@@ -969,16 +974,23 @@ void sdl_video_event_thread(void *data)
const char *newh; const char *newh;
pthread_mutex_lock(&vstatlock); pthread_mutex_lock(&vstatlock);
if ((ev.window.data1 % cvstat.scrnwidth) || (ev.window.data2 % cvstat.scrnheight)) pthread_mutex_lock(&win_mutex);
if ((ev.window.data1 % cvstat.scrnwidth) && (ev.window.data2 % cvstat.scrnheight)) {
newh = "2"; newh = "2";
else internal_scaling = false;
}
else {
newh = "0"; newh = "0";
pthread_mutex_lock(&win_mutex); internal_scaling = true;
}
sdl.GetWindowSize(win, &cvstat.winwidth, &cvstat.winheight); sdl.GetWindowSize(win, &cvstat.winwidth, &cvstat.winheight);
if (strcmp(newh, sdl.GetHint(SDL_HINT_RENDER_SCALE_QUALITY))) { if (strcmp(newh, sdl.GetHint(SDL_HINT_RENDER_SCALE_QUALITY))) {
SDL_Texture *newtexture; SDL_Texture *newtexture;
sdl.SetHint(SDL_HINT_RENDER_SCALE_QUALITY, newh); sdl.SetHint(SDL_HINT_RENDER_SCALE_QUALITY, newh);
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.scrnwidth, cvstat.scrnheight); if (internal_scaling)
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.winwidth, cvstat.winheight);
else
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.scrnwidth, cvstat.scrnheight);
sdl.RenderClear(renderer); sdl.RenderClear(renderer);
if (texture) if (texture)
sdl.DestroyTexture(texture); sdl.DestroyTexture(texture);
...@@ -1025,43 +1037,78 @@ void sdl_video_event_thread(void *data) ...@@ -1025,43 +1037,78 @@ void sdl_video_event_thread(void *data)
int row; int row;
int tw, th; int tw, th;
src.x = 0; if (internal_scaling) {
src.y = 0; struct graphics_buffer *gb;
src.w = list->rect.width; gb = do_scale(list, cvstat.winwidth / cvstat.scrnwidth, cvstat.winheight / cvstat.scrnheight,
src.h = list->rect.height; (double)cvstat.scale_numerator / cvstat.scale_denominator);
sdl.QueryTexture(texture, NULL, NULL, &tw, &th); src.x = 0;
sdl.LockTexture(texture, &src, &pixels, &pitch); src.y = 0;
if (pitch != list->rect.width * sizeof(list->data[0])) { src.w = gb->w;
// If this happens, we need to copy a row at a time... src.h = gb->h;
for (row = 0; row < list->rect.height && row < th; row++) { sdl.QueryTexture(texture, NULL, NULL, &tw, &th);
if (pitch < list->rect.width * sizeof(list->data[0])) sdl.LockTexture(texture, &src, &pixels, &pitch);
memcpy(pixels, &list->data[list->rect.width * row], pitch); if (pitch != gb->w * sizeof(gb->data[0])) {
else // If this happens, we need to copy a row at a time...
memcpy(pixels, &list->data[list->rect.width * row], list->rect.width * sizeof(list->data[0])); for (row = 0; row < gb->h && row < th; row++) {
pixels = (void *)((char*)pixels + pitch); if (pitch < gb->w * sizeof(gb->data[0]))
memcpy(pixels, &gb->data[gb->w * row], pitch);
else
memcpy(pixels, &gb->data[gb->w * row], gb->w * sizeof(gb->data[0]));
pixels = (void *)((char*)pixels + pitch);
}
} }
else {
int ch = gb->h;
if (ch > th)
ch = th;
memcpy(pixels, gb->data, gb->w * ch * sizeof(gb->data[0]));
}
sdl.UnlockTexture(texture);
dst.x = 0;
dst.y = 0;
dst.w = gb->w;
dst.h = gb->h;
release_buffer(gb);
} }
else { else {
int ch = list->rect.height; src.x = 0;
if (ch > th) src.y = 0;
ch = th; src.w = list->rect.width;
memcpy(pixels, list->data, list->rect.width * ch * sizeof(list->data[0])); src.h = list->rect.height;
} sdl.QueryTexture(texture, NULL, NULL, &tw, &th);
sdl.UnlockTexture(texture); sdl.LockTexture(texture, &src, &pixels, &pitch);
dst.x = 0; if (pitch != list->rect.width * sizeof(list->data[0])) {
dst.y = 0; // If this happens, we need to copy a row at a time...
dst.w = cvstat.winwidth; for (row = 0; row < list->rect.height && row < th; row++) {
dst.h = cvstat.winheight; if (pitch < list->rect.width * sizeof(list->data[0]))
// Get correct aspect ratio for dst... memcpy(pixels, &list->data[list->rect.width * row], pitch);
idealw = roundl((long double)dst.h * cvstat.scale_numerator / cvstat.scale_denominator * cvstat.scrnwidth / cvstat.scrnheight); else
idealh = roundl((long double)dst.w * cvstat.scale_denominator / cvstat.scale_numerator * cvstat.scrnheight / cvstat.scrnwidth); memcpy(pixels, &list->data[list->rect.width * row], list->rect.width * sizeof(list->data[0]));
if (idealw < cvstat.winwidth) { pixels = (void *)((char*)pixels + pitch);
dst.x = (cvstat.winwidth - idealw) / 2; }
dst.w = idealw; }
} else {
else if(idealh < cvstat.winheight) { int ch = list->rect.height;
dst.y = (cvstat.winheight - idealh) / 2; if (ch > th)
dst.h = idealh; ch = th;
memcpy(pixels, list->data, list->rect.width * ch * sizeof(list->data[0]));
}
sdl.UnlockTexture(texture);
dst.x = 0;
dst.y = 0;
dst.w = cvstat.winwidth;
dst.h = cvstat.winheight;
// Get correct aspect ratio for dst...
idealw = roundl((long double)dst.h * cvstat.scale_numerator / cvstat.scale_denominator * cvstat.scrnwidth / cvstat.scrnheight);
idealh = roundl((long double)dst.w * cvstat.scale_denominator / cvstat.scale_numerator * cvstat.scrnheight / cvstat.scrnwidth);
if (idealw < cvstat.winwidth) {
dst.x = (cvstat.winwidth - idealw) / 2;
dst.w = idealw;
}
else if(idealh < cvstat.winheight) {
dst.y = (cvstat.winheight - idealh) / 2;
dst.h = idealh;
}
} }
sdl.RenderCopy(renderer, texture, &src, &dst); sdl.RenderCopy(renderer, texture, &src, &dst);
} }
......
...@@ -1816,7 +1816,7 @@ int main(int argc, char **argv) ...@@ -1816,7 +1816,7 @@ int main(int argc, char **argv)
// Save changed settings // Save changed settings
gettextinfo(&txtinfo); gettextinfo(&txtinfo);
// Only save window info if we're in the startup mode... // Only save window info if we're in the startup mode...
if (txtinfo.currmode == settings.startup_mode || (settings.startup_mode == SCREEN_MODE_CURRENT && txtinfo.currmode == C80)) { if (txtinfo.currmode == screen_to_ciolib(settings.startup_mode) || (settings.startup_mode == SCREEN_MODE_CURRENT && txtinfo.currmode == C80)) {
ww = wh = sf = -1; ww = wh = sf = -1;
get_window_info(&ww, &wh, NULL, NULL); get_window_info(&ww, &wh, NULL, NULL);
sf = getscaling(); sf = getscaling();
......