Skip to content

Commit c9e2e73

Browse files
authored
examples: Add blending example (#15657)
1 parent f9380e1 commit c9e2e73

6 files changed

Lines changed: 252 additions & 0 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup Label="Globals">
4+
<ProjectGuid>{B938A3C0-6C64-4734-B705-ED3642C01B47}</ProjectGuid>
5+
</PropertyGroup>
6+
<Import Project="$(SolutionDir)\examples\Examples.props" />
7+
<ItemGroup>
8+
<None Include="$(SolutionDir)\..\examples\renderer\20-blending\README.txt" />
9+
<ClCompile Include="$(SolutionDir)\..\examples\renderer\20-blending\blending.c" />
10+
</ItemGroup>
11+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
12+
</Project>

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ add_sdl_example_executable(renderer-cliprect SOURCES renderer/15-cliprect/clipre
142142
add_sdl_example_executable(renderer-read-pixels SOURCES renderer/17-read-pixels/read-pixels.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.png)
143143
add_sdl_example_executable(renderer-debug-text SOURCES renderer/18-debug-text/debug-text.c)
144144
add_sdl_example_executable(renderer-affine-textures SOURCES renderer/19-affine-textures/affine-textures.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.png)
145+
add_sdl_example_executable(renderer-blending SOURCES renderer/20-blending/blending.c)
145146
add_sdl_example_executable(audio-simple-playback SOURCES audio/01-simple-playback/simple-playback.c)
146147
add_sdl_example_executable(audio-simple-playback-callback SOURCES audio/02-simple-playback-callback/simple-playback-callback.c)
147148
add_sdl_example_executable(audio-load-wav SOURCES audio/03-load-wav/load-wav.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.wav)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
This example uses SDL_SetTextureBlendMode() to apply blending to textures,
2+
and SDL_ComposeCustomBlendMode() to create a custom blend mode.
3+
4+
You can also use SDL_SetRenderDrawBlendMode() to apply blending to the
5+
entire renderer, but it only affects filled rects and lines, not texture
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
/*
2+
* Blending combines a source color 'src',
3+
* with the pixels already on the screen 'dst',
4+
* to produce transparency and other visual effects.
5+
*
6+
* formula: dst := (a * dst) op (b * src)
7+
*
8+
* where:
9+
* dst: existed pixel on the screen.
10+
* src: new pixel.
11+
* a: dst factor.
12+
* b: src factor.
13+
* op: blend operation (usually addition).
14+
*
15+
* In graphics programming, color and alpha are usually blended separately:
16+
* dstRGB := (a * srcRGB) op (b * dstRGB)
17+
* dstA := (c * srcA) op (d * dstA)
18+
*
19+
* This example uses SDL_SetTextureBlendMode() to apply blending to textures,
20+
* and uses SDL_ComposeCustomBlendMode() to create a custom blend mode.
21+
*
22+
* You can also use SDL_SetRenderDrawBlendMode() to apply blending to the
23+
* entire renderer, but it only affects filled rects and lines, not textures.
24+
*
25+
* This code is public domain. Feel free to use it for any purpose!
26+
*/
27+
28+
29+
#define SDL_MAIN_USE_CALLBACKS 1
30+
#include <SDL3/SDL.h>
31+
#include <SDL3/SDL_main.h>
32+
33+
#define WINDOW_WIDTH 640
34+
#define WINDOW_HEIGHT 480
35+
36+
/* UI Constants */
37+
#define ROWS 2
38+
#define COLS 3
39+
#define GRID_SIZE ((WINDOW_WIDTH - 1) / 18.0f)
40+
#define PANEL_SIZE (GRID_SIZE * 4)
41+
#define ROW_OFFSET ((WINDOW_HEIGHT - ROWS * PANEL_SIZE) / 4)
42+
#define COL_OFFSET (GRID_SIZE * COLS)
43+
#define RECT_SIZE 50.0f
44+
#define RED_OFFSET (GRID_SIZE)
45+
#define GREEN_OFFSET (RECT_SIZE / 3 + GRID_SIZE)
46+
#define BLUE_OFFSET (RECT_SIZE * 2 / 3 + GRID_SIZE)
47+
48+
static SDL_FRect panels[ROWS*COLS];
49+
static SDL_Window *window = NULL;
50+
static SDL_Renderer *renderer = NULL;
51+
static SDL_Texture *red_rect_texture = NULL;
52+
static SDL_Texture *green_rect_texture = NULL;
53+
static SDL_Texture *blue_rect_texture = NULL;
54+
static Uint8 alpha = 255;
55+
static SDL_BlendMode blend_modes[] = {
56+
/*The default no blending: dstRGB := srcRGB
57+
dstA := srcA */
58+
SDL_BLENDMODE_NONE,
59+
60+
/* Alpha blending: dstRGB := srcA * srcRGB + (1 - srcA) * dstRGB
61+
dstA := srcA + (1 - srcA) * dstA */
62+
SDL_BLENDMODE_BLEND,
63+
64+
/* Additive blending: dstRGB := srcRGB + dstRGB
65+
dstA := srcA + dstA */
66+
SDL_BLENDMODE_ADD,
67+
68+
/* Modulate blending: dstRGB := srcRGB * dstRGB
69+
dstA := dstA */
70+
SDL_BLENDMODE_MOD,
71+
72+
/* Multiply blending: dstRGB := srcRGB * dstRGB + (1 - srcA) * dstRGB
73+
dstA := dstA */
74+
SDL_BLENDMODE_MUL,
75+
76+
/* Our custom blending 'Screen Blending': dstRGB := 1 - (1 - dstRGB) * (1 - srcRGB)
77+
dstA := dstA */
78+
0
79+
};
80+
static const char *blend_mode_names[] = { "NONE", "BLEND", "ADD", "MOD", "MUL", "SCREEN \"CUSTOM\"" };
81+
82+
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
83+
{
84+
SDL_Surface *surface = NULL;
85+
86+
SDL_SetAppMetadata("Example Blending", "1.0", "com.example.blending");
87+
if (!SDL_Init(SDL_INIT_VIDEO)) {
88+
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
89+
return SDL_APP_FAILURE;
90+
}
91+
if (!SDL_CreateWindowAndRenderer("examples/renderer/blending", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
92+
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
93+
return SDL_APP_FAILURE;
94+
}
95+
SDL_SetRenderLogicalPresentation(renderer, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_LOGICAL_PRESENTATION_LETTERBOX);
96+
97+
int row = 0;
98+
int col = 0;
99+
for (row = 0; row < ROWS; row++)
100+
{
101+
for (col = 0; col < COLS; col++)
102+
{
103+
panels[col + row*COLS] = (SDL_FRect){ col*PANEL_SIZE + col*COL_OFFSET, row*PANEL_SIZE + (row+1)*ROW_OFFSET, PANEL_SIZE, PANEL_SIZE };
104+
}
105+
}
106+
107+
/* Create 'screen blend' mode */
108+
blend_modes[ROWS*COLS - 1] = SDL_ComposeCustomBlendMode(
109+
SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR, /* srcRGB factor := (1 - dstRGB) */
110+
SDL_BLENDFACTOR_ONE, /* dstRGB factor := 1 */
111+
SDL_BLENDOPERATION_ADD, /* RGB operation := + */
112+
SDL_BLENDFACTOR_ZERO, /* srcA factor := 0 */
113+
SDL_BLENDFACTOR_ONE, /* dstA factor := dstA */
114+
SDL_BLENDOPERATION_ADD /* A operation := + */
115+
);
116+
117+
surface = SDL_CreateSurface((int)RECT_SIZE, (int)RECT_SIZE, SDL_PIXELFORMAT_RGBA8888);
118+
if (!surface) {
119+
SDL_Log("Couldn't create surface: %s", SDL_GetError());
120+
return SDL_APP_FAILURE;
121+
}
122+
123+
SDL_FillSurfaceRect(surface, NULL, 0xFF0000FF); /* Red */
124+
red_rect_texture = SDL_CreateTextureFromSurface(renderer, surface);
125+
if (!red_rect_texture) {
126+
SDL_Log("Couldn't create texture: %s", SDL_GetError());
127+
return SDL_APP_FAILURE;
128+
}
129+
130+
SDL_FillSurfaceRect(surface, NULL, 0x00FF00FF); /* Green */
131+
green_rect_texture = SDL_CreateTextureFromSurface(renderer, surface);
132+
if (!green_rect_texture) {
133+
SDL_Log("Couldn't create texture: %s", SDL_GetError());
134+
return SDL_APP_FAILURE;
135+
}
136+
137+
SDL_FillSurfaceRect(surface, NULL, 0x0000FFFF); /* Blue */
138+
blue_rect_texture = SDL_CreateTextureFromSurface(renderer, surface);
139+
if (!blue_rect_texture) {
140+
SDL_Log("Couldn't create texture: %s", SDL_GetError());
141+
return SDL_APP_FAILURE;
142+
}
143+
144+
SDL_DestroySurface(surface);
145+
146+
return SDL_APP_CONTINUE;
147+
}
148+
149+
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
150+
{
151+
if (event->type == SDL_EVENT_QUIT) {
152+
return SDL_APP_SUCCESS;
153+
}
154+
if (event->type == SDL_EVENT_KEY_DOWN) {
155+
/* UP arrow increase alpha */
156+
if (event->key.key == SDLK_UP && alpha <= 255-8) alpha += 8;
157+
/* DOWN arrow decrease alpha */
158+
if (event->key.key == SDLK_DOWN && alpha >= 8) alpha -= 8;
159+
}
160+
return SDL_APP_CONTINUE;
161+
}
162+
163+
SDL_AppResult SDL_AppIterate(void *appstate)
164+
{
165+
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
166+
SDL_RenderClear(renderer);
167+
168+
int i = 0;
169+
float x;
170+
float y;
171+
/* Render checkerboard panels */
172+
for (i = 0; i < ROWS*COLS; i++)
173+
{
174+
/* Loop through the panel pixels */
175+
for (y = panels[i].y; y < PANEL_SIZE + panels[i].y; y += GRID_SIZE)
176+
{
177+
for (x = panels[i].x; x < PANEL_SIZE + panels[i].x; x += GRID_SIZE)
178+
{
179+
SDL_FRect grid = { x, y, GRID_SIZE, GRID_SIZE };
180+
bool dark = (int)(x/GRID_SIZE + y/GRID_SIZE) % 2;
181+
182+
if (dark) SDL_SetRenderDrawColor(renderer, 70, 70, 70, 255); /* Darker color */
183+
else SDL_SetRenderDrawColor(renderer, 110, 110, 110, 255); /* Lighter color */
184+
185+
SDL_RenderFillRect(renderer, &grid);
186+
}
187+
}
188+
189+
/* Label the blend mode */
190+
SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
191+
SDL_RenderDebugText(renderer, panels[i].x, panels[i].y - 15, blend_mode_names[i]);
192+
}
193+
194+
/* Render panels */
195+
SDL_RenderRects(renderer, panels, ROWS*COLS);
196+
197+
/* Render UI text */
198+
SDL_RenderDebugText(renderer, WINDOW_WIDTH - 176, WINDOW_HEIGHT - 20, "UP/DOWN: CHANGE ALPHA");
199+
SDL_RenderDebugTextFormat(renderer, 0, WINDOW_HEIGHT - 20, "ALPHA: %d", alpha);
200+
201+
/* Update textures alpha mod */
202+
SDL_SetTextureAlphaMod(red_rect_texture, alpha);
203+
SDL_SetTextureAlphaMod(green_rect_texture, alpha);
204+
SDL_SetTextureAlphaMod(blue_rect_texture, alpha);
205+
206+
/* Render panels */
207+
for (i = 0; i < ROWS*COLS; i++) {
208+
/* Update rects destination */
209+
SDL_FRect red_dst = { panels[i].x + RED_OFFSET, panels[i].y + RED_OFFSET, RECT_SIZE, RECT_SIZE };
210+
SDL_FRect green_dst = { panels[i].x + GREEN_OFFSET, panels[i].y + GREEN_OFFSET, RECT_SIZE, RECT_SIZE };
211+
SDL_FRect blue_dst = { panels[i].x + BLUE_OFFSET, panels[i].y + BLUE_OFFSET, RECT_SIZE, RECT_SIZE };
212+
213+
/* Apply the current blend mode */
214+
SDL_SetTextureBlendMode(red_rect_texture, blend_modes[i]);
215+
SDL_SetTextureBlendMode(green_rect_texture, blend_modes[i]);
216+
SDL_SetTextureBlendMode(blue_rect_texture, blend_modes[i]);
217+
218+
/* Render textures */
219+
SDL_RenderTexture(renderer, red_rect_texture, NULL, &red_dst);
220+
SDL_RenderTexture(renderer, green_rect_texture, NULL, &green_dst);
221+
SDL_RenderTexture(renderer, blue_rect_texture, NULL, &blue_dst);
222+
}
223+
224+
SDL_RenderPresent(renderer);
225+
226+
return SDL_APP_CONTINUE;
227+
}
228+
229+
void SDL_AppQuit(void *appstate, SDL_AppResult result)
230+
{
231+
SDL_DestroyTexture(red_rect_texture);
232+
SDL_DestroyTexture(green_rect_texture);
233+
SDL_DestroyTexture(blue_rect_texture);
234+
}
147 KB
Loading
11.4 KB
Loading

0 commit comments

Comments
 (0)