Browse Source

Added SDL_WriteSurfacePixel() and SDL_WriteSurfacePixelFloat()

Sam Lantinga 1 year ago
parent
commit
9294476788

+ 43 - 0
include/SDL3/SDL_surface.h

@@ -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);
 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++ */
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 2 - 0
src/dynapi/SDL_dynapi.sym

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

+ 2 - 0
src/dynapi/SDL_dynapi_overrides.h

@@ -900,6 +900,8 @@
 #define SDL_WriteS64LE SDL_WriteS64LE_REAL
 #define SDL_WriteS64LE SDL_WriteS64LE_REAL
 #define SDL_WriteS8 SDL_WriteS8_REAL
 #define SDL_WriteS8 SDL_WriteS8_REAL
 #define SDL_WriteStorageFile SDL_WriteStorageFile_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_WriteU16BE SDL_WriteU16BE_REAL
 #define SDL_WriteU16LE SDL_WriteU16LE_REAL
 #define SDL_WriteU16LE SDL_WriteU16LE_REAL
 #define SDL_WriteU32BE SDL_WriteU32BE_REAL
 #define SDL_WriteU32BE SDL_WriteU32BE_REAL

+ 2 - 0
src/dynapi/SDL_dynapi_procs.h

@@ -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_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(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_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_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_WriteU16LE,(SDL_IOStream *a, Uint16 b),(a,b),return)
 SDL_DYNAPI_PROC(SDL_bool,SDL_WriteU32BE,(SDL_IOStream *a, Uint32 b),(a,b),return)
 SDL_DYNAPI_PROC(SDL_bool,SDL_WriteU32BE,(SDL_IOStream *a, Uint32 b),(a,b),return)

+ 120 - 0
src/video/SDL_surface.c

@@ -2459,6 +2459,126 @@ int SDL_ReadSurfacePixelFloat(SDL_Surface *surface, int x, int y, float *r, floa
     return result;
     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.
  * Free a surface created by the above function.
  */
  */