Added SDL_WriteSurfacePixel() and SDL_WriteSurfacePixelFloat()

This commit is contained in:
Sam Lantinga 2024-07-20 17:52:45 -07:00
parent 12e50d17a2
commit 9294476788
5 changed files with 169 additions and 0 deletions

View File

@ -1211,6 +1211,49 @@ extern SDL_DECLSPEC int SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int x
*/
extern SDL_DECLSPEC int SDLCALL SDL_ReadSurfacePixelFloat(SDL_Surface *surface, int x, int y, float *r, float *g, float *b, float *a);
/**
* Writes a single pixel to a surface.
*
* This function prioritizes correctness over speed: it is suitable for unit
* tests, but is not intended for use in a game engine.
*
* Like SDL_MapRGBA, this uses the entire 0..255 range when converting color
* components from pixel formats with less than 8 bits per RGB component.
*
* \param surface the surface to write.
* \param x the horizontal coordinate, 0 <= x < width.
* \param y the vertical coordinate, 0 <= y < height.
* \param r the red channel value, 0-255.
* \param g the green channel value, 0-255.
* \param b the blue channel value, 0-255.
* \param a the alpha channel value, 0-255.
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*/
extern SDL_DECLSPEC int SDLCALL SDL_WriteSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
/**
* Writes a single pixel to a surface.
*
* This function prioritizes correctness over speed: it is suitable for unit
* tests, but is not intended for use in a game engine.
*
* \param surface the surface to write.
* \param x the horizontal coordinate, 0 <= x < width.
* \param y the vertical coordinate, 0 <= y < height.
* \param r the red channel value, normally in the range 0-1.
* \param g the green channel value, normally in the range 0-1.
* \param b the blue channel value, normally in the range 0-1.
* \param a the alpha channel value, normally in the range 0-1.
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*/
extern SDL_DECLSPEC int SDLCALL SDL_WriteSurfacePixelFloat(SDL_Surface *surface, int x, int y, float r, float g, float b, float a);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}

View File

