2021-03-06 05:40:13 +01:00
|
|
|
#include <SDL.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2022-12-01 07:30:16 +01:00
|
|
|
#include "Alloc.h"
|
2020-01-01 21:29:24 +01:00
|
|
|
#include "Graphics.h"
|
2021-03-06 05:40:13 +01:00
|
|
|
#include "Maths.h"
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void setRect( SDL_Rect& _r, int x, int y, int w, int h )
|
|
|
|
{
|
|
|
|
_r.x = x;
|
|
|
|
_r.y = y;
|
|
|
|
_r.w = w;
|
|
|
|
_r.h = h;
|
|
|
|
}
|
|
|
|
|
2021-03-06 05:12:01 +01:00
|
|
|
static SDL_Surface* RecreateSurfaceWithDimensions(
|
|
|
|
SDL_Surface* surface,
|
|
|
|
const int width,
|
|
|
|
const int height
|
|
|
|
) {
|
|
|
|
SDL_Surface* retval;
|
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-06 05:17:56 +01:00
|
|
|
SDL_BlendMode blend_mode;
|
2021-03-06 05:12:01 +01:00
|
|
|
|
|
|
|
if (surface == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = SDL_CreateRGBSurface(
|
|
|
|
surface->flags,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
surface->format->BitsPerPixel,
|
|
|
|
surface->format->Rmask,
|
|
|
|
surface->format->Gmask,
|
|
|
|
surface->format->Bmask,
|
|
|
|
surface->format->Amask
|
|
|
|
);
|
|
|
|
|
|
|
|
if (retval == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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-06 05:17:56 +01:00
|
|
|
SDL_GetSurfaceBlendMode(surface, &blend_mode);
|
|
|
|
SDL_SetSurfaceBlendMode(retval, blend_mode);
|
|
|
|
|
2021-03-06 05:12:01 +01:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SDL_Surface* RecreateSurface(SDL_Surface* surface)
|
|
|
|
{
|
|
|
|
if (surface == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RecreateSurfaceWithDimensions(
|
|
|
|
surface,
|
|
|
|
surface->w,
|
|
|
|
surface->h
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_Surface* GetSubSurface( SDL_Surface* metaSurface, int x, int y, int width, int height )
|
|
|
|
{
|
|
|
|
// Create an SDL_Rect with the area of the _surface
|
|
|
|
SDL_Rect area;
|
|
|
|
area.x = x;
|
|
|
|
area.y = y;
|
|
|
|
area.w = width;
|
|
|
|
area.h = height;
|
|
|
|
|
|
|
|
//Convert to the correct display format after nabbing the new _surface or we will slow things down.
|
2021-03-06 05:12:01 +01:00
|
|
|
SDL_Surface* preSurface = RecreateSurfaceWithDimensions(
|
|
|
|
metaSurface,
|
2020-08-23 03:52:42 +02:00
|
|
|
width,
|
2021-03-06 05:12:01 +01:00
|
|
|
height
|
2020-08-23 03:52:42 +02:00
|
|
|
);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
// Lastly, apply the area from the meta _surface onto the whole of the sub _surface.
|
|
|
|
SDL_BlitSurface(metaSurface, &area, preSurface, 0);
|
|
|
|
|
|
|
|
// Return the new Bitmap _surface
|
|
|
|
return preSurface;
|
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
static void DrawPixel(SDL_Surface* surface, const int x, const int y, const SDL_Color color)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_PixelFormat* fmt = surface->format;
|
|
|
|
const int bpp = fmt->BytesPerPixel;
|
|
|
|
Uint32* pixel = (Uint32*) ((Uint8*) surface->pixels + y * surface->pitch + x * bpp);
|
|
|
|
|
|
|
|
switch (bpp)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
case 3:
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_assert(0 && "Non-32-bit colors not supported!");
|
|
|
|
return;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
case 4:
|
2023-01-02 19:44:35 +01:00
|
|
|
*pixel = SDL_MapRGBA(fmt, color.r, color.g, color.b, color.a);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Color ReadPixel(const SDL_Surface* surface, const int x, const int y)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_PixelFormat* fmt = surface->format;
|
|
|
|
const int bpp = surface->format->BytesPerPixel;
|
|
|
|
const Uint32* pixel = (Uint32*) ((Uint8*) surface->pixels + y * surface->pitch + x * bpp);
|
2023-01-02 19:44:35 +01:00
|
|
|
SDL_Color color = {0, 0, 0, 0};
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
switch (bpp)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
case 3:
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_assert(0 && "Non-32-bit colors not supported!");
|
2023-01-02 19:44:35 +01:00
|
|
|
break;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
case 4:
|
2023-01-02 19:44:35 +01:00
|
|
|
SDL_GetRGBA(*pixel, fmt, &color.r, &color.g, &color.b, &color.a);
|
2023-01-02 01:36:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return color;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Surface * ScaleSurface( SDL_Surface *_surface, int Width, int Height, SDL_Surface * Dest )
|
|
|
|
{
|
|
|
|
if(!_surface || !Width || !Height)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
SDL_Surface *_ret;
|
|
|
|
if(Dest == NULL)
|
|
|
|
{
|
2021-03-06 05:12:01 +01:00
|
|
|
_ret = RecreateSurfaceWithDimensions(_surface, Width, Height);
|
2020-01-01 21:29:24 +01:00
|
|
|
if(_ret == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_ret = Dest;
|
|
|
|
}
|
|
|
|
|
2021-09-06 05:06:28 +02:00
|
|
|
SDL_BlitScaled(_surface, NULL, _ret, NULL);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
return _ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Surface * FlipSurfaceVerticle(SDL_Surface* _src)
|
|
|
|
{
|
2021-03-06 05:12:01 +01:00
|
|
|
SDL_Surface * ret = RecreateSurface(_src);
|
2020-04-02 22:35:43 +02:00
|
|
|
if(ret == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
for(Sint32 y = 0; y < _src->h; y++)
|
|
|
|
{
|
|
|
|
for(Sint32 x = 0; x < _src->w; x++)
|
|
|
|
{
|
|
|
|
DrawPixel(ret, x ,(_src->h-1) - y ,ReadPixel(_src, x, y));
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
return ret;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void BlitSurfaceStandard( SDL_Surface* _src, SDL_Rect* _srcRect, SDL_Surface* _dest, SDL_Rect* _destRect )
|
|
|
|
{
|
|
|
|
SDL_BlitSurface( _src, _srcRect, _dest, _destRect );
|
|
|
|
}
|
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
static void BlitSurfaceTransform(
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Surface* src,
|
|
|
|
const SDL_Rect* src_rect,
|
|
|
|
SDL_Surface* dest,
|
|
|
|
SDL_Rect* dest_rect,
|
2023-01-03 03:01:42 +01:00
|
|
|
SDL_Color (*transform)(SDL_Color pixel, SDL_Color color),
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color color
|
2020-01-01 21:29:24 +01:00
|
|
|
) {
|
2023-01-03 03:01:42 +01:00
|
|
|
if (src == NULL || dest == NULL || transform == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (color.a == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Rect orig_rect;
|
|
|
|
if (src_rect == NULL)
|
|
|
|
{
|
|
|
|
setRect(orig_rect, 0, 0, src->w, src->h);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
orig_rect = *src_rect;
|
|
|
|
}
|
|
|
|
int blit_x;
|
|
|
|
int blit_y;
|
|
|
|
if (dest_rect == NULL)
|
|
|
|
{
|
|
|
|
blit_x = 0;
|
|
|
|
blit_y = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
blit_x = dest_rect->x;
|
|
|
|
blit_y = dest_rect->y;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2023-01-05 00:33:56 +01:00
|
|
|
/* FIXME: Find a way to do this without allocating... */
|
|
|
|
SDL_Surface* tempsurface = RecreateSurface(dest);
|
|
|
|
if (tempsurface == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SDL_SetSurfaceBlendMode(tempsurface, SDL_BLENDMODE_BLEND);
|
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
for (int x = 0; x < orig_rect.w; x++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-03 03:01:42 +01:00
|
|
|
for (int y = 0; y < orig_rect.h; y++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-03 03:01:42 +01:00
|
|
|
if (blit_x + x < 0 || blit_y + y < 0 ||
|
|
|
|
blit_x + x >= dest->w || blit_y + y >= dest->h)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SDL_Color pixel = ReadPixel(src, orig_rect.x + x, orig_rect.y + y);
|
|
|
|
if (pixel.a == 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SDL_Color result = transform(pixel, color);
|
2023-01-05 00:33:56 +01:00
|
|
|
DrawPixel(tempsurface, blit_x + x, blit_y + y, result);
|
2020-06-30 00:05:57 +02:00
|
|
|
}
|
|
|
|
}
|
2023-01-05 00:33:56 +01:00
|
|
|
|
|
|
|
SDL_BlitSurface(tempsurface, NULL, dest, NULL);
|
|
|
|
VVV_freefunc(SDL_FreeSurface, tempsurface);
|
2023-01-03 03:01:42 +01:00
|
|
|
}
|
2020-06-30 00:05:57 +02:00
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
static SDL_Color transform_color(const SDL_Color pixel, const SDL_Color color)
|
|
|
|
{
|
|
|
|
const float div1 = pixel.a / 255.0f;
|
|
|
|
const float div2 = color.a / 255.0f;
|
|
|
|
const Uint8 alpha = (div1 * div2) * 255.0f;
|
|
|
|
const SDL_Color result = {color.r, color.g, color.b, alpha};
|
|
|
|
return result;
|
2020-06-30 00:05:57 +02:00
|
|
|
}
|
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
void BlitSurfaceColoured(
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Surface* src,
|
|
|
|
const SDL_Rect* src_rect,
|
|
|
|
SDL_Surface* dest,
|
|
|
|
SDL_Rect* dest_rect,
|
|
|
|
const SDL_Color color
|
2020-06-30 00:05:57 +02:00
|
|
|
) {
|
2023-01-03 03:01:42 +01:00
|
|
|
return BlitSurfaceTransform(
|
|
|
|
src, src_rect, dest, dest_rect, transform_color, color
|
|
|
|
);
|
|
|
|
}
|
2020-06-30 00:05:57 +02:00
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
static SDL_Color transform_tint(const SDL_Color pixel, const SDL_Color color)
|
|
|
|
{
|
|
|
|
double red = pixel.r * 0.299;
|
|
|
|
double green = pixel.g * 0.587;
|
|
|
|
double blue = pixel.b * 0.114;
|
2020-06-30 00:05:57 +02:00
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
const double gray = SDL_floor(red + green + blue + 0.5);
|
2020-06-30 00:05:57 +02:00
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
red = gray * color.r / 255.0;
|
|
|
|
green = gray * color.g / 255.0;
|
|
|
|
blue = gray * color.b / 255.0;
|
2020-06-30 00:05:57 +02:00
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
red = SDL_clamp(red, 0, 255);
|
|
|
|
green = SDL_clamp(green, 0, 255);
|
|
|
|
blue = SDL_clamp(blue, 0, 255);
|
2020-06-30 00:05:57 +02:00
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
const float div1 = pixel.a / 255.0f;
|
|
|
|
const float div2 = color.a / 255.0f;
|
|
|
|
const Uint8 alpha = (div1 * div2) * 255.0f;
|
2020-06-30 00:05:57 +02:00
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
const SDL_Color result = {(Uint8) red, (Uint8) green, (Uint8) blue, alpha};
|
|
|
|
return result;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2023-01-03 03:01:42 +01:00
|
|
|
void BlitSurfaceTinted(
|
|
|
|
SDL_Surface* src,
|
|
|
|
const SDL_Rect* src_rect,
|
|
|
|
SDL_Surface* dest,
|
|
|
|
SDL_Rect* dest_rect,
|
|
|
|
const SDL_Color color
|
|
|
|
) {
|
|
|
|
return BlitSurfaceTransform(
|
|
|
|
src, src_rect, dest, dest_rect, transform_tint, color
|
|
|
|
);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-10 18:14:37 +01:00
|
|
|
static int oldscrollamount = 0;
|
|
|
|
static int scrollamount = 0;
|
|
|
|
static bool isscrolling = 0;
|
2020-04-02 22:35:43 +02:00
|
|
|
|
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 23:23:59 +01:00
|
|
|
void UpdateFilter(void)
|
2020-05-03 05:27:47 +02:00
|
|
|
{
|
2020-04-02 22:35:43 +02:00
|
|
|
if (rand() % 4000 < 8)
|
|
|
|
{
|
|
|
|
isscrolling = true;
|
|
|
|
}
|
|
|
|
|
2020-11-08 01:21:30 +01:00
|
|
|
oldscrollamount = scrollamount;
|
2020-04-02 22:35:43 +02:00
|
|
|
if(isscrolling == true)
|
|
|
|
{
|
|
|
|
scrollamount += 20;
|
|
|
|
if(scrollamount > 240)
|
|
|
|
{
|
|
|
|
scrollamount = 0;
|
2020-11-08 01:21:30 +01:00
|
|
|
oldscrollamount = 0;
|
2020-04-02 22:35:43 +02:00
|
|
|
isscrolling = false;
|
|
|
|
}
|
|
|
|
}
|
2020-05-03 05:27:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Surface* ApplyFilter(SDL_Surface* src)
|
2020-05-03 05:27:47 +02:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
SDL_Surface* ret = RecreateSurface(src);
|
2020-04-02 22:35:43 +02:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
const int red_offset = rand() % 4;
|
2020-04-02 22:35:43 +02:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
for (int x = 0; x < ret->w; x++)
|
2020-04-02 22:35:43 +02:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
for (int y = 0; y < ret->h; y++)
|
2020-04-02 22:35:43 +02:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const int sampley = (y + (int) graphics.lerp(oldscrollamount, scrollamount)) % 240;
|
2020-04-02 22:35:43 +02:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color pixel = ReadPixel(src, x, sampley);
|
2020-04-02 22:35:43 +02:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
Uint8 green = pixel.g;
|
|
|
|
Uint8 blue = pixel.b;
|
2020-04-02 22:35:43 +02:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color pixel_offset = ReadPixel(src, SDL_min(x + red_offset, 319), sampley);
|
|
|
|
Uint8 red = pixel_offset.r;
|
2020-04-02 22:35:43 +02:00
|
|
|
|
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-23 01:43:31 +01:00
|
|
|
double mult;
|
2021-12-23 06:49:08 +01:00
|
|
|
int tmp; /* needed to avoid char overflow */
|
2023-01-02 01:36:43 +01:00
|
|
|
if (isscrolling && sampley > 220 && ((rand() % 10) < 4))
|
2020-04-02 22:35:43 +02:00
|
|
|
{
|
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-23 01:43:31 +01:00
|
|
|
mult = 0.6;
|
2020-04-02 22:35:43 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
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-23 01:43:31 +01:00
|
|
|
mult = 0.2;
|
2020-04-02 22:35:43 +02:00
|
|
|
}
|
|
|
|
|
2021-12-23 06:49:08 +01:00
|
|
|
tmp = red + fRandom() * mult * 254;
|
|
|
|
red = SDL_min(tmp, 255);
|
|
|
|
tmp = green + fRandom() * mult * 254;
|
|
|
|
green = SDL_min(tmp, 255);
|
|
|
|
tmp = blue + fRandom() * mult * 254;
|
|
|
|
blue = SDL_min(tmp, 255);
|
2020-04-02 22:35:43 +02:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
if (y % 2 == 0)
|
2020-04-02 22:35:43 +02:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
red = (Uint8) (red / 1.2f);
|
|
|
|
green = (Uint8) (green / 1.2f);
|
|
|
|
blue = (Uint8) (blue / 1.2f);
|
2020-04-02 22:35:43 +02:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
int distX = (int) ((SDL_abs(160.0f - x) / 160.0f) * 16);
|
|
|
|
int distY = (int) ((SDL_abs(120.0f - y) / 120.0f) * 32);
|
2020-04-02 22:35:43 +02:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
red = SDL_max(red - (distX + distY), 0);
|
|
|
|
green = SDL_max(green - (distX + distY), 0);
|
|
|
|
blue = SDL_max(blue - (distX + distY), 0);
|
2020-04-02 22:35:43 +02:00
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
const SDL_Color color = {red, green, blue, pixel.a};
|
|
|
|
DrawPixel(ret, x, y, color);
|
2020-04-02 22:35:43 +02:00
|
|
|
}
|
|
|
|
}
|
2023-01-02 01:36:43 +01:00
|
|
|
|
|
|
|
return ret;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FillRect( SDL_Surface* _surface, const int _x, const int _y, const int _w, const int _h, const int r, int g, int b )
|
|
|
|
{
|
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 20:13:12 +02:00
|
|
|
SDL_Rect rect = {_x, _y, _w, _h};
|
2021-02-26 00:36:02 +01:00
|
|
|
Uint32 color = SDL_MapRGB(_surface->format, r, g, b);
|
2020-01-01 21:29:24 +01:00
|
|
|
SDL_FillRect(_surface, &rect, color);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FillRect( SDL_Surface* _surface, const int r, int g, int b )
|
|
|
|
{
|
2021-02-26 00:34:59 +01:00
|
|
|
Uint32 color = SDL_MapRGB(_surface->format, r, g, b);
|
|
|
|
SDL_FillRect(_surface, NULL, color);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
void FillRect( SDL_Surface* _surface, SDL_Rect& _rect, const int r, int g, int b )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
Uint32 color = SDL_MapRGB(_surface->format, r, g, b);
|
|
|
|
SDL_FillRect(_surface, &_rect, color);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
void FillRect(SDL_Surface* surface, const SDL_Rect rect, const SDL_Color color)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const Uint32 mapped = SDL_MapRGBA(surface->format, color.r, color.g, color.b, color.a);
|
|
|
|
SDL_FillRect(surface, &rect, mapped);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
void FillRect(SDL_Surface* surface, const SDL_Color color)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const Uint32 mapped = SDL_MapRGBA(surface->format, color.r, color.g, color.b, color.a);
|
|
|
|
SDL_FillRect(surface, NULL, mapped);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FillRect(SDL_Surface* surface, const int x, const int y, const int w, const int h, const SDL_Color color)
|
|
|
|
{
|
|
|
|
const SDL_Rect rect = {x, y, w, h};
|
|
|
|
const Uint32 mapped = SDL_MapRGBA(surface->format, color.r, color.g, color.b, color.a);
|
|
|
|
SDL_FillRect(surface, &rect, mapped);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 01:36:43 +01:00
|
|
|
void FillRect(SDL_Surface* surface, const int r, const int g, const int b, const int a)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2023-01-02 01:36:43 +01:00
|
|
|
const Uint32 mapped = SDL_MapRGBA(surface->format, r, g, b, a);
|
|
|
|
SDL_FillRect(surface, NULL, mapped);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-02-26 00:26:12 +01:00
|
|
|
void ClearSurface(SDL_Surface* surface)
|
|
|
|
{
|
|
|
|
SDL_FillRect(surface, NULL, 0x00000000);
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
void ScrollSurface( SDL_Surface* _src, int _pX, int _pY )
|
|
|
|
{
|
|
|
|
SDL_Surface* part1 = NULL;
|
|
|
|
|
|
|
|
SDL_Rect rect1;
|
2020-04-02 22:35:43 +02:00
|
|
|
SDL_Rect rect2;
|
2020-01-01 21:29:24 +01:00
|
|
|
//scrolling up;
|
|
|
|
if(_pY < 0)
|
|
|
|
{
|
|
|
|
setRect(rect2, 0, 0, _src->w, _src->h - _pY);
|
|
|
|
|
|
|
|
part1 = GetSubSurface(_src, rect2.x, rect2.y, rect2.w, rect2.h);
|
|
|
|
|
|
|
|
SDL_Rect destrect1;
|
|
|
|
|
|
|
|
SDL_SetSurfaceBlendMode(part1, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
setRect(destrect1, 0, _pY, _pX, _src->h);
|
|
|
|
|
|
|
|
SDL_BlitSurface (part1, NULL, _src, &destrect1);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if(_pY > 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
setRect(rect1, 0, 0, _src->w, _src->h - _pY);
|
|
|
|
|
|
|
|
part1 = GetSubSurface(_src, rect1.x, rect1.y, rect1.w, rect1.h);
|
|
|
|
|
|
|
|
SDL_Rect destrect1;
|
|
|
|
|
|
|
|
SDL_SetSurfaceBlendMode(part1, SDL_BLENDMODE_NONE);
|
|
|
|
|
|
|
|
setRect(destrect1, _pX, _pY, _src->w, _src->h - _pY);
|
|
|
|
|
|
|
|
SDL_BlitSurface (part1, NULL, _src, &destrect1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
//Right
|
|
|
|
else if(_pX <= 0)
|
|
|
|
{
|
|
|
|
setRect(rect2, 0, 0, _src->w - _pX, _src->h );
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
part1 = GetSubSurface(_src, rect2.x, rect2.y, rect2.w, rect2.h);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
SDL_Rect destrect1;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
SDL_SetSurfaceBlendMode(part1, SDL_BLENDMODE_NONE);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
setRect(destrect1, _pX, 0, _src->w - _pX, _src->h);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
SDL_BlitSurface (part1, NULL, _src, &destrect1);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
else if(_pX > 0)
|
|
|
|
{
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
setRect(rect1, _pX, 0, _src->w - _pX, _src->h );
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
part1 = GetSubSurface(_src, rect1.x, rect1.y, rect1.w, rect1.h);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
SDL_Rect destrect1;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
SDL_SetSurfaceBlendMode(part1, SDL_BLENDMODE_NONE);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
setRect(destrect1, 0, 0, _src->w - _pX, _src->h);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
SDL_BlitSurface (part1, NULL, _src, &destrect1);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:35:43 +02:00
|
|
|
}
|
|
|
|
//Cleanup temp surface
|
2020-01-01 21:29:24 +01:00
|
|
|
if (part1)
|
|
|
|
{
|
2022-12-01 07:30:16 +01:00
|
|
|
VVV_freefunc(SDL_FreeSurface, part1);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|