summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
committer3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
commit6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch)
tree34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels
parent8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff)
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels')
-rw-r--r--src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/README.txt12
-rw-r--r--src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/onmouseover.webpbin0 -> 482380 bytes
-rw-r--r--src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/read-pixels.c178
-rw-r--r--src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/thumbnail.pngbin0 -> 102838 bytes
4 files changed, 190 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/README.txt b/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/README.txt
new file mode 100644
index 0000000..dd474e6
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/README.txt
@@ -0,0 +1,12 @@
1This example creates an SDL window and renderer, and draws a
2rotating texture to it, reads back the rendered pixels, converts them to
3black and white, and then draws the converted image to a corner of the
4screen.
5
6This isn't necessarily an efficient thing to do--in real life one might
7want to do this sort of thing with a render target--but it's just a visual
8example of how to use SDL_RenderReadPixels().
9
10A better, but less visual, use of SDL_RenderReadPixels() is to make
11screenshots: you grab the current contents of the screen, and save the pixels
12as a bitmap file or whatever.
diff --git a/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/onmouseover.webp b/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/onmouseover.webp
new file mode 100644
index 0000000..bb4e5c4
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/onmouseover.webp
Binary files differ
diff --git a/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/read-pixels.c b/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/read-pixels.c
new file mode 100644
index 0000000..556b490
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/read-pixels.c
@@ -0,0 +1,178 @@
1/*
2 * This example creates an SDL window and renderer, and draws a
3 * rotating texture to it, reads back the rendered pixels, converts them to
4 * black and white, and then draws the converted image to a corner of the
5 * screen.
6 *
7 * This isn't necessarily an efficient thing to do--in real life one might
8 * want to do this sort of thing with a render target--but it's just a visual
9 * example of how to use SDL_RenderReadPixels().
10 *
11 * This code is public domain. Feel free to use it for any purpose!
12 */
13
14#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
15#include <SDL3/SDL.h>
16#include <SDL3/SDL_main.h>
17
18/* We will use this renderer to draw into this window every frame. */
19static SDL_Window *window = NULL;
20static SDL_Renderer *renderer = NULL;
21static SDL_Texture *texture = NULL;
22static int texture_width = 0;
23static int texture_height = 0;
24static SDL_Texture *converted_texture = NULL;
25static int converted_texture_width = 0;
26static int converted_texture_height = 0;
27
28#define WINDOW_WIDTH 640
29#define WINDOW_HEIGHT 480
30
31/* This function runs once at startup. */
32SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
33{
34 SDL_Surface *surface = NULL;
35 char *bmp_path = NULL;
36
37 SDL_SetAppMetadata("Example Renderer Read Pixels", "1.0", "com.example.renderer-read-pixels");
38
39 if (!SDL_Init(SDL_INIT_VIDEO)) {
40 SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
41 return SDL_APP_FAILURE;
42 }
43
44 if (!SDL_CreateWindowAndRenderer("examples/renderer/read-pixels", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) {
45 SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
46 return SDL_APP_FAILURE;
47 }
48
49 /* Textures are pixel data that we upload to the video hardware for fast drawing. Lots of 2D
50 engines refer to these as "sprites." We'll do a static texture (upload once, draw many
51 times) with data from a bitmap file. */
52
53 /* SDL_Surface is pixel data the CPU can access. SDL_Texture is pixel data the GPU can access.
54 Load a .bmp into a surface, move it to a texture from there. */
55 SDL_asprintf(&bmp_path, "%ssample.bmp", SDL_GetBasePath()); /* allocate a string of the full file path */
56 surface = SDL_LoadBMP(bmp_path);
57 if (!surface) {
58 SDL_Log("Couldn't load bitmap: %s", SDL_GetError());
59 return SDL_APP_FAILURE;
60 }
61
62 SDL_free(bmp_path); /* done with this, the file is loaded. */
63
64 texture_width = surface->w;
65 texture_height = surface->h;
66
67 texture = SDL_CreateTextureFromSurface(renderer, surface);
68 if (!texture) {
69 SDL_Log("Couldn't create static texture: %s", SDL_GetError());
70 return SDL_APP_FAILURE;
71 }
72
73 SDL_DestroySurface(surface); /* done with this, the texture has a copy of the pixels now. */
74
75 return SDL_APP_CONTINUE; /* carry on with the program! */
76}
77
78/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
79SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
80{
81 if (event->type == SDL_EVENT_QUIT) {
82 return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
83 }
84 return SDL_APP_CONTINUE; /* carry on with the program! */
85}
86
87/* This function runs once per frame, and is the heart of the program. */
88SDL_AppResult SDL_AppIterate(void *appstate)
89{
90 const Uint64 now = SDL_GetTicks();
91 SDL_Surface *surface;
92 SDL_FPoint center;
93 SDL_FRect dst_rect;
94
95 /* we'll have a texture rotate around over 2 seconds (2000 milliseconds). 360 degrees in a circle! */
96 const float rotation = (((float) ((int) (now % 2000))) / 2000.0f) * 360.0f;
97
98 /* as you can see from this, rendering draws over whatever was drawn before it. */
99 SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); /* black, full alpha */
100 SDL_RenderClear(renderer); /* start with a blank canvas. */
101
102 /* Center this one, and draw it with some rotation so it spins! */
103 dst_rect.x = ((float) (WINDOW_WIDTH - texture_width)) / 2.0f;
104 dst_rect.y = ((float) (WINDOW_HEIGHT - texture_height)) / 2.0f;
105 dst_rect.w = (float) texture_width;
106 dst_rect.h = (float) texture_height;
107 /* rotate it around the center of the texture; you can rotate it from a different point, too! */
108 center.x = texture_width / 2.0f;
109 center.y = texture_height / 2.0f;
110 SDL_RenderTextureRotated(renderer, texture, NULL, &dst_rect, rotation, &center, SDL_FLIP_NONE);
111
112 /* this next whole thing is _super_ expensive. Seriously, don't do this in real life. */
113
114 /* Download the pixels of what has just been rendered. This has to wait for the GPU to finish rendering it and everything before it,
115 and then make an expensive copy from the GPU to system RAM! */
116 surface = SDL_RenderReadPixels(renderer, NULL);
117
118 /* This is also expensive, but easier: convert the pixels to a format we want. */
119 if (surface && (surface->format != SDL_PIXELFORMAT_RGBA8888) && (surface->format != SDL_PIXELFORMAT_BGRA8888)) {
120 SDL_Surface *converted = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA8888);
121 SDL_DestroySurface(surface);
122 surface = converted;
123 }
124
125 if (surface) {
126 /* Rebuild converted_texture if the dimensions have changed (window resized, etc). */
127 if ((surface->w != converted_texture_width) || (surface->h != converted_texture_height)) {
128 SDL_DestroyTexture(converted_texture);
129 converted_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, surface->w, surface->h);
130 if (!converted_texture) {
131 SDL_Log("Couldn't (re)create conversion texture: %s", SDL_GetError());
132 return SDL_APP_FAILURE;
133 }
134 converted_texture_width = surface->w;
135 converted_texture_height = surface->h;
136 }
137
138 /* Turn each pixel into either black or white. This is a lousy technique but it works here.
139 In real life, something like Floyd-Steinberg dithering might work
140 better: https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering*/
141 int x, y;
142 for (y = 0; y < surface->h; y++) {
143 Uint32 *pixels = (Uint32 *) (((Uint8 *) surface->pixels) + (y * surface->pitch));
144 for (x = 0; x < surface->w; x++) {
145 Uint8 *p = (Uint8 *) (&pixels[x]);
146 const Uint32 average = (((Uint32) p[1]) + ((Uint32) p[2]) + ((Uint32) p[3])) / 3;
147 if (average == 0) {
148 p[0] = p[3] = 0xFF; p[1] = p[2] = 0; /* make pure black pixels red. */
149 } else {
150 p[1] = p[2] = p[3] = (average > 50) ? 0xFF : 0x00; /* make everything else either black or white. */
151 }
152 }
153 }
154
155 /* upload the processed pixels back into a texture. */
156 SDL_UpdateTexture(converted_texture, NULL, surface->pixels, surface->pitch);
157 SDL_DestroySurface(surface);
158
159 /* draw the texture to the top-left of the screen. */
160 dst_rect.x = dst_rect.y = 0.0f;
161 dst_rect.w = ((float) WINDOW_WIDTH) / 4.0f;
162 dst_rect.h = ((float) WINDOW_HEIGHT) / 4.0f;
163 SDL_RenderTexture(renderer, converted_texture, NULL, &dst_rect);
164 }
165
166 SDL_RenderPresent(renderer); /* put it all on the screen! */
167
168 return SDL_APP_CONTINUE; /* carry on with the program! */
169}
170
171/* This function runs once at shutdown. */
172void SDL_AppQuit(void *appstate, SDL_AppResult result)
173{
174 SDL_DestroyTexture(converted_texture);
175 SDL_DestroyTexture(texture);
176 /* SDL will clean up the window/renderer for us. */
177}
178
diff --git a/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/thumbnail.png b/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/thumbnail.png
new file mode 100644
index 0000000..8da02ac
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/examples/renderer/17-read-pixels/thumbnail.png
Binary files differ