mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-06-30 00:18:30 +02:00
5c7e869ee7
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.
233 lines
4.5 KiB
C++
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
|
|
);
|
|
}
|