Commit Graph

50 Commits

Author SHA1 Message Date
Misa a926ce9851 Replace all free calls with `VVV_free[func]`
This replaces all calls to SDL_free with a new macro, VVV_free, that
nulls the pointer afterwards. This mitigates any use-after-frees and
also completely eliminates double-frees. The same is done for any
function to free specific objects such as SDL_FreeSurface, with the
VVV_freefunc macro.

No exceptions for any of these calls, even if the pointer is discarded
or zeroed afterwards anyway. Better safe than sorry.

This is a macro rather than a function that takes in a
pointer-to-pointer because such a function would have type issues that
require casting and that's just not safe.

Even though SDL_free and other SDL functions already check for NULL, the
macro has a NULL check for other functions that don't. For example,
FAudioVoice_DestroyVoice does not check for NULL.

FILESYSTEM_freeMemory has been axed in favor of VVV_free because it
functionally does the same thing except for `unsigned char*` only.
2022-11-30 22:50:08 -08:00
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
Misa 997363ce56 `GetWindowSize`: Initialize out values if `GetRendererOutput` fails
Issue #870 showed one of the problems that this game has, namely that it
only sometimes checks SDL return values, and did not do so in this case.
Part of the cause of #870 is that Screen::GetWindowSize does not check
the return value of SDL_GetRendererOutputSize, so when that function
fails (as in the case where m_renderer is NULL and does not exist), it
does not initialize the out values, so it ends up writing uninitialized
values to the save files.

We need to make sure every function's return value is checked, not just
SDL functions, but that will have to be done later.
2022-03-12 16:49:55 -08:00
Misa 726b149fbb Refactor `Screen.cpp` to use named constants
No more hardcoded 320s and 240s here.
2022-03-12 16:46:58 -08:00
Misa aa343bc334 Remove `SDL_GetTicks64()` ifdefs
We can now use the function that doesn't wrap after ~49 days since
SDL 2.0.18 released.
2022-02-11 17:31:41 -05:00
Misa 276aab1209 Default to integer scaling mode
Issue #849 suggested making integer be the default on Big Picture and
Steam Deck, but after thinking about it more, I think it's better and
more simple to just default to integer mode in general.

Reason being that people in Big Picture shouldn't expect the picture to
look different if they're out of Big Picture but still in fullscreen, or
have the picture look different in fullscreen depending on if they
launched the game for the first time in Big Picture or not. And besides,
the less lines of code, the better. So I'm just making integer mode the
default.
2021-12-25 23:14:43 -08:00
Misa 550e76a6dc Add and use scaling mode enum
This enum is to just make each mode be readable, instead of mysterious
0/1/2 values. It's not a strictly-typed enum because we still have to
serialize it as ints in the XML, but it's better than just leaving them
as ints.

This also adds a NUM_SCALING_MODES enum, so we don't have to hardcode
that 3 when cycling scaling modes anymore.
2021-12-25 23:14:12 -08:00
Misa f5166c437e Add forced fullscreen mode
This is mainly to make sure the game is definitely set to fullscreen in
Big Picture and on the Steam Deck, and to also remove windowed options
that wouldn't make sense if you're not on a desktop (toggling
fullscreen, resize to nearest). Those options would also be removed on
console and mobile too.

There's a bit of an annoying bug where if you launch the game in forced
fullscreen mode, but then exit and relaunch in normal mode, your game
will have fullscreen window sizes but it won't be fullscreen. This is
because forced fullscreen mode tries to preserve your non-forced
fullscreen setting, but due to the way window sizes are stored and
queried, it can't preserve the non-forced window size. This is a bit
difficult to work around, so I'm just putting in a FIXME here because we
can fix it later and I'd rather have a slightly buggy forced fullscreen
mode than not have one at all.

Closes #849.
2021-12-25 23:01:45 -08:00
Misa dd24343141 Use `LoadImage` in `LoadIcon`
This de-duplicates the code, simplifying the codebase and reducing the
number of code paths that needs to be maintained. It also adds
robustness checks to LoadIcon that weren't there before (checking that
loading the file succeeded and that decoding the file also succeeded).

