FifeGUI 0.2.0
A C++ GUI library designed for games.
pixel.hpp
1// SPDX-License-Identifier: LGPL-2.1-or-later OR BSD-3-Clause
2// SPDX-FileCopyrightText: 2004 - 2008 Olof Naessén and Per Larsson
3// SPDX-FileCopyrightText: 2013 - 2026 Fifengine contributors
4
5#ifndef INCLUDE_FIFECHAN_BACKENDS_SDL_SDLPIXEL_HPP_
6#define INCLUDE_FIFECHAN_BACKENDS_SDL_SDLPIXEL_HPP_
7
8#include <SDL2/SDL.h>
9
10#include <cstddef>
11#include <cstring>
12#include <span>
13
14#include "fifechan/color.hpp"
15
16namespace fcn::sdl2
17{
18
27 inline Color SDLgetPixel(SDL_Surface* surface, int x, int y)
28 {
29 int const bpp = surface->format->BytesPerPixel;
30
31 SDL_LockSurface(surface);
32
33 std::ptrdiff_t const offset = (static_cast<std::ptrdiff_t>(y) * static_cast<std::ptrdiff_t>(surface->pitch)) +
34 (static_cast<std::ptrdiff_t>(x) * static_cast<std::ptrdiff_t>(bpp));
35
36 std::span<Uint8 const> const pixels(
37 reinterpret_cast<Uint8*>(surface->pixels),
38 static_cast<size_t>(surface->h) * static_cast<size_t>(surface->pitch));
39 size_t const idx = static_cast<size_t>(offset);
40
41 unsigned int color = 0U;
42
43 switch (bpp) {
44 case 1:
45 color = pixels[idx];
46 break;
47
48 case 2: {
49 Uint16 tmp = 0;
50 std::memcpy(&tmp, &pixels[idx], sizeof(Uint16));
51 color = static_cast<unsigned int>(tmp);
52 break;
53 }
54
55 case 3:
56 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
57 color = (static_cast<unsigned int>(pixels[idx]) << 16) |
58 (static_cast<unsigned int>(pixels[idx + 1]) << 8) | static_cast<unsigned int>(pixels[idx + 2]);
59 } else {
60 color = static_cast<unsigned int>(pixels[idx]) | (static_cast<unsigned int>(pixels[idx + 1]) << 8) |
61 (static_cast<unsigned int>(pixels[idx + 2]) << 16);
62 }
63 break;
64
65 case 4: {
66 Uint32 tmp = 0;
67 std::memcpy(&tmp, &pixels[idx], sizeof(Uint32));
68 color = static_cast<unsigned int>(tmp);
69 break;
70 }
71
72 default:
73 break;
74 }
75
76 unsigned char r = 0;
77 unsigned char g = 0;
78 unsigned char b = 0;
79 unsigned char a = 0;
80
81 SDL_GetRGBA(color, surface->format, &r, &g, &b, &a);
82 SDL_UnlockSurface(surface);
83
84 return {r, g, b, a};
85 }
86
95 inline void SDLputPixel(SDL_Surface* surface, int x, int y, Color const & color)
96 {
97 int const bpp = surface->format->BytesPerPixel;
98
99 SDL_LockSurface(surface);
100
101 std::ptrdiff_t const offset = (static_cast<std::ptrdiff_t>(y) * static_cast<std::ptrdiff_t>(surface->pitch)) +
102 (static_cast<std::ptrdiff_t>(x) * static_cast<std::ptrdiff_t>(bpp));
103
104 std::span<Uint8> const pixels(
105 reinterpret_cast<Uint8*>(surface->pixels),
106 static_cast<size_t>(surface->h) * static_cast<size_t>(surface->pitch));
107 size_t const idx = static_cast<size_t>(offset);
108
109 Uint32 const pixel = SDL_MapRGB(surface->format, color.r, color.g, color.b);
110
111 switch (bpp) {
112 case 1:
113 pixels[idx] = static_cast<Uint8>(pixel);
114 break;
115
116 case 2: {
117 Uint16 tmp = static_cast<Uint16>(pixel);
118 std::memcpy(&pixels[idx], &tmp, sizeof(Uint16));
119 break;
120 }
121
122 case 3:
123 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
124 pixels[idx] = static_cast<Uint8>((pixel >> 16) & 0xff);
125 pixels[idx + 1] = static_cast<Uint8>((pixel >> 8) & 0xff);
126 pixels[idx + 2] = static_cast<Uint8>(pixel & 0xff);
127 } else {
128 pixels[idx] = static_cast<Uint8>(pixel & 0xff);
129 pixels[idx + 1] = static_cast<Uint8>((pixel >> 8) & 0xff);
130 pixels[idx + 2] = static_cast<Uint8>((pixel >> 16) & 0xff);
131 }
132 break;
133
134 case 4: {
135 Uint32 tmp = pixel;
136 std::memcpy(&pixels[idx], &tmp, sizeof(Uint32));
137 break;
138 }
139
140 default:
141 break;
142 }
143
144 SDL_UnlockSurface(surface);
145 }
146
154 template <typename T>
155 inline T SDLBlend(T source, T dest, unsigned char alpha)
156 {
157 return dest + ((source - dest) * alpha >> 8);
158 }
159
168 template <typename T>
169 inline T SDLBlendColor(T src, T dst, unsigned char alpha, SDL_PixelFormat const * f)
170 {
171 return (SDLBlend(src & f->Rmask, dst & f->Rmask, alpha) & f->Rmask) |
172 (SDLBlend(src & f->Gmask, dst & f->Gmask, alpha) & f->Gmask) |
173 (SDLBlend(src & f->Bmask, dst & f->Bmask, alpha) & f->Bmask);
174 }
175
176 /*
177 typedef struct{
178 SDL_Palette *palette;
179 Uint8 BitsPerPixel;
180 Uint8 BytesPerPixel;
181 Uint32 Rmask, Gmask, Bmask, Amask;
182 Uint8 Rshift, Gshift, Bshift, Ashift;
183 Uint8 Rloss, Gloss, Bloss, Aloss;
184 Uint32 colorkey;
185 Uint8 alpha;
186 } SDL_PixelFormat;
187 */
188
197 inline void SDLputPixelAlpha(SDL_Surface* surface, int x, int y, Color const & color)
198 {
199 // avoids overhead and truncation artifacts
200 if (color.a == 255) {
201 SDLputPixel(surface, x, y, color);
202 return;
203 }
204
205 int const bpp = surface->format->BytesPerPixel;
206
207 // avoids overhead and truncation artifacts
208 if (color.a == 255) {
209 SDLputPixel(surface, x, y, color);
210 return;
211 }
212
213 SDL_LockSurface(surface);
214
215 std::ptrdiff_t const offset = (static_cast<std::ptrdiff_t>(y) * static_cast<std::ptrdiff_t>(surface->pitch)) +
216 (static_cast<std::ptrdiff_t>(x) * static_cast<std::ptrdiff_t>(bpp));
217
218 std::span<Uint8> const pixels(
219 reinterpret_cast<Uint8*>(surface->pixels),
220 static_cast<size_t>(surface->h) * static_cast<size_t>(surface->pitch));
221 size_t const idx = static_cast<size_t>(offset);
222
223 switch (bpp) {
224 case 1: {
225 Uint32 const pixel = SDL_MapRGB(surface->format, color.r, color.g, color.b);
226
227 SDL_Color const * colors = surface->format->palette->colors;
228 SDL_Color const & sourceColor = colors[pixel];
229 SDL_Color const & destColor = colors[pixels[idx]];
230
231 pixels[idx] = static_cast<Uint8>(SDL_MapRGB(
232 surface->format,
233 SDLBlend(sourceColor.r, destColor.r, color.a),
234 SDLBlend(sourceColor.g, destColor.g, color.a),
235 SDLBlend(sourceColor.b, destColor.b, color.a)));
236 break;
237 }
238 case 2: {
239 Uint32 const pixel = SDL_MapRGB(surface->format, color.r, color.g, color.b);
240 Uint16 dest = 0;
241 std::memcpy(&dest, &pixels[idx], sizeof(Uint16));
242 Uint16 result = SDLBlendColor<Uint16>(pixel, dest, color.a, surface->format);
243 std::memcpy(&pixels[idx], &result, sizeof(Uint16));
244 break;
245 }
246 case 3: {
247 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
248 pixels[idx + 0] = SDLBlend<Uint8>(color.r, pixels[idx + 0], color.a);
249 pixels[idx + 1] = SDLBlend<Uint8>(color.g, pixels[idx + 1], color.a);
250 pixels[idx + 2] = SDLBlend<Uint8>(color.b, pixels[idx + 2], color.a);
251 } else {
252 pixels[idx + 0] = SDLBlend<Uint8>(color.b, pixels[idx + 0], color.a);
253 pixels[idx + 1] = SDLBlend<Uint8>(color.g, pixels[idx + 1], color.a);
254 pixels[idx + 2] = SDLBlend<Uint8>(color.r, pixels[idx + 2], color.a);
255 }
256 break;
257 }
258 case 4: {
259 Uint32 const pixel = SDL_MapRGB(surface->format, color.r, color.g, color.b);
260 Uint32 dest = 0;
261 std::memcpy(&dest, &pixels[idx], sizeof(Uint32));
262 Uint32 result = SDLBlendColor<Uint32>(pixel, dest, color.a, surface->format);
263 std::memcpy(&pixels[idx], &result, sizeof(Uint32));
264 break;
265 }
266
267 default:
268 break;
269 }
270
271 SDL_UnlockSurface(surface);
272 }
273} // namespace fcn::sdl2
274
275#endif // INCLUDE_FIFECHAN_BACKENDS_SDL_SDLPIXEL_HPP_
Color.
Definition color.hpp:56
uint8_t a
Alpha color component (0-255).
Definition color.hpp:322
uint8_t b
Blue color component (0-255).
Definition color.hpp:319
uint8_t g
Green color component (0-255).
Definition color.hpp:316
uint8_t r
Red color component (0-255).
Definition color.hpp:313
Unified header for the SDL backend.
T SDLBlendColor(T src, T dst, unsigned char alpha, SDL_PixelFormat const *f)
Blends two packed color values together using the supplied pixel format.
Definition pixel.hpp:169
T SDLBlend(T source, T dest, unsigned char alpha)
Blends two color components together.
Definition pixel.hpp:155
void SDLputPixelAlpha(SDL_Surface *surface, int x, int y, Color const &color)
Puts a pixel on an SDL_Surface with alpha blending.
Definition pixel.hpp:197
Color SDLgetPixel(SDL_Surface *surface, int x, int y)
Checks a pixels color of an SDL_Surface.
Definition pixel.hpp:27
void SDLputPixel(SDL_Surface *surface, int x, int y, Color const &color)
Puts a pixel on an SDL_Surface.
Definition pixel.hpp:95