mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-24 22:09:54 +00:00
examples: Add blending example (#15657)
This commit is contained in:
12
VisualC/examples/renderer/20-blending/20-blending.vcxproj
Normal file
12
VisualC/examples/renderer/20-blending/20-blending.vcxproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B938A3C0-6C64-4734-B705-ED3642C01B47}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)\examples\Examples.props" />
|
||||
<ItemGroup>
|
||||
<None Include="$(SolutionDir)\..\examples\renderer\20-blending\README.txt" />
|
||||
<ClCompile Include="$(SolutionDir)\..\examples\renderer\20-blending\blending.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
@@ -142,6 +142,7 @@ add_sdl_example_executable(renderer-cliprect SOURCES renderer/15-cliprect/clipre
|
||||
add_sdl_example_executable(renderer-read-pixels SOURCES renderer/17-read-pixels/read-pixels.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.png)
|
||||
add_sdl_example_executable(renderer-debug-text SOURCES renderer/18-debug-text/debug-text.c)
|
||||
add_sdl_example_executable(renderer-affine-textures SOURCES renderer/19-affine-textures/affine-textures.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.png)
|
||||
add_sdl_example_executable(renderer-blending SOURCES renderer/20-blending/blending.c)
|
||||
add_sdl_example_executable(audio-simple-playback SOURCES audio/01-simple-playback/simple-playback.c)
|
||||
add_sdl_example_executable(audio-simple-playback-callback SOURCES audio/02-simple-playback-callback/simple-playback-callback.c)
|
||||
add_sdl_example_executable(audio-load-wav SOURCES audio/03-load-wav/load-wav.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.wav)
|
||||
|
||||
5
examples/renderer/20-blending/README.txt
Normal file
5
examples/renderer/20-blending/README.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
This example uses SDL_SetTextureBlendMode() to apply blending to textures,
|
||||
and SDL_ComposeCustomBlendMode() to create a custom blend mode.
|
||||
|
||||
You can also use SDL_SetRenderDrawBlendMode() to apply blending to the
|
||||
entire renderer, but it only affects filled rects and lines, not texture
|
||||
234
examples/renderer/20-blending/blending.c
Normal file
234
examples/renderer/20-blending/blending.c
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Blending combines a source color 'src',
|
||||
* with the pixels already on the screen 'dst',
|
||||
* to produce transparency and other visual effects.
|
||||
*
|
||||
* formula: dst := (a * dst) op (b * src)
|
||||
*
|
||||
* where:
|
||||
* dst: existed pixel on the screen.
|
||||
* src: new pixel.
|
||||
* a: dst factor.
|
||||
* b: src factor.
|
||||
* op: blend operation (usually addition).
|
||||
*
|
||||
* In graphics programming, color and alpha are usually blended separately:
|
||||
* dstRGB := (a * srcRGB) op (b * dstRGB)
|
||||
* dstA := (c * srcA) op (d * dstA)
|
||||
*
|
||||
* This example uses SDL_SetTextureBlendMode() to apply blending to textures,
|
||||
* and uses SDL_ComposeCustomBlendMode() to create a custom blend mode.
|
||||
*
|
||||
* You can also use SDL_SetRenderDrawBlendMode() to apply blending to the
|
||||
* entire renderer, but it only affects filled rects and lines, not textures.
|
||||
*
|
||||
* This code is public domain. Feel free to use it for any purpose!
|
||||
*/
|
||||
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
|
||||
#define WINDOW_WIDTH 640
|
||||
#define WINDOW_HEIGHT 480
|
||||
|
||||
/* UI Constants */
|
||||
#define ROWS 2
|
||||
#define COLS 3
|
||||
#define GRID_SIZE ((WINDOW_WIDTH - 1) / 18.0f)
|
||||
#define PANEL_SIZE (GRID_SIZE * 4)
|
||||
#define ROW_OFFSET ((WINDOW_HEIGHT - ROWS * PANEL_SIZE) / 4)
|
||||
#define COL_OFFSET (GRID_SIZE * COLS)
|
||||
#define RECT_SIZE 50.0f
|
||||
#define RED_OFFSET (GRID_SIZE)
|
||||
#define GREEN_OFFSET (RECT_SIZE / 3 + GRID_SIZE)
|
||||
#define BLUE_OFFSET (RECT_SIZE * 2 / 3 + GRID_SIZE)
|
||||
|
||||
static SDL_FRect panels[ROWS*COLS];
|
||||
static SDL_Window *window = NULL;
|
||||
static SDL_Renderer *renderer = NULL;
|
||||
static SDL_Texture *red_rect_texture = NULL;
|
||||
static SDL_Texture *green_rect_texture = NULL;
|
||||
static SDL_Texture *blue_rect_texture = NULL;
|
||||
static Uint8 alpha = 255;
|
||||
static SDL_BlendMode blend_modes[] = {
|
||||
/*The default no blending: dstRGB := srcRGB
|
||||
dstA := srcA */
|
||||
SDL_BLENDMODE_NONE,
|
||||
|
||||
/* Alpha blending: dstRGB := srcA * srcRGB + (1 - srcA) * dstRGB
|
||||
dstA := srcA + (1 - srcA) * dstA */
|
||||
SDL_BLENDMODE_BLEND,
|
||||
|
||||
/* Additive blending: dstRGB := srcRGB + dstRGB
|
||||
dstA := srcA + dstA */
|
||||
SDL_BLENDMODE_ADD,
|
||||
|
||||
/* Modulate blending: dstRGB := srcRGB * dstRGB
|
||||
dstA := dstA */
|
||||
SDL_BLENDMODE_MOD,
|
||||
|
||||
/* Multiply blending: dstRGB := srcRGB * dstRGB + (1 - srcA) * dstRGB
|
||||
dstA := dstA */
|
||||
SDL_BLENDMODE_MUL,
|
||||
|
||||
/* Our custom blending 'Screen Blending': dstRGB := 1 - (1 - dstRGB) * (1 - srcRGB)
|
||||
dstA := dstA */
|
||||
0
|
||||
};
|
||||
static const char *blend_mode_names[] = { "NONE", "BLEND", "ADD", "MOD", "MUL", "SCREEN \"CUSTOM\"" };
|
||||
|
||||
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
{
|
||||
SDL_Surface *surface = NULL;
|
||||
|
||||
SDL_SetAppMetadata("Example Blending", "1.0", "com.example.blending");
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
if (!SDL_CreateWindowAndRenderer("examples/renderer/blending", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
|
||||
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
SDL_SetRenderLogicalPresentation(renderer, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
for (row = 0; row < ROWS; row++)
|
||||
{
|
||||
for (col = 0; col < COLS; col++)
|
||||
{
|
||||
panels[col + row*COLS] = (SDL_FRect){ col*PANEL_SIZE + col*COL_OFFSET, row*PANEL_SIZE + (row+1)*ROW_OFFSET, PANEL_SIZE, PANEL_SIZE };
|
||||
}
|
||||
}
|
||||
|
||||
/* Create 'screen blend' mode */
|
||||
blend_modes[ROWS*COLS - 1] = SDL_ComposeCustomBlendMode(
|
||||
SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR, /* srcRGB factor := (1 - dstRGB) */
|
||||
SDL_BLENDFACTOR_ONE, /* dstRGB factor := 1 */
|
||||
SDL_BLENDOPERATION_ADD, /* RGB operation := + */
|
||||
SDL_BLENDFACTOR_ZERO, /* srcA factor := 0 */
|
||||
SDL_BLENDFACTOR_ONE, /* dstA factor := dstA */
|
||||
SDL_BLENDOPERATION_ADD /* A operation := + */
|
||||
);
|
||||
|
||||
surface = SDL_CreateSurface((int)RECT_SIZE, (int)RECT_SIZE, SDL_PIXELFORMAT_RGBA8888);
|
||||
if (!surface) {
|
||||
SDL_Log("Couldn't create surface: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
SDL_FillSurfaceRect(surface, NULL, 0xFF0000FF); /* Red */
|
||||
red_rect_texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
if (!red_rect_texture) {
|
||||
SDL_Log("Couldn't create texture: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
SDL_FillSurfaceRect(surface, NULL, 0x00FF00FF); /* Green */
|
||||
green_rect_texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
if (!green_rect_texture) {
|
||||
SDL_Log("Couldn't create texture: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
SDL_FillSurfaceRect(surface, NULL, 0x0000FFFF); /* Blue */
|
||||
blue_rect_texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
if (!blue_rect_texture) {
|
||||
SDL_Log("Couldn't create texture: %s", SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
SDL_DestroySurface(surface);
|
||||
|
||||
return SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
return SDL_APP_SUCCESS;
|
||||
}
|
||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||
/* UP arrow increase alpha */
|
||||
if (event->key.key == SDLK_UP && alpha <= 255-8) alpha += 8;
|
||||
/* DOWN arrow decrease alpha */
|
||||
if (event->key.key == SDLK_DOWN && alpha >= 8) alpha -= 8;
|
||||
}
|
||||
return SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
{
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
int i = 0;
|
||||
float x;
|
||||
float y;
|
||||
/* Render checkerboard panels */
|
||||
for (i = 0; i < ROWS*COLS; i++)
|
||||
{
|
||||
/* Loop through the panel pixels */
|
||||
for (y = panels[i].y; y < PANEL_SIZE + panels[i].y; y += GRID_SIZE)
|
||||
{
|
||||
for (x = panels[i].x; x < PANEL_SIZE + panels[i].x; x += GRID_SIZE)
|
||||
{
|
||||
SDL_FRect grid = { x, y, GRID_SIZE, GRID_SIZE };
|
||||
bool dark = (int)(x/GRID_SIZE + y/GRID_SIZE) % 2;
|
||||
|
||||
if (dark) SDL_SetRenderDrawColor(renderer, 70, 70, 70, 255); /* Darker color */
|
||||
else SDL_SetRenderDrawColor(renderer, 110, 110, 110, 255); /* Lighter color */
|
||||
|
||||
SDL_RenderFillRect(renderer, &grid);
|
||||
}
|
||||
}
|
||||
|
||||
/* Label the blend mode */
|
||||
SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderDebugText(renderer, panels[i].x, panels[i].y - 15, blend_mode_names[i]);
|
||||
}
|
||||
|
||||
/* Render panels */
|
||||
SDL_RenderRects(renderer, panels, ROWS*COLS);
|
||||
|
||||
/* Render UI text */
|
||||
SDL_RenderDebugText(renderer, WINDOW_WIDTH - 176, WINDOW_HEIGHT - 20, "UP/DOWN: CHANGE ALPHA");
|
||||
SDL_RenderDebugTextFormat(renderer, 0, WINDOW_HEIGHT - 20, "ALPHA: %d", alpha);
|
||||
|
||||
/* Update textures alpha mod */
|
||||
SDL_SetTextureAlphaMod(red_rect_texture, alpha);
|
||||
SDL_SetTextureAlphaMod(green_rect_texture, alpha);
|
||||
SDL_SetTextureAlphaMod(blue_rect_texture, alpha);
|
||||
|
||||
/* Render panels */
|
||||
for (i = 0; i < ROWS*COLS; i++) {
|
||||
/* Update rects destination */
|
||||
SDL_FRect red_dst = { panels[i].x + RED_OFFSET, panels[i].y + RED_OFFSET, RECT_SIZE, RECT_SIZE };
|
||||
SDL_FRect green_dst = { panels[i].x + GREEN_OFFSET, panels[i].y + GREEN_OFFSET, RECT_SIZE, RECT_SIZE };
|
||||
SDL_FRect blue_dst = { panels[i].x + BLUE_OFFSET, panels[i].y + BLUE_OFFSET, RECT_SIZE, RECT_SIZE };
|
||||
|
||||
/* Apply the current blend mode */
|
||||
SDL_SetTextureBlendMode(red_rect_texture, blend_modes[i]);
|
||||
SDL_SetTextureBlendMode(green_rect_texture, blend_modes[i]);
|
||||
SDL_SetTextureBlendMode(blue_rect_texture, blend_modes[i]);
|
||||
|
||||
/* Render textures */
|
||||
SDL_RenderTexture(renderer, red_rect_texture, NULL, &red_dst);
|
||||
SDL_RenderTexture(renderer, green_rect_texture, NULL, &green_dst);
|
||||
SDL_RenderTexture(renderer, blue_rect_texture, NULL, &blue_dst);
|
||||
}
|
||||
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
return SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
void SDL_AppQuit(void *appstate, SDL_AppResult result)
|
||||
{
|
||||
SDL_DestroyTexture(red_rect_texture);
|
||||
SDL_DestroyTexture(green_rect_texture);
|
||||
SDL_DestroyTexture(blue_rect_texture);
|
||||
}
|
||||
BIN
examples/renderer/20-blending/onmouseover.webp
Normal file
BIN
examples/renderer/20-blending/onmouseover.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 147 KiB |
BIN
examples/renderer/20-blending/thumbnail.png
Normal file
BIN
examples/renderer/20-blending/thumbnail.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Reference in New Issue
Block a user