1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-28 15:38:30 +02:00
VVVVVV/desktop_version/src/Screen.cpp
Misa cc61194bed Move SDL_ShowWindow to after assets are loaded
This is a minor optimization to streamline the experience of Ved
playtesting. Previously, the user would have to wait for all the assets
to load when launching playtesting (most of the time, I suspect, is
taken up by loading music from a vvvvvvmusic blob). With this
optimization, however, the game can be launched in the background and
its assets can be loaded, while it blocks on STDIN input. During this
time, the user in Ved will be choosing where to start playtesting. After
Ved provides STDIN input, then the window will be created and appears
instantaneously.

This also fixes a related issue in which providing an invalid
playtesting level name would result in a brief window flash that gets
instantly destroyed. With this, if the level is invalid then no window
is ever shown at all.
2022-06-01 16:42:22 -07:00

378 lines
9.0 KiB
C++

#define GAMESCREEN_DEFINITION
#include "Screen.h"
#include <SDL.h>
#include "Constants.h"
#include "FileSystemUtils.h"
#include "Game.h"
#include "GraphicsUtil.h"
#include "Vlogging.h"
void ScreenSettings_default(struct ScreenSettings* _this)
{
_this->windowWidth = SCREEN_WIDTH_PIXELS;
_this->windowHeight = SCREEN_HEIGHT_PIXELS;
_this->fullscreen = false;
_this->useVsync = true; // Now that uncapped is the default...
_this->scalingMode = SCALING_INTEGER;
_this->linearFilter = false;
_this->badSignal = false;
}
void Screen::init(const struct ScreenSettings* settings)
{
m_window = NULL;
m_renderer = NULL;
m_screenTexture = NULL;
m_screen = NULL;
isWindowed = !settings->fullscreen;
scalingMode = settings->scalingMode;
isFiltered = settings->linearFilter;
vsync = settings->useVsync;
SDL_SetHintWithPriority(
SDL_HINT_RENDER_SCALE_QUALITY,
isFiltered ? "linear" : "nearest",
SDL_HINT_OVERRIDE
);
SDL_SetHintWithPriority(
SDL_HINT_RENDER_VSYNC,
vsync ? "1" : "0",
SDL_HINT_OVERRIDE
);
// Uncomment this next line when you need to debug -flibit
// SDL_SetHintWithPriority(SDL_HINT_RENDER_DRIVER, "software", SDL_HINT_OVERRIDE);
SDL_CreateWindowAndRenderer(
640,
480,
SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI,
&m_window,
&m_renderer
);
SDL_SetWindowTitle(m_window, "VVVVVV");
LoadIcon();
// FIXME: This surface should be the actual backbuffer! -flibit
m_screen = SDL_CreateRGBSurface(
0,
SCREEN_WIDTH_PIXELS,
SCREEN_HEIGHT_PIXELS,
32,
0x00FF0000,
0x0000FF00,
0x000000FF,
0xFF000000
);
m_screenTexture = SDL_CreateTexture(
m_renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
SCREEN_WIDTH_PIXELS,
SCREEN_HEIGHT_PIXELS
);
badSignalEffect = settings->badSignal;
ResizeScreen(settings->windowWidth, settings->windowHeight);
}
void Screen::destroy(void)
{
#define X(CLEANUP, POINTER) \
CLEANUP(POINTER); \
POINTER = NULL;
/* Order matters! */
X(SDL_DestroyTexture, m_screenTexture);
X(SDL_FreeSurface, m_screen);
X(SDL_DestroyRenderer, m_renderer);
X(SDL_DestroyWindow, m_window);
#undef X
}
void Screen::GetSettings(struct ScreenSettings* settings)
{
int width, height;
GetWindowSize(&width, &height);
settings->windowWidth = width;
settings->windowHeight = height;
settings->fullscreen = !isWindowed;
settings->useVsync = vsync;
settings->scalingMode = scalingMode;
settings->linearFilter = isFiltered;
settings->badSignal = badSignalEffect;
}
#ifdef __APPLE__
/* Apple doesn't like icons anymore... */
void Screen::LoadIcon(void)
{
}
#else
SDL_Surface* LoadImage(const char* filename);
void Screen::LoadIcon(void)
{
SDL_Surface* icon = LoadImage("VVVVVV.png");
if (icon == NULL)
{
return;
}
SDL_SetWindowIcon(m_window, icon);
SDL_FreeSurface(icon);
}
#endif /* __APPLE__ */
void Screen::ResizeScreen(int x, int y)
{
static int resX = SCREEN_WIDTH_PIXELS;
static int resY = SCREEN_HEIGHT_PIXELS;
if (x != -1 && y != -1)
{
// This is a user resize!
resX = x;
resY = y;
}
if (!isWindowed || isForcedFullscreen())
{
int result = SDL_SetWindowFullscreen(m_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
if (result != 0)
{
vlog_error("Error: could not set the game to fullscreen mode: %s", SDL_GetError());
return;
}
}
else
{
int result = SDL_SetWindowFullscreen(m_window, 0);
if (result != 0)
{
vlog_error("Error: could not set the game to windowed mode: %s", SDL_GetError());
return;
}
if (x != -1 && y != -1)
{
SDL_SetWindowSize(m_window, resX, resY);
SDL_SetWindowPosition(m_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
}
}
if (scalingMode == SCALING_STRETCH)
{
int winX, winY;
GetWindowSize(&winX, &winY);
int result = SDL_RenderSetLogicalSize(m_renderer, winX, winY);
if (result != 0)
{
vlog_error("Error: could not set logical size: %s", SDL_GetError());
return;
}
result = SDL_RenderSetIntegerScale(m_renderer, SDL_FALSE);
if (result != 0)
{
vlog_error("Error: could not set scale: %s", SDL_GetError());
return;
}
}
else
{
SDL_RenderSetLogicalSize(m_renderer, SCREEN_WIDTH_PIXELS, SCREEN_HEIGHT_PIXELS);
int result = SDL_RenderSetIntegerScale(m_renderer, (SDL_bool) (scalingMode == SCALING_INTEGER));
if (result != 0)
{
vlog_error("Error: could not set scale: %s", SDL_GetError());
return;
}
}
}
void Screen::ResizeToNearestMultiple(void)
{
int w, h;
GetWindowSize(&w, &h);
// Check aspect ratio first
bool using_width;
int usethisdimension, usethisratio;
if ((float) w / (float) h > 4.0 / 3.0)
{
// Width is bigger, so it's limited by height
usethisdimension = h;
usethisratio = SCREEN_HEIGHT_PIXELS;
using_width = false;
}
else
{
// Height is bigger, so it's limited by width. Or we're exactly 4:3 already
usethisdimension = w;
usethisratio = SCREEN_WIDTH_PIXELS;
using_width = true;
}
int floor = (usethisdimension / usethisratio) * usethisratio;
int ceiling = floor + usethisratio;
int final_dimension;
if (usethisdimension - floor < ceiling - usethisdimension)
{
// Floor is nearest
final_dimension = floor;
}
else
{
// Ceiling is nearest. Or we're exactly on a multiple already
final_dimension = ceiling;
}
if (final_dimension == 0)
{
// We're way too small!
ResizeScreen(SCREEN_WIDTH_PIXELS, SCREEN_HEIGHT_PIXELS);
return;
}
if (using_width)
{
ResizeScreen(final_dimension, final_dimension / 4 * 3);
}
else
{
ResizeScreen(final_dimension * 4 / 3, final_dimension);
}
}
void Screen::GetWindowSize(int* x, int* y)
{
if (SDL_GetRendererOutputSize(m_renderer, x, y) != 0)
{
vlog_error("Could not get window size: %s", SDL_GetError());
/* Initialize to safe defaults */
*x = SCREEN_WIDTH_PIXELS;
*y = SCREEN_HEIGHT_PIXELS;
}
}
void Screen::UpdateScreen(SDL_Surface* buffer, SDL_Rect* rect )
{
if((buffer == NULL) && (m_screen == NULL) )
{
return;
}
if(badSignalEffect)
{
buffer = ApplyFilter(buffer);
}
ClearSurface(m_screen);
BlitSurfaceStandard(buffer,NULL,m_screen,rect);
if(badSignalEffect)
{
SDL_FreeSurface(buffer);
}
}
const SDL_PixelFormat* Screen::GetFormat(void)
{
return m_screen->format;
}
void Screen::FlipScreen(const bool flipmode)
{
static const SDL_Rect filterSubrect = {1, 1, 318, 238};
SDL_RendererFlip flip_flags;
if (flipmode)
{
flip_flags = SDL_FLIP_VERTICAL;
}
else
{
flip_flags = SDL_FLIP_NONE;
}
SDL_UpdateTexture(
m_screenTexture,
NULL,
m_screen->pixels,
m_screen->pitch
);
SDL_RenderCopyEx(
m_renderer,
m_screenTexture,
isFiltered ? &filterSubrect : NULL,
NULL,
0.0,
NULL,
flip_flags
);
SDL_RenderPresent(m_renderer);
SDL_RenderClear(m_renderer);
ClearSurface(m_screen);
}
void Screen::toggleFullScreen(void)
{
isWindowed = !isWindowed;
ResizeScreen(-1, -1);
if (game.currentmenuname == Menu::graphicoptions)
{
/* Recreate menu to update "resize to nearest" */
game.createmenu(game.currentmenuname, true);
}
}
void Screen::toggleScalingMode(void)
{
scalingMode = (scalingMode + 1) % NUM_SCALING_MODES;
ResizeScreen(-1, -1);
}
void Screen::toggleLinearFilter(void)
{
isFiltered = !isFiltered;
SDL_SetHintWithPriority(
SDL_HINT_RENDER_SCALE_QUALITY,
isFiltered ? "linear" : "nearest",
SDL_HINT_OVERRIDE
);
SDL_DestroyTexture(m_screenTexture);
m_screenTexture = SDL_CreateTexture(
m_renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
SCREEN_WIDTH_PIXELS,
SCREEN_HEIGHT_PIXELS
);
}
void Screen::toggleVSync(void)
{
vsync = !vsync;
SDL_RenderSetVSync(m_renderer, (int) vsync);
}
/* FIXME: Launching in forced fullscreen then exiting and relaunching in normal
* mode will result in the window having fullscreen size but being windowed. */
bool Screen::isForcedFullscreen(void)
{
/* This is just a check to see if we're on a desktop or tenfoot setup.
* If you're working on a tenfoot-only build, add a def that always
* returns true!
*/
return SDL_GetHintBoolean("SteamTenfoot", SDL_FALSE);
}