Commit Graph

32 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 b7cbdfe8f9 Fix char overflow in Analogue Mode
In aa7b63fa5f, I didn't notice that the
result was implicitly being converted to int by the min/max from before.
I instead added it to the existing char, but that resulted in a char
overflow (it's unsigned, so thankfully not undefined behavior).

But of course the entire point of that commit is to make it explicitly
clear when you are converting between types, intentionally or otherwise,
in min/max comparisons. So despite causing a regression (which I have
now fixed), at least it did its job.
2021-12-22 21:49:08 -08:00
Misa aa7b63fa5f Remove `VVV_min/max` in favor of `SDL_min/max`
VVV_min/max are functions that only operate on ints, and SDL_min/max are
macros that operate on any type but double-evaluate everything.

I know I more-or-less said earlier that SDL_min/max were dumb but I've
changed my mind and think it's better to use them, taking care to make
sure you don't double-evaluate, rather than trying to generate your own
litany of functions with either your own hand-rolled generation macros,
C++ templates, C11 generics, or GCC extensions (that last one you'd
technically use in a macro but it doesn't really matter), all of which
have more downsides than just not double-evaluating.

And the upside of not double-evaluating is that you're disencouraged
from having really complicated single-line min/max expressions and
encouraged to precompute the values beforehand anyway so the final
min/max is more readable. And furthermore you'll notice when you
yourself end up doing double-evaluations anyway. I removed a couple
instances of Graphics::len() being double-evaluated in this commit (as
well as cleaned up some other min/max-using code). Although the only
downside to those double-evaluations was unnecessary computation,
rather than checking the wrong result or having multiple side effects,
thankfully, it's still good to minimize double-evaluations where
possible.
2021-12-22 16:43:31 -08:00
Misa fc2de88b03 Use `SDL_BlitScaled` in `ScaleSurface`
Why do all this error-prone per-pixel work when you can just use an SDL
function instead?
2021-09-05 20:07:18 -07:00
Misa b02cf00ce6 Remove unnecessary Sint16 casts
These casts are sprinkled all throughout the graphics code when creating
and initializing an SDL_Rect on the same line. Unfortunately, most of
these are unnecessary, and at worst are wasteful because they result in
narrowing a 4-byte integer into a 2-byte one when they don't need to
(SDL_Rects are made up of 4-byte integers).

Now, removing them reveals why they were placed there in the first place
- a warning is raised (-Wnarrowing) that implicit narrowing conversions
are prohibited in initializer lists in C++11. (Notably, if the
conversion wasn't narrowing, or implicit, or done in an initializer
list, it would be fine. This is a really specific prohibition that
doesn't apply if any of its sub-cases are true.)

We don't use C++11, but this warning can be easily vanquished by a
simple explicit cast to int (similar to the error of implicitly
converting void* to any other pointer in C++, which works just fine in
C), and we only need to do it when the warning is raised (not every
single time we make an SDL_Rect), so there we go.
2021-04-18 14:55:33 -04:00
Misa 0f36cdce0d Use SDL_floor() instead of libc floor()
Now there is one less dependency on libc.
2021-03-06 16:01:29 -05:00
Misa acfe4c294d Fix transitive includes in GraphicsUtil.cpp
I ran Include What You Use on the file, and a BUNCH of transitive
includes showed up.

colourTransform is used in the file, so GraphicsUtil.h needs to be
included. libc floor() is used in the file, so math.h needs to be
included (I'm removing this next...). NULL is used, so stddef.h. And
stdlib.h is used because we use rand() directly instead of going through
fRandom(). Speaking of which, we use fRandom(), so Maths.h needs to be
included, too.
2021-03-06 16:01:29 -05:00
Misa d19a6cc437 Copy blend mode to recreated surface
This fixes a "root cause" bug (that's existed since 2.2 and below) where
recreated surfaces wouldn't preserve the blend mode of their original
surface.

The surface-level (pun genuinely unintended) bug that this root bug
fixes is the one where there's no background to the room name during the
map menu animation in Flip Mode.

This is because the room name background relies on graphics.backBuffer
being filled with complete black. This is achieved by a call to
ClearSurface() - however, ClearSurface() actually fills it with
transparent black (this is not a regression; in 2.2 and previous, this
was an "inlined" FillRect(backBuffer, 0x00000000)). This would be okay,
and indeed the room name background renders fine in unflipped mode - but
it suddenly breaks in Flip Mode.

Why? Because backBuffer gets fed through FlipSurfaceVerticle(), and
FlipSurfaceVerticle() creates a temporary surface with the same
dimensions and color masks as backBuffer - it, however, does NOT create
it with the same blend mode, and kind of sort of just forgets that the
original was SDL_BLENDMODE_NONE; the new surface is SDL_BLENDMODE_BLEND.
Thus, transparency applies on the new surface, and instead of the room
name being drawn against black, it gets drawn against transparency.
2021-03-05 20:58:46 -08:00
Misa aca33e5587 De-duplicate surface recreation in GraphicsUtil
Here I'm using "surface recreation" to mean allocating a new surface
with almost the exact same properties as a given previous. As you can
see, GraphicsUtil likes to recreate surfaces all the time - copying the
masks and flags (unused lol) of an existing surface - and only varies it
by the dimensions of the new surface.

As you can see, this is a lot less wordy and a lot less repetitive than
copy-pasting it a bunch.
2021-03-05 20:47:47 -08:00
Misa e545c89b5e Combine declaration/initialization of color in two FillRect()s
Just a small simplification, so it's both declared and initialized on
the same line.
2021-02-25 19:38:25 -05:00
Misa e641063d68 Fix two versions of FillRect() unnecessarily creating SDL_Rects
When you pass NULL in for the SDL_Rect* parameter to SDL_FillRect(), SDL
will automatically fill the entire surface with that color. There's no
need for us to create the SDL_Rect ourselves.
2021-02-25 19:38:25 -05:00
Misa 163b85d206 Add ClearSurface()
This is a function that does what it says - it clears the given surface.
This just means doing a FillRect(), but it's better to use this function
because it conveys intent better.
2021-02-25 19:38:25 -05:00
Misa 994f47e7d8 Remove commented-out code from Graphics.cpp and GraphicsUtil.cpp
This is pretty old commented-out code from earlier versions of the game;
they are no longer useful, and are just distracting. If we need them, we
can always refer back to this commit (but I sincerely doubt that we'll
need them).
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 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 e9c62ea9a3 Clean up unnecessary exports and add static keywords
This patch cleans up unnecessary exports from header files (there were
only a few), as well as adds the static keyword to all symbols that
aren't exported and are specific to a file. This helps the linker out in
not doing any unnecessary work, speeding it up and avoiding silent
symbol conflicts (otherwise two symbols with the same name (and
type/signature in C++) would quietly resolve as okay by the linker).
2021-01-10 12:23:59 -05:00
Misa 0e0f5c47a5 Remove unused function FlipSurfaceHorizontal()
This function was marked as unused by cppcheck.
2021-01-02 09:06:42 -05:00
Misa 7687440273 Use SDL_abs() instead of libc abs() in ApplyFilter()
Always good to use the SDL stdlib where possible.
2020-11-07 19:41:25 -05:00
Misa 1a2dd787f3 Interpolate scrolling in Analogue Mode filter
I can't really make the filter update only every timestep, because it's
per-pixel and operates on deltaframes too, so it TECHNICALLY runs faster
in over-30-FPS mode than not. That said, it's not really noticeable, the
filter doesn't look bad for updating more often or anything. However, I
can at least interpolate the scrolling, so it's smooth in over-30-FPS
mode.
2020-11-07 19:41:25 -05:00
Misa 760f1e8e5a Don't hardcode SDL_CreateRGBSurface BitsPerPixel/mask args
For some reason, GetSubSurface() and ApplyFilter() were hardcoding the
bits-per-pixel and/or mask arguments to SDL_CreateRGBSurface(). I've
made them simply re-use the bits-per-pixel and masks of the input
surfaces they operate on, but the bits-per-pixel should always be 32 and
masks should always go first-byte alpha, second-byte red, third-byte
green, fourth-byte blue.
2020-09-08 16:16:40 -04:00
Misa 8af9007b5f Axe SDL_BYTEORDER checks
The game usually runs on little-endian anyways, but even if it did run
on big-endian, it doesn't check endianness everywhere so these checks
are useless. Furthermore, the code should be written so that endianness
doesn't matter in the first place.
2020-09-08 16:16:40 -04:00
Misa 68a54d2594 Axe endian_swap() function and template
Neither of these were used anywhere, so to simplify the code and prevent
having potentially broken code that's never shown to be broken because
it's never tested, I'm removing these.
2020-09-08 16:16:40 -04:00
Misa 79fd3e1d36 Remove -1,-1 offset from ScaleSurface()
For some reason, ScaleSurface() was drawing each pixel one pixel up and
to the left from its actual position. I have no idea why.

But this was causing an issue where pixels would just be dropped,
because they would be drawn outside of the temporary SDL_Surface from
which the scaled surface would be drawn onto. Also, the offset just
creates a visual one-pixel offset in the result for no reason. So I'm
just removing it.

Big Viridian also suffered from this one-pixel offset, so now they will
no longer look like they're floating above the ground when standing on
the floor.
2020-08-06 22:10:47 -04:00
Misa 5f776faba7 Ax ScaleSurfaceSlow() in favor of ScaleSurface()
ScaleSurfaceSlow() uses DrawPixel() instead of SDL_FillRect() to scale a
given surface, which is slow and inefficient, and makes it less likely
that the game could be moved to SDL_Render.

Unfortunately, it has this weird -1,-1 offset, but that will be fixed in
the next commit.
2020-08-06 22:10:47 -04:00
Misa 57dca99a4e Ax OverlaySurfaceKeyed(), set proper foregroundBuffer blend mode
So, earlier in the development of 2.0, Simon Roth (I presume)
encountered a problem: Oh no, all my backgrounds aren't appearing! And
this is because my foregroundBuffer, which contains all the drawn tiles,
is drawing complete black over it!

So he had a solution that seems ingenius, but is actually really really
hacky and super 100% NOT the proper solution. Just, take the
foregroundBuffer, iterate over each pixel, and DON'T draw any pixel
that's 0xDEADBEEF. 0xDEADBEEF is a special signal meaning "don't draw
this pixel". It is called a 'key'.

Unfortunately, this causes a bug where translucent pixels on tiles
(pixels between 0% and 100% opacity) didn't get drawn correctly. They
would be drawn against this weird blue color.

Now, in #103, I came across this weird constant and decided "hey, this
looks awfully like that weird blue color I came across, maybe if I set
it to 0x00000000, i.e. complete and transparent black, the issue will be
fixed". And it DID appear to be fixed. However, I didn't look too
closely, nor did I test it that much, and all that ended up doing was
drawing the pixels against black, which more subtly disguised the
problem with translucent pixels.

So, after some investigation, I noticed that BlitSurfaceColoured() was
drawing translucent pixels just fine. And I thought at the time that
there was something wrong with BlitSurfaceStandard(), or something.
Further along later I realized that all drawn tiles were passing through
this weird OverlaySurfaceKeyed() function. And removing it in favor of a
straight SDL_BlitSurface() produced the bug I mentioned above: Oh no,
all the backgrounds don't show up, because my foregroundBuffer is
drawing pure black over them!

Well... just... set the proper blend mode for foregroundBuffer. It
should be SDL_BLENDMODE_BLEND instead of SDL_BLENDMODE_NONE.

Then you don't have to worry about your transparency at all. If you did
it right, you won't have to resort this hacky color-keying business.

*sigh*
2020-08-06 22:10:30 -04:00
Misa 627e971e90 Remove unnecessary intersectRect() function
This function checked the intersection of rectangles, but it used floats
for some reason when its only caller used ints. There's already an
intersection function (UtilityClass::intersects()), so we should be
using that one instead in order to minimize code duplication.

Graphics::Hitest() is used for per-pixel collision detection, directly
checking the pixels of both entities' sprites. I checked with one of my
TASes and it still syncs, so I'm pretty sure this won't cause any
issues.
2020-08-04 15:59:21 -04:00
Misa 584f73f0a4 Add BlitSurfaceTinted()
This will be used to change the color of existing textures while
preserving their lightness values.
2020-06-29 19:07:45 -04:00
Misa 97b8e062ff Move analogue mode filter update logic to fixed-timestep loop
Otherwise if the analogue filter is scrolling, it'll scroll by REALLY
fast.
2020-06-19 09:05:48 -04:00
Misa 7c511b1550 Fix mixed indentation in GraphicsUtil.cpp
To be fair, it was more on the level of entire functions using different
indentation than the surrounding code, but it's not consistent enough
for me to justify leaving it alone.
2020-04-03 10:40:50 -04:00
AllyTally 6b1a7ebce6 Make "[Press ENTER to return to editor]" fade out after a bit
This makes the "[Press ENTER to return to editor]" fade out after a few frames, allowing screenshots of custom levels to be cleaner and to make sure nothing is obscured while the user is editing their level.
This commit also adds alpha support in BlitSurfaceColoured, where it takes into account the alpha of the pixel *and* the alpha of the color.
`graphics::getRGBA(r,g,b,a)` was added to help with this.
2020-02-09 22:31:33 -04:00
Rémi Verschelde a83e83ca1b Fix warnings raised by GCC 8 2020-01-11 08:53:32 -05:00
Ethan Lee f7c0321b71 Hello WWWWWWorld! 2020-01-08 10:37:50 -05:00