@ -875,6 +875,8 @@ SDL3_0.0.0 {
SDL_WriteS64LE;
SDL_WriteS8;
SDL_WriteStorageFile;
SDL_WriteSurfacePixel;
SDL_WriteSurfacePixelFloat;
SDL_WriteU16BE;
SDL_WriteU16LE;
SDL_WriteU32BE;

View File

@ -900,6 +900,8 @@
#define SDL_WriteS64LE SDL_WriteS64LE_REAL
#define SDL_WriteS8 SDL_WriteS8_REAL
#define SDL_WriteStorageFile SDL_WriteStorageFile_REAL
#define SDL_WriteSurfacePixel SDL_WriteSurfacePixel_REAL
#define SDL_WriteSurfacePixelFloat SDL_WriteSurfacePixelFloat_REAL
#define SDL_WriteU16BE SDL_WriteU16BE_REAL
#define SDL_WriteU16LE SDL_WriteU16LE_REAL
#define SDL_WriteU32BE SDL_WriteU32BE_REAL

View File

@ -910,6 +910,8 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS64BE,(SDL_IOStream *a, Sint64 b),(a,b),return
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS64LE,(SDL_IOStream *a, Sint64 b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS8,(SDL_IOStream *a, Sint8 b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_WriteStorageFile,(SDL_Storage *a, const char *b, const void *c, Uint64 d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_WriteSurfacePixel,(SDL_Surface *a, int b, int c, Uint8 d, Uint8 e, Uint8 f, Uint8 g),(a,b,c,d,e,f,g),return)
SDL_DYNAPI_PROC(int,SDL_WriteSurfacePixelFloat,(SDL_Surface *a, int b, int c, float d, float e, float f, float g),(a,b,c,d,e,f,g),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteU16BE,(SDL_IOStream *a, Uint16 b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteU16LE,(SDL_IOStream *a, Uint16 b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteU32BE,(SDL_IOStream *a, Uint32 b),(a,b),return)

View File

@ -2459,6 +2459,126 @@ int SDL_ReadSurfacePixelFloat(SDL_Surface *surface, int x, int y, float *r, floa
return result;
}
int SDL_WriteSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
Uint32 pixel = 0;
size_t bytes_per_pixel;
Uint8 *p;
int result = -1;
if (!SDL_SurfaceValid(surface) || !surface->format || !surface->pixels) {
return SDL_InvalidParamError("surface");
}
if (x < 0 || x >= surface->w) {
return SDL_InvalidParamError("x");
}
if (y < 0 || y >= surface->h) {
return SDL_InvalidParamError("y");
}
bytes_per_pixel = SDL_BYTESPERPIXEL(surface->format);
if (SDL_MUSTLOCK(surface)) {
if (SDL_LockSurface(surface) < 0) {
return -1;
}
}
p = (Uint8 *)surface->pixels + y * surface->pitch + x * bytes_per_pixel;
if (bytes_per_pixel <= sizeof(pixel) && !SDL_ISPIXELFORMAT_FOURCC(surface->format)) {
pixel = SDL_MapRGBA(surface->internal->format, surface->internal->palette, r, g, b, a);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
SDL_memcpy(p, ((Uint8 *)&pixel) + (sizeof(pixel) - bytes_per_pixel), bytes_per_pixel);
#else
SDL_memcpy(p, &pixel, bytes_per_pixel);
#endif
result = 0;
} else if (SDL_ISPIXELFORMAT_FOURCC(surface->format)) {
result = SDL_Unsupported();
} else {
/* This is really slow, but it gets the job done */
Uint8 rgba[4];
SDL_Colorspace colorspace = SDL_GetSurfaceColorspace(surface);
rgba[0] = r;
rgba[1] = g;
rgba[2] = b;
rgba[3] = a;
result = SDL_ConvertPixelsAndColorspace(1, 1, SDL_PIXELFORMAT_RGBA32, SDL_COLORSPACE_SRGB, 0, rgba, sizeof(rgba), surface->format, colorspace, surface->internal->props, p, surface->pitch);
}
if (SDL_MUSTLOCK(surface)) {
SDL_UnlockSurface(surface);
}
return result;
}
int SDL_WriteSurfacePixelFloat(SDL_Surface *surface, int x, int y, float r, float g, float b, float a)
{
int result = -1;
if (!SDL_SurfaceValid(surface) || !surface->format || !surface->pixels) {
return SDL_InvalidParamError("surface");
}
if (x < 0 || x >= surface->w) {
return SDL_InvalidParamError("x");
}
if (y < 0 || y >= surface->h) {
return SDL_InvalidParamError("y");
}
if (SDL_BYTESPERPIXEL(surface->format) <= sizeof(Uint32) && !SDL_ISPIXELFORMAT_FOURCC(surface->format)) {
Uint8 r8, g8, b8, a8;
r8 = (Uint8)SDL_round(SDL_clamp(r, 0.0f, 1.0f) * 255.0f);
g8 = (Uint8)SDL_round(SDL_clamp(g, 0.0f, 1.0f) * 255.0f);
b8 = (Uint8)SDL_round(SDL_clamp(b, 0.0f, 1.0f) * 255.0f);
a8 = (Uint8)SDL_round(SDL_clamp(a, 0.0f, 1.0f) * 255.0f);
if (SDL_WriteSurfacePixel(surface, x, y, r8, g8, b8, a8) == 0) {
result = 0;
}
} else if (SDL_ISPIXELFORMAT_FOURCC(surface->format)) {
result = SDL_Unsupported();
} else {
/* This is really slow, but it gets the job done */
float rgba[4];
Uint8 *p;
if (SDL_MUSTLOCK(surface)) {
if (SDL_LockSurface(surface) < 0) {
return -1;
}
}
p = (Uint8 *)surface->pixels + y * surface->pitch + x * SDL_BYTESPERPIXEL(surface->format);
rgba[0] = r;
rgba[1] = g;
rgba[2] = b;
rgba[3] = a;
if (surface->format == SDL_PIXELFORMAT_RGBA128_FLOAT) {
SDL_memcpy(p, rgba, sizeof(rgba));
result = 0;
} else {
SDL_Colorspace dst_colorspace = SDL_GetSurfaceColorspace(surface);
SDL_Colorspace src_colorspace = (dst_colorspace == SDL_COLORSPACE_SRGB_LINEAR ? SDL_COLORSPACE_SRGB_LINEAR : SDL_COLORSPACE_SRGB);
result = SDL_ConvertPixelsAndColorspace(1, 1, SDL_PIXELFORMAT_RGBA128_FLOAT, src_colorspace, 0, rgba, sizeof(rgba), surface->format, dst_colorspace, surface->internal->props, p, surface->pitch);
}
if (SDL_MUSTLOCK(surface)) {
SDL_UnlockSurface(surface);
}
}
return result;
}
/*
* Free a surface created by the above function.
*/