Now, you might think that loading the image with alpha will change
things in some way. But actually, I tested it, and I'm pretty sure it
doesn't. Since my window manager, i3, doesn't display icons, I've had to
resort to this hacky multi-liner
( https://unix.stackexchange.com/a/48866 ) to dump the icon to a PAM
file. I don't know what a PAM file is and all my various attempts to
convert it into something readable failed. But what I did instead was
just grab the icon of the game before this commit (on 2.3, just to be
extra sure), and `diff`ed it with the grabbed icon now, and they end up
being the exact same file. So there's literally no difference.

The only other consideration is that LoadImage needs to be exported,
since it's implemented in GraphicsResources.cpp. I just opted to
forward-declare it right before LoadIcon in Screen.cpp, since it's
really the only other time it's used. No need to create a new header
file for it or anything.
2021-12-25 01:29:24 -08:00
Misa 1e157f3cc9 De-C++-ify `struct ScreenSettings`
This includes:
- Removing the constructor in favor of actually being able to see that
  there's an actual function called being made initializing the struct
- Removing the use of a reference in Screen::init() in favor of using a
  pointer
- Adding the struct qualifier everywhere (it's not much typing),
  although technically you could typedef it in C, but I'd rather much
  not typedef just to remove a tag qualifier
2021-12-25 00:30:10 -08:00
Misa d0ffafe117 Extern `gameScreen`, remove `screenbuffer`
I know earlier I removed the gameScreen extern in favor of using
screenbuffer, but that was only to be consistent. After further
consideration, I have found that it's actually really stupid.

There's no reason to be accessing it through screenbuffer, and it's
probably an artifact of 2.0-2.2 passing stack-allocated otherwise-global
classes everywhere through function arguments. Also, it leads to stupid
bugs where screenbuffer could potentially be NULL, which has already
resulted in various annoying crashes in the past. Although those could
be fixed by simply initializing screenbuffer at the very top of main(),
but, why not just scrap the whole thing anyway?

So that's what I'm doing.

As a nice side effect, I've removed the transitive include of Screen.h
from Graphics.h. This could've been done already since it only includes
it for the pointer anyway, but it's still good to do it now.
2021-12-25 00:29:28 -08:00
Misa 816a0b9eb7 Move `filterSubrect` off of `Screen`
It's only used in FlipScreen.
2021-12-22 20:39:11 -08:00
Misa f7b4ac8322 Rename stretch mode to scaling mode internally
It's been long overdue that this variable be named properly. 2.2 added
integer scaling mode (thanks Ethan), 2.3 renamed it to scaling mode. Now
2.4 will properly call it what it is so people won't be confused by it.

The ScreenSettings struct member is renamed from stretch to scalingMode
along with the Screen class member being renamed, as well as the
toggleStretchMode function being renamed to toggleScalingMode as well.
Unfortunately, due to compatibility, we can't change the <stretch> XML
tag.
2021-12-22 19:54:59 -08:00
Misa 038f15f4a6 Remove outdated FIXMEs from `Screen.cpp`
The VSync renderer workaround is no longer a thing, so these comments
should go away.
2021-10-03 13:23:12 -07:00
Misa 6ba7058a0e Fix VSync renderer workaround
SDL just got an API to toggle VSync without having to tear down the
renderer ( libsdl-org/SDL#4157 ). We can remove the workaround and use
that instead. For now, we are putting it behind an ifdef until SDL
2.0.18 officially releases in November.

Fixes #831.
2021-09-14 20:23:22 -07:00
Misa 37b7615b71 Fix surface color masks
This fixes the color ordering of every SDL_Surface in the game.

Basically, images need to be loaded in ABGR format (except if they don't
have alpha, then you use RGB? I'm not sure what's going on here), and
then they will be converted to RGB/RGBA afterwards.

Due to the surfaces actually being BGR/BGRA, the game used to use
getRGBA/getRGB to swap the colors back around to BGRA/BGR, but I've
fixed those too.
2021-09-06 20:12:48 -07:00
Misa c64fd89325 Untabify every single file
YOLO.

This is a repeat of #642. As before, I just did

    rg -l '\t' | xargs -n 1 sed -i -e 's/\t/    /g'

inside the desktop_version/ folder.
2021-09-06 18:56:39 -07:00
Misa c58c357a81 Simplify Flip Mode rendering code with SDL_RenderCopyEx
Previously, Flip Mode rendering had to be complicated and allocate
another buffer to call FlipSurfaceVerticle, and it was just a mess.

Instead, why not just do SDL_RenderCopyEx, and let SDL flip the screen
for us? This ends up pretty massively simplifying the rendering code.
2021-09-01 14:44:59 -07:00
Misa 96539f891c Replace all print calls with vlog calls
This is pretty straight-forward to do.
2021-09-01 14:34:55 -07:00
Ethan Lee 8ebf8a21e4 Default to VSync being enabled 2021-08-31 15:08:46 -04:00
Misa 53b3811a4d Move graphic options menu update to toggleFullScreen
This fixes a bug where using the fullscreen toggle keybind (Alt+Enter,
Alt+F, or F11) wouldn't update the color of the "resize to nearest" menu
option. The color doesn't functionally change anything - the option
still won't work, and will still have the message telling you that you
need to be in windowed mode when you move your menu selection to it -
but it's an easy inconsistency to fix; just move the menu recreation in
to Screen::toggleFullScreen() itself.
2021-04-22 19:42:32 -04:00
Misa 3ebdc1da89 Transfer param init responsibility to loadFileToMemory
So, the codebase was kind of undecided about who is responsible for
initializing the parameters passed to FILESYSTEM_loadFileToMemory() - is
it the caller? Is it FILESYSTEM_loadFileToMemory()? Sometimes callers
would initialize one variable but not the other, and it was always a
toss-up whether or not FILESYSTEM_loadFileToMemory() would end up
initializing everything in the end.

All of this is to say that the game dereferences an uninitialized
pointer if it can't load a sound effect. Which is bad. Now, I could
either fix that single case, or fix every case. Judging by the title of
this commit, you can infer that I decided to fix every case - fixing
every case means not just all cases that currently exist (which, as far
as I know, is only the sound effect one), but all cases that could exist
in the future.

So, FILESYSTEM_loadFileToMemory() is now guaranteed to initialize its
parameters even if the file fails to be loaded. This is better than
passing the responsibility to the caller anyway, because if the caller
initialized it, then that would be wasted work if the file succeeds
anyway because FILESYSTEM_loadFileToMemory() will overwrite it, and if
the file fails to load, well that's when the variables get initialized
anyway.
2021-04-18 15:01:43 -04:00
Misa ff3cba9cee Replace asset load calls with loadAssetToMemory()
All assets now use FILESYSTEM_loadAssetToMemory() instead of
FILESYSTEM_loadFileToMemory().
2021-04-05 16:39:37 -04:00
Misa aea5611e5b Remove default argument from loadFileToMemory()
Default function arguments are the devil, and it's better to be more
explicit about what you're passing into the function. Also because we
might become C-only in the future and to help faciliate that, we should
get rid of C++-isms like default function arguments now.
2021-04-05 16:39:37 -04:00
Ethan Lee 051fe9eba9 Skip the icon on Apple targets, it also has the icns 2021-03-31 02:50:38 -04:00
Misa 758d201296 Fix transitive includes in Screen.cpp
Screen.cpp wasn't explicitly including SDL.h, instead relying on
Screen.h to include it.

It was also relying on SDL.h to include stdio.h on Linux, which breaks
because SDL.h doesn't include stdio.h on Windows. So stdio.h is now
explicitly included as well.

stdlib.h is not used in this file.
2021-02-27 14:26:08 -05:00
Misa 38d5664601 Change all surface-clearing FillRect()s to use ClearSurface()
ClearSurface() is less verbose than doing it the old way, and also
conveys intent clearer. Plus, some of these FillRect()s had hardcoded
width and height values, whereas ClearSurface() doesn't - meaning this
change also has better future-proofing, in case the widths and heights
of the surfaces involved change in the future.
2021-02-25 19:38:25 -05:00
Misa 6a3a1fe147
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.

This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.

I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 17:23:59 -05:00
Misa de26596d54 Fix FIXME comments with outdated referents in Screen.cpp
These FIXME comments are still correct about code duplication, but
they're incorrect about where exactly the original code is after the
original code got moved around. So I've fixed them to refer to the
correct locations.

We really should get around to de-duplicating the code mentioned in
these comments...
2021-02-15 23:07:35 -05:00
Misa a3ad7b73f3 Add Screen::destroy()
In order to have squeaky-clean memory management, we'll need to clean up
all the things that Screen allocates. This is the function to call to do
so.
2021-02-15 23:07:35 -05:00
leo60228 b5ef10cae5 Consistently use Screen::GetWindowSize 2021-01-18 13:10:22 -05:00
leo60228 46d8599f62 Use SDL_GetRendererOutputSize instead of SDL_GetWindowSize
SDL_GetRendererOutputSize will always return the actual size, even in
some obscure HiDPI/macOS cases.
2021-01-18 13:10:06 -05:00
leo60228 d9fff2a8c3 Set SDL window as DPI-aware
This works on macOS, Wayland, and a few more esoteric platforms. X11
doesn't have a concept of DPI-awareness. Note that with this flag
SDL_GetWindowSize() isn't guaranteed to return the actual window size.
2021-01-18 13:09:47 -05:00
Misa 769f99f590 Reduce dependency on libc functions
During 2.3 development, there's been a gradual shift to using SDL stdlib
functions instead of libc functions, but there are still some libc
functions (or the same libc function but from the STL) in the code.

Well, this patch replaces all the rest of them in one fell swoop.

SDL's stdlib can replace most of these, but its SDL_min() and SDL_max()
are inadequate - they aren't really functions, they're more like macros
with a nasty penchant for double-evaluation. So I just made my own
VVV_min() and VVV_max() functions and placed them in Maths.h instead,
then replaced all the previous usages of min(), max(), std::min(),
std::max(), SDL_min(), and SDL_max() with VVV_min() and VVV_max().

Additionally, there's no SDL_isxdigit(), so I just implemented my own
VVV_isxdigit().

SDL has SDL_malloc() and SDL_free(), but they have some refcounting
built in to them, so in order to use them with LodePNG, I have to
replace the malloc() and free() that LodePNG uses. Which isn't too hard,
I did it in a new file called ThirdPartyDeps.c, and LodePNG is now
compiled with the LODEPNG_NO_COMPILE_ALLOCATORS definition.

Lastly, I also refactored the awful strcpy() and strcat() usages in
PLATFORM_migrateSaveData() to use SDL_snprintf() instead. I know save
migration is getting axed in 2.4, but it still bothers me to have
something like that in the codebase otherwise.

Without further ado, here is the full list of functions that the
codebase now uses:

- SDL_strlcpy() instead of strcpy()
- SDL_strlcat() instead of strcat()
- SDL_snprintf() instead of sprintf(), strcpy(), or strcat() (see above)
- VVV_min() instead of min(), std::min(), or SDL_min()
- VVV_max() instead of max(), std::max(), or SDL_max()
- VVV_isxdigit() instead of isxdigit()
- SDL_strcmp() instead of strcmp()
- SDL_strcasecmp() instead of strcasecmp() or Win32 strcmpi()
- SDL_strstr() instead of strstr()
- SDL_strlen() instead of strlen()
- SDL_sscanf() instead of sscanf()
- SDL_getenv() instead of getenv()
- SDL_malloc() instead of malloc() (replacing in LodePNG as well)
- SDL_free() instead of free() (replacing in LodePNG as well)
2021-01-12 14:02:31 -05:00
Misa 55163e90d5 Allow Game::savestats() to accept a pointer to ScreenSettings
Another step to fix the bug #556 is to allow Game::savestats() to accept
a pointer to an existing ScreenSettings struct. This entails refactoring
Game::savesettings() and Game::serializesettings() to accept the
function as well, along with adding Screen::GetSettings() so the
settings of the current Screen can be easily grabbed.
2020-12-21 20:15:30 -05:00
Misa af11f6936a Factor out screen settings to ScreenSettings struct
It's a bit annoying to pass each screen setting individually, would be
nice if we could just wrap it up in a nice struct and pass that instead.
2020-12-18 10:02:18 -05:00
Misa 6d8b8d08b9 Factor out icon loading to Screen::LoadIcon()
This is so it can be called multiple times without having to duplicate
code.
2020-11-01 13:59:13 -05:00
Misa 52f7a587fe Separate includes into sections and alphabetize them
Okay, so basically here's the include layout that this game now
consistently uses:

[The "main" header file, if any (e.g. Graphics.h for Graphics.cpp)]
[blank line]
[All system includes, such as tinyxml2/physfs/utfcpp/SDL]
[blank line]
[All project includes, such as Game.h/Entity.h/etc.]

And if applicable, another blank line, and then some special-case
include screwy stuff (take a look at editor.cpp or FileSystemUtils.cpp,
for example, they have ifdefs and defines with their includes).
2020-07-19 21:37:40 -04:00
Ethan Lee 82666a1875 Set both filter and vsync hints with override priority 2020-07-08 21:43:05 -04:00
Ethan Lee d3f9a36941 Refactor startup to load config before calling Screen::init 2020-07-08 14:30:57 -04:00
Ethan Lee 0f450f3e39 Move the VSync work to Screen.
The problem we're running into is entirely contained in the Screen - we need to
either decouple graphics context init from Screen::init or we need to take out
the screenbuffer interaction from loadstats (which I'm more in favor of since we
can just pull the config values and pass them to Screen::init later).
2020-07-02 00:19:40 -04:00
Misa 7ce4f1173d Add "resize to nearest" graphics option
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.
2020-06-30 09:21:00 -04:00
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
Misa 30bcc08bec Move gameScreen off of the stack and onto the heap
Just so it can be properly used globally like all the other classes.
2020-06-13 14:50:33 -04:00
Misa 0947840365 Remove unused variable Screen::glScreen
Not sure what this was meant to be - a flag for if the screen is OpenGL
or not? Either way, unused.
2020-04-03 10:40:50 -04:00
Misa ef234d3fc0 Fix mixed indentation in Screen.cpp
Screen.cpp now consistently uses tabs.
2020-04-03 10:40:50 -04:00
Misa e722251ebe Remove useless function Screen::ClearScreen()
This function does not clear the screen at all, it does absolutely
nothing.
2020-04-03 10:40:50 -04:00
Misa cad0b4fcc4 Do proper error handling inside Screen::ResizeScreen()
Instead of passing the error codes out of the function, just handle the
errors directly as they happen, and fail gracefully if something goes
wrong instead of continuing.
2020-03-13 19:05:56 -04:00
Misa 9175c08763 Don't print useless false error message when toggling fullscreen
Whenever you would press Alt+Enter, or Alt+F, or on macOS Command+Enter,
or on macOS Command+F, or F11, the game would print this useless error
message to console, every single time: "Error: failed: " and it would
concatenate SDL_GetError() after it, but most of the time SDL_GetError()
is blank, so it would print just that.

Instead, what the fullscreen shortcut will now do is check the result of
the relevant SDL functions, BEFORE it decides to print an error message.
And when it DOES print an error message, it will be less vague and will
say instead "Error: toggling fullscreen failed: <output of
SDL_GetError()>".

This means Screen::ResizeScreen() and Screen::toggleFullScreen() are now
int-returning functions. Ideally, every function interfacing with SDL
would return an error code, but that's too much for this simple patch.

Additionally, I took the opportunity to clean up the surrounding
formatting of the code a bit, most notably dedenting the
keypress-clearing stuff by one tab level, converting the
shortcut-handling code to spaces, and removing commented-out code.
2020-03-13 08:40:59 -04:00
Ethan Lee f7c0321b71 Hello WWWWWWorld! 2020-01-08 10:37:50 -05:00