271 lines
7.5 KiB
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;
|
|
}
|
|
}
|