diff --git a/VisualC/examples/renderer/20-blending/20-blending.vcxproj b/VisualC/examples/renderer/20-blending/20-blending.vcxproj new file mode 100644 index 0000000000..ff89bd3e0d --- /dev/null +++ b/VisualC/examples/renderer/20-blending/20-blending.vcxproj @@ -0,0 +1,12 @@ + + + + {B938A3C0-6C64-4734-B705-ED3642C01B47} + + + + + + + + \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ca88933009..752eb640e3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -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) diff --git a/examples/renderer/20-blending/README.txt b/examples/renderer/20-blending/README.txt new file mode 100644 index 0000000000..fb7ae5333b --- /dev/null +++ b/examples/renderer/20-blending/README.txt @@ -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 diff --git a/examples/renderer/20-blending/blending.c b/examples/renderer/20-blending/blending.c new file mode 100644 index 0000000000..53701fb969 --- /dev/null +++ b/examples/renderer/20-blending/blending.c @@ -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 +#include + +#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); +} diff --git a/examples/renderer/20-blending/onmouseover.webp b/examples/renderer/20-blending/onmouseover.webp new file mode 100644 index 0000000000..dc1e2d94df Binary files /dev/null and b/examples/renderer/20-blending/onmouseover.webp differ diff --git a/examples/renderer/20-blending/thumbnail.png b/examples/renderer/20-blending/thumbnail.png new file mode 100644 index 0000000000..a5595d8811 Binary files /dev/null and b/examples/renderer/20-blending/thumbnail.png differ