int h = g_menubg_src_h ? g_menubg_src_h : g_screen_height;
int pp = g_menubg_src_pp ? g_menubg_src_pp : g_screen_ppitch;
short *dst;
- int x, y;
if (from_screen) {
src = g_screen_ptr;
if (!no_scale && g_menuscreen_w / w >= 2 && g_menuscreen_h / h >= 2)
{
int xf = g_menuscreen_w / w, yf = g_menuscreen_h / h;
- int f = no_scale ? 1 : xf < yf ? xf : yf;
- int xs = f * w, ys = f * h;
- unsigned short t;
- int i, j, k, l;
+ int f = no_scale ? 1 : xf < yf ? xf : yf, xs = f * w, ys = f * h;
+ int x = (g_menuscreen_w - xs)/2, y = (g_menuscreen_h - ys)/2;
+ uint16_t *p = (uint16_t *)g_menubg_ptr;
+ uint16_t *q = (uint16_t *)src;
- x = (g_menuscreen_w - xs)/2, y = (g_menuscreen_h - ys)/2;
- dst = (short *)g_menubg_ptr + y * g_menuscreen_w + x;
+ int i, j, k, l;
+ p += y * g_menuscreen_pp + x;
for (i = 0; i < h; i++) {
- for (j = 0; j < w; j++, src++) {
- t = (PXMASKH(*src,1)>>1) - (PXMASKH(*src,3)>>3);
+ for (j = 0; j < w; j++, q++) {
+ uint16_t t = (PXMASKH(*q,1)>>1) - (PXMASKH(*q,3)>>3);
for (l = 0; l < f; l++)
- *dst++ = t;
+ *p++ = t;
}
- src += pp - w;
- dst += g_menuscreen_w - xs;
+ p += g_menuscreen_pp - xs;
+ q += pp - w;
for (k = 1; k < f; k++) {
- memcpy(dst, dst-g_menuscreen_w, g_menuscreen_w*2);
- dst += g_menuscreen_w;
+ memcpy(p, p-g_menuscreen_pp, g_menuscreen_w*2);
+ p += g_menuscreen_pp;
}
}
return;
}
}
+void copy_intscale(void *dst, int w, int h, int pp, void *src, int sw, int sh, int spp)
+{
+ int xf = w / sw, yf = h / sh;
+ int f = xf < yf ? xf : yf, xs = f * sw, ys = f * sh;
+ int x = (w - xs)/2, y = (h - ys)/2;
+ uint16_t *p = (uint16_t *)dst;
+ uint16_t *q = (uint16_t *)src;
+
+ // copy 16bit image with scaling by an integer factor
+ int i, j, k, l;
+ p += y * pp + x;
+ for (i = 0; i < sh; i++) {
+ for (j = 0; j < sw; j++, q++)
+ for (l = 0; l < f; l++)
+ *p++ = *q;
+ p += pp - xs;
+ q += spp - sw;
+ for (k = 1; k < f; k++) {
+ memcpy(p, p-pp, w*2);
+ p += pp;
+ }
+ }
+}
+
static int clear_buf_cnt, clear_stat_cnt;
static void resize_buffers(void)
void plat_video_set_size(int w, int h)
{
+ if ((plat_sdl_overlay || plat_sdl_gl_active) &&
+ (w != g_screen_width || h != g_screen_height)) {
+ // scale to the window, but mind aspect ratio (scaled to 4:3)
+ if (g_menuscreen_w * /*h*/w*3/4 >= g_menuscreen_h * w)
+ w = (w * 3 * g_menuscreen_w/g_menuscreen_h)/4 & ~1;
+ else
+ h = (h * 4 * g_menuscreen_h/g_menuscreen_w)/3 & ~1;
+ }
+
if (area.w != w || area.h != h) {
area = (struct area) { w, h };
- if (plat_sdl_change_video_mode(w, h, 0) < 0) {
- // failed, revert to original resolution
- area = (struct area) { g_screen_width,g_screen_height };
- plat_sdl_change_video_mode(g_screen_width, g_screen_height, 0);
+
+ if (plat_sdl_overlay || plat_sdl_gl_active || !plat_sdl_is_windowed()) {
+ // create surface for overlays, or try using a hw scaler
+ if (plat_sdl_change_video_mode(w, h, 0) < 0) {
+ // failed, revert to original resolution
+ area = (struct area) { g_screen_width,g_screen_height };
+ plat_sdl_change_video_mode(g_screen_width, g_screen_height, 0);
+ }
}
- if (!plat_sdl_overlay && !plat_sdl_gl_active) {
+ if (plat_sdl_overlay || plat_sdl_gl_active ||
+ plat_sdl_screen->w >= 320*2 || plat_sdl_screen->h >= 240*2) {
+ // use shadow buffer for overlays and sw integer scaling
+ g_screen_width = area.w;
+ g_screen_height = area.h;
+ g_screen_ppitch = area.w;
+ g_screen_ptr = shadow_fb;
+ } else {
+ // unscaled SDL window buffer can be used directly
g_screen_width = plat_sdl_screen->w;
g_screen_height = plat_sdl_screen->h;
g_screen_ppitch = plat_sdl_screen->pitch/2;
g_screen_ptr = plat_sdl_screen->pixels;
- } else {
- g_screen_width = w;
- g_screen_height = h;
- g_screen_ppitch = w;
}
}
}
gl_flip(shadow_fb, g_screen_ppitch, g_screen_height);
}
else {
- if (SDL_MUSTLOCK(plat_sdl_screen)) {
+ int copy = g_screen_ptr != plat_sdl_screen->pixels;
+ if (copy)
+ copy_intscale(plat_sdl_screen->pixels, plat_sdl_screen->w,
+ plat_sdl_screen->h, plat_sdl_screen->pitch/2,
+ shadow_fb, area.w, area.h, area.w);
+
+ if (SDL_MUSTLOCK(plat_sdl_screen))
SDL_UnlockSurface(plat_sdl_screen);
- SDL_Flip(plat_sdl_screen);
+ SDL_Flip(plat_sdl_screen);
+ if (SDL_MUSTLOCK(plat_sdl_screen))
SDL_LockSurface(plat_sdl_screen);
- } else
- SDL_Flip(plat_sdl_screen);
- g_screen_ppitch = plat_sdl_screen->pitch/2;
- g_screen_ptr = plat_sdl_screen->pixels;
- plat_video_set_buffer(g_screen_ptr);
+
+ if (!copy) {
+ g_screen_ppitch = plat_sdl_screen->pitch/2;
+ g_screen_ptr = plat_sdl_screen->pixels;
+ plat_video_set_buffer(g_screen_ptr);
+ }
+
if (clear_buf_cnt) {
memset(g_screen_ptr, 0, plat_sdl_screen->pitch*plat_sdl_screen->h);
clear_buf_cnt--;
void plat_video_clear_buffers(void)
{
- if (plat_sdl_overlay || plat_sdl_gl_active)
+ if (plat_sdl_overlay || plat_sdl_gl_active ||
+ plat_sdl_screen->w >= 320*2 || plat_sdl_screen->h >= 240*2)
memset(shadow_fb, 0, g_menuscreen_w * g_menuscreen_h * 2);
else {
memset(g_screen_ptr, 0, plat_sdl_screen->pitch*plat_sdl_screen->h);
}
g_screen_ppitch = g_screen_width;
g_screen_ptr = shadow_fb;
+ plat_video_set_size(g_screen_width, g_screen_height);
}
else {
- g_screen_width = plat_sdl_screen->w;
- g_screen_height = plat_sdl_screen->h;
- g_screen_ppitch = plat_sdl_screen->pitch/2;
+ if (plat_sdl_is_windowed() &&
+ (plat_sdl_screen->w >= 320*2 || plat_sdl_screen->h >= 240*2)) {
+ // shadow buffer for integer scaling
+ g_screen_width = 320;
+ g_screen_height = 240;
+ g_screen_ppitch = 320;
+ g_screen_ptr = shadow_fb;
+ } else {
+ // no scaling needed, use screen buffer directly
+ g_screen_width = plat_sdl_screen->w;
+ g_screen_height = plat_sdl_screen->h;
+ g_screen_ppitch = plat_sdl_screen->pitch/2;
+ g_screen_ptr = plat_sdl_screen->pixels;
+ }
+ plat_video_set_size(g_screen_width, g_screen_height);
+
if (SDL_MUSTLOCK(plat_sdl_screen))
SDL_LockSurface(plat_sdl_screen);
- g_screen_ptr = plat_sdl_screen->pixels;
}
- plat_video_set_size(g_screen_width, g_screen_height);
plat_video_set_buffer(g_screen_ptr);
}
static void plat_sdl_resize(int w, int h)
{
// take over new settings
- if (plat_sdl_screen->w != area.w || plat_sdl_screen->h != area.h) {
#if defined(__OPENDINGUX__)
- if (currentConfig.vscaling != EOPT_SCALE_HW &&
- plat_sdl_screen->w == 320 &&
- plat_sdl_screen->h == 480) {
- g_menuscreen_h = 240;
- g_menuscreen_w = 320;
-
- } else
+ if (currentConfig.vscaling != EOPT_SCALE_HW &&
+ plat_sdl_screen->w == 320 && plat_sdl_screen->h == 480) {
+ g_menuscreen_h = 240;
+ g_menuscreen_w = 320;
+ } else
#endif
- {
- g_menuscreen_h = plat_sdl_screen->h;
- g_menuscreen_w = plat_sdl_screen->w;
- }
- resize_buffers();
- rendstatus_old = -1;
+ {
+ g_menuscreen_h = plat_sdl_screen->h;
+ g_menuscreen_w = plat_sdl_screen->w;
}
+ resize_buffers();
+ rendstatus_old = -1;
}
static void plat_sdl_quit(void)