HatariWii/src/resolution.c

271 lines
7.5 KiB
C

/*
Hatari - resolution.c
This file is distributed under the GNU General Public License, version 2
or at your option any later version. Read the file gpl.txt for details.
SDL resolution limitation and selection routines.
*/
const char Resolution_fileid[] = "Hatari resolution.c : " __DATE__ " " __TIME__;
#include <SDL.h>
#include "main.h"
#include "configuration.h"
#include "resolution.h"
#include "statusbar.h"
#include "screen.h"
#define DEBUG 0
#if DEBUG
# define DEBUGPRINT(x) printf x
#else
#ifdef GEKKO
# define DEBUGPRINT(x) //
#include "log.h"
#else
# define DEBUGPRINT(x)
#endif
#endif
static int DesktopWidth, DesktopHeight;
/**
* Initilizes resolution settings (gets current desktop
* resolution, sets max Falcon/TT Videl zooming resolution).
*/
void Resolution_Init(void)
{
#if WITH_SDL2
SDL_DisplayMode dm;
if (SDL_GetDesktopDisplayMode(0, &dm) == 0)
{
DesktopWidth = dm.w;
DesktopHeight = dm.h;
}
else
{
#ifndef GEKKO
fprintf(stderr, "SDL_GetDesktopDisplayMode failed: %s", SDL_GetError());
#else
Log_Printf(LOG_ERROR, "SDL_GetDesktopDisplayMode failed: %s", SDL_GetError());
#endif
DesktopWidth = 2*NUM_VISIBLE_LINE_PIXELS;
DesktopHeight = 2*NUM_VISIBLE_LINES+STATUSBAR_MAX_HEIGHT;
}
#else
/* Needs to be called after SDL video and configuration
* initialization, but before Hatari Screen init is called
* for the first time!
*/
const SDL_VideoInfo* info = SDL_GetVideoInfo();
if (info->current_w >= 640 && info->current_h >= 400) {
DesktopWidth = info->current_w;
DesktopHeight = info->current_h;
} else {
/* target 800x600 screen with statusbar out of screen */
DesktopWidth = 2*NUM_VISIBLE_LINE_PIXELS;
DesktopHeight = 2*NUM_VISIBLE_LINES+STATUSBAR_MAX_HEIGHT;
#ifndef GEKKO
fprintf(stderr, "WARNING: invalid desktop size %dx%d, defaulting to %dx%d!\n",
info->current_w, info->current_h, DesktopWidth, DesktopHeight);
#else
Log_Printf(LOG_ERROR, "WARNING: invalid desktop size %dx%d, defaulting to %dx%d!\n",
info->current_w, info->current_h, DesktopWidth, DesktopHeight);
#endif
}
#endif
/* if user hasn't set own max zoom size, use desktop size */
if (!(ConfigureParams.Screen.nMaxWidth &&
ConfigureParams.Screen.nMaxHeight)) {
ConfigureParams.Screen.nMaxWidth = DesktopWidth;
ConfigureParams.Screen.nMaxHeight = DesktopHeight;
}
DEBUGPRINT(("Desktop resolution: %dx%d\n",DesktopWidth, DesktopHeight));
#ifndef GEKKO
fprintf(stderr, "Configured max Hatari resolution = %dx%d, optimal for ST = %dx%d\n",
ConfigureParams.Screen.nMaxWidth, ConfigureParams.Screen.nMaxHeight,
2*NUM_VISIBLE_LINE_PIXELS, 2*NUM_VISIBLE_LINES+STATUSBAR_MAX_HEIGHT);
#else
Log_Printf(LOG_ERROR, "Configured max Hatari resolution = %dx%d, optimal for ST = %dx%d\n",
ConfigureParams.Screen.nMaxWidth, ConfigureParams.Screen.nMaxHeight,
2*NUM_VISIBLE_LINE_PIXELS, 2*NUM_VISIBLE_LINES+STATUSBAR_MAX_HEIGHT);
#endif
}
/**
* Get current desktop resolution
*/
void Resolution_GetDesktopSize(int *width, int *height)
{
DEBUGPRINT(("resolution: limit to desktop size\n"));
*width = DesktopWidth;
*height = DesktopHeight;
}
/**
* Get max resolution
*/
static void Resolution_GetMaxSize(int *width, int *height)
{
DEBUGPRINT(("resolution: force to specified max size\n"));
*width = ConfigureParams.Screen.nMaxWidth;
*height = ConfigureParams.Screen.nMaxHeight;
}
/**
* Select best resolution from given SDL video modes.
* - If width and height are given, select the smallest mode larger
* or equal to requested size
* - Otherwise select the largest available mode
* return true for success and false if no matching mode was found.
*/
static inline bool Resolution_Select(SDL_Rect **modes, int *width, int *height)
{
#define TOO_LARGE 0x7fff
int i, bestw, besth;
if (!(*width && *height)) {
/* search the largest mode (prefer wider ones) */
for (i = 0; modes[i]; i++) {
if ((modes[i]->w > *width) && (modes[i]->h >= *height)) {
*width = modes[i]->w;
*height = modes[i]->h;
}
}
DEBUGPRINT(("resolution: largest found video mode: %dx%d\n",*width,*height));
return true;
}
/* Search the smallest mode larger or equal to requested size */
bestw = TOO_LARGE;
besth = TOO_LARGE;
for (i = 0; modes[i]; i++) {
if ((modes[i]->w >= *width) && (modes[i]->h >= *height)) {
if ((modes[i]->w < bestw) || (modes[i]->h < besth)) {
bestw = modes[i]->w;
besth = modes[i]->h;
}
}
}
if (bestw == TOO_LARGE || besth == TOO_LARGE) {
return false;
}
*width = bestw;
*height = besth;
DEBUGPRINT(("resolution: video mode found: %dx%d\n",*width,*height));
return true;
#undef TOO_LARGE
}
/**
* Search video mode size that best suits the given width/height/bpp
* constraints and set them into given arguments. With zeroed arguments,
* set largest video mode.
*
* Return true if mode is forced (shouldn't be further limited).
*/
bool Resolution_Search(int *width, int *height, int *bpp, bool keep)
{
#if !WITH_SDL2
SDL_Rect **modes;
SDL_PixelFormat pixelformat;
Uint32 modeflags = 0 /*SDL_HWSURFACE | SDL_HWPALETTE*/;
#endif
/* Search in available modes the best suited */
DEBUGPRINT(("resolution: video mode asked: %dx%dx%d (%s)\n",
*width, *height, *bpp, bInFullScreen ? "fullscreen" : "windowed"));
if (bInFullScreen)
{
/* resolution change not allowed? */
if (keep)
{
Resolution_GetDesktopSize(width, height);
return true;
}
}
if (ConfigureParams.Screen.bForceMax)
{
/* force given max size */
Resolution_GetMaxSize(width, height);
return true;
}
#if !WITH_SDL2
if (bInFullScreen)
modeflags |= SDL_FULLSCREEN;
/*--- Search a video mode with asked bpp ---*/
if (*bpp != 0) {
pixelformat.BitsPerPixel = *bpp;
modes = SDL_ListModes(&pixelformat, modeflags);
if ((modes != (SDL_Rect **) 0) && (modes != (SDL_Rect **) -1)) {
DEBUGPRINT(("resolution: searching a good video mode (given bpp)\n"));
if (Resolution_Select(modes, width, height)) {
DEBUGPRINT(("resolution: video mode selected: %dx%dx%d\n",
*width, *height, *bpp));
return false;
}
}
}
/*--- Search a video mode with any bpp ---*/
modes = SDL_ListModes(NULL, modeflags);
if ((modes != (SDL_Rect **) 0) && (modes != (SDL_Rect **) -1)) {
DEBUGPRINT(("resolution: searching a good video mode (any bpp)\n"));
if (Resolution_Select(modes, width, height)) {
DEBUGPRINT(("resolution: video mode selected: %dx%dx%d\n",
*width, *height, *bpp));
return false;
}
}
if (modes == (SDL_Rect **) 0) {
#ifndef GEKKO
fprintf(stderr, "WARNING: No suitable video modes available!\n");
#else
Log_Printf(LOG_ERROR, "WARNING: No suitable video modes available!\n");
#endif
}
if (modes == (SDL_Rect **) -1) {
/* Any mode available */
DEBUGPRINT(("resolution: All resolutions available.\n"));
}
#endif
DEBUGPRINT(("resolution: video mode selected: %dx%dx%d\n",
*width, *height, *bpp));
return false;
}
/**
* Set given width & height arguments to maximum size allowed in the
* configuration, or if that's too large for the requested bit depth,
* to the largest available video mode size.
*/
void Resolution_GetLimits(int *width, int *height, int *bpp, bool keep)
{
*width = *height = 0;
/* constrain max size to what HW/SDL offers */
DEBUGPRINT(("resolution: request limits for: %dx%dx%d\n", *width, *height, *bpp));
/* forced resolution? */
if (Resolution_Search(width, height, bpp, keep)) {
return;
}
if (!(*width && *height) ||
(ConfigureParams.Screen.nMaxWidth < *width &&
ConfigureParams.Screen.nMaxHeight < *height)) {
DEBUGPRINT(("resolution: limit to user configured max\n"));
*width = ConfigureParams.Screen.nMaxWidth;
*height = ConfigureParams.Screen.nMaxHeight;
}
}