diff --git a/configure.ac b/configure.ac index 4d8dd355..7837b64b 100644 --- a/configure.ac +++ b/configure.ac @@ -34,7 +34,7 @@ then CFLAGS="-O$OPT_LEVEL -g $WARNINGS $orig_CFLAGS" fi -PKG_CHECK_MODULES(SDL, [sdl2 >= 2.0.0]) +PKG_CHECK_MODULES(SDL, [sdl2 >= 2.0.1]) PKG_CHECK_MODULES(SDLMIXER, [SDL2_mixer >= 2.0.0]) PKG_CHECK_MODULES(SDLNET, [SDL2_net >= 2.0.0]) diff --git a/pkg/osx/Info.plist.in b/pkg/osx/Info.plist.in index a648ed8b..b838d757 100644 --- a/pkg/osx/Info.plist.in +++ b/pkg/osx/Info.plist.in @@ -24,6 +24,8 @@ @PACKAGE_VERSION@ CFBundleVersion @PACKAGE_VERSION@ + NSHighResolutionCapable + true NSPrincipalClass NSApplication NSMainNibFile diff --git a/textscreen/txt_sdl.c b/textscreen/txt_sdl.c index e0938ad6..5fad0c7e 100644 --- a/textscreen/txt_sdl.c +++ b/textscreen/txt_sdl.c @@ -51,6 +51,7 @@ typedef struct SDL_Window *TXT_SDLWindow; static SDL_Surface *screenbuffer; static unsigned char *screendata; +static SDL_Renderer *renderer; static int key_mapping = 1; static TxtSDLEventCallbackFunc event_callback; @@ -59,8 +60,11 @@ static void *event_callback_data; static int modifier_state[TXT_NUM_MODIFIERS]; // Font we are using: +static const txt_font_t *font; -static txt_font_t *font; +// Dummy "font" that means to try highdpi rendering, or fallback to +// main_font otherwise. +static const txt_font_t highdpi_font = { NULL, 8, 16 }; //#define TANGO @@ -142,24 +146,28 @@ static int Win32_UseLargeFont(void) #endif -static txt_font_t *FontForName(char *name) +static const txt_font_t *FontForName(char *name) { - if (!strcmp(name, "small")) + int i; + struct { + char *name; + const txt_font_t *font; + } fonts[] = { + { "small", &small_font }, + { "normal", &main_font }, + { "large", &large_font }, + { "normal-highdpi", &highdpi_font }, + { NULL }, + }; + + for (i = 0; fonts[i].name != NULL; ++i) { - return &small_font; - } - else if (!strcmp(name, "normal")) - { - return &main_font; - } - else if (!strcmp(name, "large")) - { - return &large_font; - } - else - { - return NULL; + if (!strcmp(fonts[i].name, name)) + { + return fonts[i].font; + } } + return NULL; } // @@ -175,9 +183,7 @@ static void ChooseFont(void) char *env; // Allow normal selection to be overridden from an environment variable: - env = getenv("TEXTSCREEN_FONT"); - if (env != NULL) { font = FontForName(env); @@ -191,10 +197,9 @@ static void ChooseFont(void) // Get desktop resolution. // If in doubt and we can't get a list, always prefer to // fall back to the normal font: - if (!SDL_GetCurrentDisplayMode(0, &desktop_info)) { - font = &main_font; + font = &highdpi_font; return; } @@ -223,7 +228,10 @@ static void ChooseFont(void) // and using large_font if the result is >= 2. else { - font = &main_font; + // highdpi_font usually means main_font (the normal resolution + // version), but actually means "set the HIGHDPI flag and try + // to use large_font if we initialize successfully". + font = &highdpi_font; } } @@ -235,6 +243,9 @@ static void ChooseFont(void) int TXT_Init(void) { + int window_w, window_h; + int flags = 0; + if (SDL_Init(SDL_INIT_VIDEO) < 0) { return 0; @@ -242,17 +253,47 @@ int TXT_Init(void) ChooseFont(); - // Always create the screen at the native screen depth (bpp=0); - // some systems nowadays don't seem to support true 8-bit palettized - // screen modes very well and we end up with screwed up colors. + window_w = TXT_SCREEN_W * font->w; + window_h = TXT_SCREEN_H * font->h; + + // If highdpi_font is selected, try to initialize high dpi rendering. + if (font == &highdpi_font) + { + flags |= SDL_WINDOW_ALLOW_HIGHDPI; + } + TXT_SDLWindow = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - TXT_SCREEN_W * font->w, TXT_SCREEN_H * font->h, - 0); + window_w, window_h, flags); if (TXT_SDLWindow == NULL) return 0; + renderer = SDL_CreateRenderer(TXT_SDLWindow, -1, 0); + + // Special handling for OS X retina display. If we successfully set the + // highdpi flag, check the output size for the screen renderer. If we get + // the 2x doubled size we expect from a retina display, use the large font + // for drawing the screen. + if ((SDL_GetWindowFlags(TXT_SDLWindow) & SDL_WINDOW_ALLOW_HIGHDPI) != 0) + { + int render_w, render_h; + + if (SDL_GetRendererOutputSize(renderer, &render_w, &render_h) == 0 + && render_w == TXT_SCREEN_W * large_font.w + && render_h == TXT_SCREEN_H * large_font.h) + { + font = &large_font; + } + } + + // Failed to initialize for high dpi (retina display) rendering? If so + // then use the normal resolution font instead. + if (font == &highdpi_font) + { + font = &main_font; + } + // Instead, we draw everything into an intermediate 8-bit surface // the same dimensions as the screen. SDL then takes care of all the // 8->32 bit (or whatever depth) color conversions for us. @@ -380,6 +421,7 @@ static int LimitToRange(int val, int min, int max) void TXT_UpdateScreenArea(int x, int y, int w, int h) { + SDL_Texture *screentx; SDL_Rect rect; int x1, y1; int x_end; @@ -407,9 +449,15 @@ void TXT_UpdateScreenArea(int x, int y, int w, int h) SDL_UnlockSurface(screenbuffer); - SDL_BlitSurface(screenbuffer, &rect, - SDL_GetWindowSurface(TXT_SDLWindow), &rect); - SDL_UpdateWindowSurfaceRects(TXT_SDLWindow, &rect, 1); + // TODO: This is currently creating a new texture every time we render + // the screen; find a more efficient way to do it. + screentx = SDL_CreateTextureFromSurface(renderer, screenbuffer); + + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, screentx, NULL, NULL); + SDL_RenderPresent(renderer); + + SDL_DestroyTexture(screentx); } void TXT_UpdateScreen(void) @@ -419,10 +467,16 @@ void TXT_UpdateScreen(void) void TXT_GetMousePosition(int *x, int *y) { + int window_w, window_h; + SDL_GetMouseState(x, y); - *x /= font->w; - *y /= font->h; + // Translate mouse position from 'pixel' position into character position. + // Note that font->{w,h} are deliberately not used in this calculation, as + // that would break when using highdpi (OS X retina display). + SDL_GetWindowSize(TXT_SDLWindow, &window_w, &window_h); + *x = (*x * TXT_SCREEN_W) / window_w; + *y = (*y * TXT_SCREEN_H) / window_h; } //