testshape: now uses SDL_WINDOW_TRANSPARENT instead of the shaped window API

This commit is contained in:
Sylvain 2023-03-11 13:53:54 +01:00 committed by Sylvain Becker
parent 2cafa52598
commit f1d9c36136
1 changed files with 168 additions and 5 deletions

View File

@ -24,7 +24,129 @@ typedef struct LoadedPicture
const char *name;
} LoadedPicture;
void render(SDL_Renderer *renderer, SDL_Texture *texture)
static Uint8 *g_bitmap = NULL;
static int g_bitmap_w = 0, g_bitmap_h = 0;
static SDL_Surface *g_shape_surface = NULL;
static SDL_Texture *g_shape_texture = NULL;
/* REQUIRES that bitmap point to a w-by-h bitmap with ppb pixels-per-byte. */
static void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode, SDL_Surface *shape, Uint8 *bitmap, Uint8 ppb)
{
int x = 0;
int y = 0;
Uint8 r = 0, g = 0, b = 0, alpha = 0;
Uint8 *pixel = NULL;
Uint32 pixel_value = 0, mask_value = 0;
size_t bytes_per_scanline = (size_t)(shape->w + (ppb - 1)) / ppb;
Uint8 *bitmap_scanline;
SDL_Color key;
if (SDL_MUSTLOCK(shape)) {
SDL_LockSurface(shape);
}
SDL_memset(bitmap, 0, shape->h * bytes_per_scanline);
for (y = 0; y < shape->h; y++) {
bitmap_scanline = bitmap + y * bytes_per_scanline;
for (x = 0; x < shape->w; x++) {
alpha = 0;
pixel_value = 0;
pixel = (Uint8 *)(shape->pixels) + (y * shape->pitch) + (x * shape->format->BytesPerPixel);
switch (shape->format->BytesPerPixel) {
case (1):
pixel_value = *pixel;
break;
case (2):
pixel_value = *(Uint16 *)pixel;
break;
case (3):
pixel_value = *(Uint32 *)pixel & (~shape->format->Amask);
break;
case (4):
pixel_value = *(Uint32 *)pixel;
break;
}
SDL_GetRGBA(pixel_value, shape->format, &r, &g, &b, &alpha);
switch (mode.mode) {
case (ShapeModeDefault):
mask_value = (alpha >= 1 ? 1 : 0);
break;
case (ShapeModeBinarizeAlpha):
mask_value = (alpha >= mode.parameters.binarizationCutoff ? 1 : 0);
break;
case (ShapeModeReverseBinarizeAlpha):
mask_value = (alpha <= mode.parameters.binarizationCutoff ? 1 : 0);
break;
case (ShapeModeColorKey):
key = mode.parameters.colorKey;
mask_value = ((key.r != r || key.g != g || key.b != b) ? 1 : 0);
break;
}
bitmap_scanline[x / ppb] |= mask_value << (x % ppb);
}
}
if (SDL_MUSTLOCK(shape)) {
SDL_UnlockSurface(shape);
}
}
static int SDL3_SetWindowShape(SDL_Window *window, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode)
{
if (g_bitmap) {
SDL_free(g_bitmap);
g_bitmap = NULL;
}
if (g_shape_texture) {
SDL_DestroyTexture(g_shape_texture);
g_shape_texture = NULL;
}
if (g_shape_surface) {
SDL_DestroySurface(g_shape_surface);
g_shape_surface = NULL;
}
if (shape == NULL) {
return SDL_SetError("shape");
}
if (shape_mode == NULL) {
return SDL_SetError("shape_mode");
}
g_bitmap_w = shape->w;
g_bitmap_h = shape->h;
g_bitmap = (Uint8*) SDL_malloc(shape->w * shape->h);
if (g_bitmap == NULL) {
return SDL_OutOfMemory();
}
SDL_CalculateShapeBitmap(*shape_mode, shape, g_bitmap, 1);
g_shape_surface = SDL_CreateSurface(g_bitmap_w, g_bitmap_h, SDL_PIXELFORMAT_ABGR8888);
if (g_shape_surface) {
int x, y, i = 0;
Uint32 *ptr = g_shape_surface->pixels;
for (y = 0; y < g_bitmap_h; y++) {
for (x = 0; x < g_bitmap_w; x++) {
Uint8 val = g_bitmap[i++];
if (val == 0) {
ptr[x] = 0;
} else {
ptr[x] = 0xffffffff;
}
}
ptr = (Uint32 *)((Uint8 *)ptr + g_shape_surface->pitch);
}
}
return 0;
}
static void render(SDL_Renderer *renderer, SDL_Texture *texture)
{
/* Clear render-target to blue. */
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0xff, 0xff);
@ -32,6 +154,45 @@ void render(SDL_Renderer *renderer, SDL_Texture *texture)
/* Render the texture. */
SDL_RenderTexture(renderer, texture, NULL, NULL);
/* Apply the shape */
if (g_shape_surface) {
SDL_RendererInfo info;
SDL_GetRendererInfo(renderer, &info);
if (info.flags & SDL_RENDERER_SOFTWARE) {
if (g_bitmap) {
int x, y, i = 0;
Uint8 r, g, b, a;
SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
for (y = 0; y < g_bitmap_h; y++) {
for (x = 0; x < g_bitmap_w; x++) {
Uint8 val = g_bitmap[i++];
if (val == 0) {
SDL_RenderPoint(renderer, (float)x, (float)y);
}
}
}
SDL_SetRenderDrawColor(renderer, r, g, b, a);
}
} else {
if (g_shape_texture == NULL) {
SDL_BlendMode bm;
g_shape_texture = SDL_CreateTextureFromSurface(renderer, g_shape_surface);
/* if Alpha is 0, set all to 0, else leave unchanged. */
bm = SDL_ComposeCustomBlendMode(
SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD,
SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD);
SDL_SetTextureBlendMode(g_shape_texture, bm);
}
SDL_RenderTexture(renderer, g_shape_texture, NULL, NULL);
}
}
SDL_RenderPresent(renderer);
}
@ -52,6 +213,9 @@ int main(int argc, char **argv)
Uint32 pixelFormat = 0;
int w, h, access = 0;
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
// SDL_SetHint(SDL_HINT_VIDEO_FORCE_EGL, "0");
/* Enable standard application logging */
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
@ -103,8 +267,7 @@ int main(int argc, char **argv)
}
}
window = SDL_CreateShapedWindow("SDL_Shape test",
SHAPED_WINDOW_DIMENSION, SHAPED_WINDOW_DIMENSION, 0);
window = SDL_CreateWindow("SDL_Shape test", SHAPED_WINDOW_DIMENSION, SHAPED_WINDOW_DIMENSION, SDL_WINDOW_TRANSPARENT);
if (window == NULL) {
for (i = 0; i < num_pictures; i++) {
SDL_DestroySurface(pictures[i].surface);
@ -156,7 +319,7 @@ int main(int argc, char **argv)
SDL_QueryTexture(pictures[current_picture].texture, &pixelFormat, &access, &w, &h);
/* We want to set the window size in pixels */
SDL_SetWindowSize(window, (int)SDL_ceilf(w / mode->display_scale), (int)SDL_ceilf(h / mode->display_scale));
SDL_SetWindowShape(window, pictures[current_picture].surface, &pictures[current_picture].mode);
SDL3_SetWindowShape(window, pictures[current_picture].surface, &pictures[current_picture].mode);
while (should_exit == 0) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_EVENT_KEY_DOWN) {
@ -175,7 +338,7 @@ int main(int argc, char **argv)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Changing to shaped bmp: %s", pictures[current_picture].name);
SDL_QueryTexture(pictures[current_picture].texture, &pixelFormat, &access, &w, &h);
SDL_SetWindowSize(window, (int)SDL_ceilf(w / mode->display_scale), (int)SDL_ceilf(h / mode->display_scale));
SDL_SetWindowShape(window, pictures[current_picture].surface, &pictures[current_picture].mode);
SDL3_SetWindowShape(window, pictures[current_picture].surface, &pictures[current_picture].mode);
}
if (event.type == SDL_EVENT_QUIT) {
should_exit = 1;