mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-09-30 10:17:23 +02:00
7ce4f1173d
If you want your game window to simply be exactly 320x240, or 640x480, or 960x720 etc. then it's really annoying that there's no easy way to do this (to clarify, this is different from integer mode, which controls the size of the game INSIDE the window). The easiest way would be having to close the game, go into unlock.vvv, and edit the window size manually. VCE has a 1x/2x/3x/4x graphics option to solve this, although it does not account for actual monitor size (those 1x/2x/3x/4x modes are all you get, whether or not you have a monitor too small for some of them or too big for any of them to be what you want). I discussed this with flibit, and he said that VCE's approach (if it accounted for monitor size) wouldn't work on high-retina displays or high DPIs, because getting the actual multiplier to account for those monitors is kind of a pain. So the next best thing would be to add an option that resizes to the nearest perfect multiple of 320x240. That way you could simply resize the window and let the game correct any imperfect dimensions automatically.
289 lines
5.6 KiB
C++
289 lines
5.6 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::ResizeToNearestMultiple()
|
|
{
|
|
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 = 240;
|
|
using_width = false;
|
|
}
|
|
else
|
|
{
|
|
// Height is bigger, so it's limited by width. Or we're exactly 4:3 already
|
|
usethisdimension = w;
|
|
usethisratio = 320;
|
|
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(320, 240);
|
|
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)
|
|
{
|
|
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
|
|
);
|
|
}
|