1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-26 14:38:30 +02:00
VVVVVV/desktop_version/src/Screen.cpp
Misa 5c7e869ee7 Work around SDL2 bug where VSync hint only applies on renderer creation
Ugh, this is terrible and stupid and I hate myself for it.

Anyway, since the SDL2 VSync hint only applies when the renderer is
created, we have to re-create the renderer whenever VSync is toggled.
However, this also means we need to re-create m_screenTexture as well,
AND call ResizeScreen() after that or else the letterbox/integer modes
won't be applied.

Unfortunately, this means that in main(), gameScreen.init() will create
a renderer only to be destroyed later by graphics.processVsync().
There's not much we can do about this. Fixing this would require putting
graphics.processVsync() before gameScreen.init(). However, in order to
know whether the user has VSync set, we would have to call
game.loadstats() first, but wait, we can't, because game.loadstats()
mutates gameScreen! Gahhhhhh!!!!

@leo60228 suggested to fix that problem (
https://github.com/TerryCavanagh/VVVVVV/pull/220#issuecomment-624217939
) by adding NULL checks to game.loadstats() and then calling it twice,
but then you're trading wastefully creating a renderer only to be
destroyed, for wastefully opening and parsing unlock.vvv twice instead
of once. In either case, you're doing something twice and wasting work.
2020-06-19 17:44:53 -04:00

233 lines
4.5 KiB
C++

#include "Screen.h"
#include "FileSystemUtils.h"
#include "GraphicsUtil.h"
#include <stdlib.h>
// Used to create the window icon
extern "C"
{
extern unsigned lodepng_decode24(
unsigned char** out,
unsigned* w,
unsigned* h,
const unsigned char* in,
size_t insize
);
}
void Screen::init()
{
m_window = NULL;
m_renderer = NULL;
m_screenTexture = NULL;
m_screen = NULL;
isWindowed = true;
stretchMode = 0;
isFiltered = false;
filterSubrect.x = 1;
filterSubrect.y = 1;
filterSubrect.w = 318;
filterSubrect.h = 238;
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
// Uncomment this next line when you need to debug -flibit
// SDL_SetHintWithPriority(SDL_HINT_RENDER_DRIVER, "software", SDL_HINT_OVERRIDE);
// FIXME: m_renderer is also created in Graphics::processVsync()!
SDL_CreateWindowAndRenderer(
640,
480,
SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE,
&m_window,
&m_renderer
);
SDL_SetWindowTitle(m_window, "VVVVVV");
unsigned char *fileIn = NULL;
size_t length = 0;
unsigned char *data;
unsigned int width, height;
FILESYSTEM_loadFileToMemory("VVVVVV.png", &fileIn, &length);
lodepng_decode24(&data, &width, &height, fileIn, length);
FILESYSTEM_freeMemory(&fileIn);
SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(
data,
width,
height,
24,
width * 3,
0x000000FF,
0x0000FF00,
0x00FF0000,
0x00000000
);
SDL_SetWindowIcon(m_window, icon);
SDL_FreeSurface(icon);
free(data);
// FIXME: This surface should be the actual backbuffer! -flibit
m_screen = SDL_CreateRGBSurface(
0,
320,
240,
32,
0x00FF0000,
0x0000FF00,
0x000000FF,
0xFF000000
);
// ALSO FIXME: This SDL_CreateTexture() is duplicated in Graphics::processVsync()!
m_screenTexture = SDL_CreateTexture(
m_renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
320,
240
);
badSignalEffect = false;
}
void Screen::ResizeScreen(int x, int y)
{
static int resX = 320;
static int resY = 240;
if (x != -1 && y != -1)
{
// This is a user resize!
resX = x;
resY = y;
}
if(!isWindowed)
{
int result = SDL_SetWindowFullscreen(m_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
if (result != 0)
{
printf("Error: could not set the game to fullscreen mode: %s\n", SDL_GetError());
return;
}
}
else
{
int result = SDL_SetWindowFullscreen(m_window, 0);
if (result != 0)
{
printf("Error: could not set the game to windowed mode: %s\n", 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 (stretchMode == 1)
{
int winX, winY;
SDL_GetWindowSize(m_window, &winX, &winY);
int result = SDL_RenderSetLogicalSize(m_renderer, winX, winY);
if (result != 0)
{
printf("Error: could not set logical size: %s\n", SDL_GetError());
return;
}
result = SDL_RenderSetIntegerScale(m_renderer, SDL_FALSE);
if (result != 0)
{
printf("Error: could not set scale: %s\n", SDL_GetError());
return;
}
}
else
{
SDL_RenderSetLogicalSize(m_renderer, 320, 240);
int result = SDL_RenderSetIntegerScale(m_renderer, (SDL_bool) (stretchMode == 2));
if (result != 0)
{
printf("Error: could not set scale: %s\n", SDL_GetError());
return;
}
}
SDL_ShowWindow(m_window);
}
void Screen::GetWindowSize(int* x, int* y)
{
SDL_GetWindowSize(m_window, x, y);
}
void Screen::UpdateScreen(SDL_Surface* buffer, SDL_Rect* rect )
{
if((buffer == NULL) && (m_screen == NULL) )
{
return;
}
if(badSignalEffect)
{
buffer = ApplyFilter(buffer);
}
FillRect(m_screen, 0x000);
BlitSurfaceStandard(buffer,NULL,m_screen,rect);
if(badSignalEffect)
{
SDL_FreeSurface(buffer);
}
}
const SDL_PixelFormat* Screen::GetFormat()
{
return m_screen->format;
}
void Screen::FlipScreen()
{
SDL_UpdateTexture(
m_screenTexture,
NULL,
m_screen->pixels,
m_screen->pitch
);
SDL_RenderCopy(
m_renderer,
m_screenTexture,
isFiltered ? &filterSubrect : NULL,
NULL
);
SDL_RenderPresent(m_renderer);
SDL_RenderClear(m_renderer);
SDL_FillRect(m_screen, NULL, 0x00000000);
}
void Screen::toggleFullScreen()
{
isWindowed = !isWindowed;
ResizeScreen(-1, -1);
}
void Screen::toggleStretchMode()
{
stretchMode = (stretchMode + 1) % 3;
ResizeScreen(-1, -1);
}
void Screen::toggleLinearFilter()
{
isFiltered = !isFiltered;
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, isFiltered ? "linear" : "nearest");
SDL_DestroyTexture(m_screenTexture);
m_screenTexture = SDL_CreateTexture(
m_renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
320,
240
);
}