src/video/SDL_shape.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 30 Jan 2018 18:08:34 -0800
changeset 11839 971881e55d61
parent 11811 5d94cb6b24d3
child 12503 806492103856
permissions -rw-r--r--
Fixed ISO C99 compatibility
SDL now builds with gcc 7.2 with the following command line options:
-Wall -pedantic-errors -Wno-deprecated-declarations -Wno-overlength-strings --std=c99
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../SDL_internal.h"
    22 
    23 #include "SDL.h"
    24 #include "SDL_assert.h"
    25 #include "SDL_video.h"
    26 #include "SDL_sysvideo.h"
    27 #include "SDL_pixels.h"
    28 #include "SDL_surface.h"
    29 #include "SDL_shape.h"
    30 #include "SDL_shape_internals.h"
    31 
    32 SDL_Window*
    33 SDL_CreateShapedWindow(const char *title,unsigned int x,unsigned int y,unsigned int w,unsigned int h,Uint32 flags)
    34 {
    35     SDL_Window *result = NULL;
    36     result = SDL_CreateWindow(title,-1000,-1000,w,h,(flags | SDL_WINDOW_BORDERLESS) & (~SDL_WINDOW_FULLSCREEN) & (~SDL_WINDOW_RESIZABLE) /* & (~SDL_WINDOW_SHOWN) */);
    37     if(result != NULL) {
    38         if (SDL_GetVideoDevice()->shape_driver.CreateShaper == NULL) {
    39             SDL_DestroyWindow(result);
    40             return NULL;
    41         }
    42         result->shaper = SDL_GetVideoDevice()->shape_driver.CreateShaper(result);
    43         if(result->shaper != NULL) {
    44             result->shaper->userx = x;
    45             result->shaper->usery = y;
    46             result->shaper->mode.mode = ShapeModeDefault;
    47             result->shaper->mode.parameters.binarizationCutoff = 1;
    48             result->shaper->hasshape = SDL_FALSE;
    49             return result;
    50         }
    51         else {
    52             SDL_DestroyWindow(result);
    53             return NULL;
    54         }
    55     }
    56     else
    57         return NULL;
    58 }
    59 
    60 SDL_bool
    61 SDL_IsShapedWindow(const SDL_Window *window)
    62 {
    63     if(window == NULL)
    64         return SDL_FALSE;
    65     else
    66         return (SDL_bool)(window->shaper != NULL);
    67 }
    68 
    69 /* REQUIRES that bitmap point to a w-by-h bitmap with ppb pixels-per-byte. */
    70 void
    71 SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode,SDL_Surface *shape,Uint8* bitmap,Uint8 ppb)
    72 {
    73     int x = 0;
    74     int y = 0;
    75     Uint8 r = 0,g = 0,b = 0,alpha = 0;
    76     Uint8* pixel = NULL;
    77     Uint32 pixel_value = 0,mask_value = 0;
    78     int bytes_per_scanline = (shape->w + (ppb - 1)) / ppb;
    79     Uint8 *bitmap_scanline;
    80     SDL_Color key;
    81     if(SDL_MUSTLOCK(shape))
    82         SDL_LockSurface(shape);
    83     for(y = 0;y<shape->h;y++) {
    84         bitmap_scanline = bitmap + y * bytes_per_scanline;
    85         for(x=0;x<shape->w;x++) {
    86             alpha = 0;
    87             pixel_value = 0;
    88             pixel = (Uint8 *)(shape->pixels) + (y*shape->pitch) + (x*shape->format->BytesPerPixel);
    89             switch(shape->format->BytesPerPixel) {
    90                 case(1):
    91                     pixel_value = *(Uint8*)pixel;
    92                     break;
    93                 case(2):
    94                     pixel_value = *(Uint16*)pixel;
    95                     break;
    96                 case(3):
    97                     pixel_value = *(Uint32*)pixel & (~shape->format->Amask);
    98                     break;
    99                 case(4):
   100                     pixel_value = *(Uint32*)pixel;
   101                     break;
   102             }
   103             SDL_GetRGBA(pixel_value,shape->format,&r,&g,&b,&alpha);
   104             switch(mode.mode) {
   105                 case(ShapeModeDefault):
   106                     mask_value = (alpha >= 1 ? 1 : 0);
   107                     break;
   108                 case(ShapeModeBinarizeAlpha):
   109                     mask_value = (alpha >= mode.parameters.binarizationCutoff ? 1 : 0);
   110                     break;
   111                 case(ShapeModeReverseBinarizeAlpha):
   112                     mask_value = (alpha <= mode.parameters.binarizationCutoff ? 1 : 0);
   113                     break;
   114                 case(ShapeModeColorKey):
   115                     key = mode.parameters.colorKey;
   116                     mask_value = ((key.r != r || key.g != g || key.b != b) ? 1 : 0);
   117                     break;
   118             }
   119             bitmap_scanline[x / ppb] |= mask_value << (x % ppb);
   120         }
   121     }
   122     if(SDL_MUSTLOCK(shape))
   123         SDL_UnlockSurface(shape);
   124 }
   125 
   126 static SDL_ShapeTree*
   127 RecursivelyCalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* mask,SDL_Rect dimensions) {
   128     int x = 0,y = 0;
   129     Uint8* pixel = NULL;
   130     Uint32 pixel_value = 0;
   131     Uint8 r = 0,g = 0,b = 0,a = 0;
   132     SDL_bool pixel_opaque = SDL_FALSE;
   133     int last_opaque = -1;
   134     SDL_Color key;
   135     SDL_ShapeTree* result = (SDL_ShapeTree*)SDL_malloc(sizeof(SDL_ShapeTree));
   136     SDL_Rect next = {0,0,0,0};
   137 
   138     for(y=dimensions.y;y<dimensions.y + dimensions.h;y++) {
   139         for(x=dimensions.x;x<dimensions.x + dimensions.w;x++) {
   140             pixel_value = 0;
   141             pixel = (Uint8 *)(mask->pixels) + (y*mask->pitch) + (x*mask->format->BytesPerPixel);
   142             switch(mask->format->BytesPerPixel) {
   143                 case(1):
   144                     pixel_value = *(Uint8*)pixel;
   145                     break;
   146                 case(2):
   147                     pixel_value = *(Uint16*)pixel;
   148                     break;
   149                 case(3):
   150                     pixel_value = *(Uint32*)pixel & (~mask->format->Amask);
   151                     break;
   152                 case(4):
   153                     pixel_value = *(Uint32*)pixel;
   154                     break;
   155             }
   156             SDL_GetRGBA(pixel_value,mask->format,&r,&g,&b,&a);
   157             switch(mode.mode) {
   158                 case(ShapeModeDefault):
   159                     pixel_opaque = (a >= 1 ? SDL_TRUE : SDL_FALSE);
   160                     break;
   161                 case(ShapeModeBinarizeAlpha):
   162                     pixel_opaque = (a >= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
   163                     break;
   164                 case(ShapeModeReverseBinarizeAlpha):
   165                     pixel_opaque = (a <= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
   166                     break;
   167                 case(ShapeModeColorKey):
   168                     key = mode.parameters.colorKey;
   169                     pixel_opaque = ((key.r != r || key.g != g || key.b != b) ? SDL_TRUE : SDL_FALSE);
   170                     break;
   171             }
   172             if(last_opaque == -1)
   173                 last_opaque = pixel_opaque;
   174             if(last_opaque != pixel_opaque) {
   175                 const int halfwidth = dimensions.w / 2;
   176                 const int halfheight = dimensions.h / 2;
   177 
   178                 result->kind = QuadShape;
   179 
   180                 next.x = dimensions.x;
   181                 next.y = dimensions.y;
   182                 next.w = halfwidth;
   183                 next.h = halfheight;
   184                 result->data.children.upleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   185 
   186                 next.x = dimensions.x + halfwidth;
   187                 next.w = dimensions.w - halfwidth;
   188                 result->data.children.upright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   189 
   190                 next.x = dimensions.x;
   191                 next.w = halfwidth;
   192                 next.y = dimensions.y + halfheight;
   193                 next.h = dimensions.h - halfheight;
   194                 result->data.children.downleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   195 
   196                 next.x = dimensions.x + halfwidth;
   197                 next.w = dimensions.w - halfwidth;
   198                 result->data.children.downright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   199 
   200                 return result;
   201             }
   202         }
   203     }
   204 
   205 
   206     /* If we never recursed, all the pixels in this quadrant have the same "value". */
   207     result->kind = (last_opaque == SDL_TRUE ? OpaqueShape : TransparentShape);
   208     result->data.shape = dimensions;
   209     return result;
   210 }
   211 
   212 SDL_ShapeTree*
   213 SDL_CalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* shape)
   214 {
   215     SDL_Rect dimensions;
   216     SDL_ShapeTree* result = NULL;
   217 
   218     dimensions.x = 0;
   219     dimensions.y = 0;
   220     dimensions.w = shape->w;
   221     dimensions.h = shape->h;
   222 
   223     if(SDL_MUSTLOCK(shape))
   224         SDL_LockSurface(shape);
   225     result = RecursivelyCalculateShapeTree(mode,shape,dimensions);
   226     if(SDL_MUSTLOCK(shape))
   227         SDL_UnlockSurface(shape);
   228     return result;
   229 }
   230 
   231 void
   232 SDL_TraverseShapeTree(SDL_ShapeTree *tree,SDL_TraversalFunction function,void* closure)
   233 {
   234     SDL_assert(tree != NULL);
   235     if(tree->kind == QuadShape) {
   236         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upleft,function,closure);
   237         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upright,function,closure);
   238         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downleft,function,closure);
   239         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downright,function,closure);
   240     }
   241     else
   242         function(tree,closure);
   243 }
   244 
   245 void
   246 SDL_FreeShapeTree(SDL_ShapeTree** shape_tree)
   247 {
   248     if((*shape_tree)->kind == QuadShape) {
   249         SDL_FreeShapeTree((SDL_ShapeTree **)(char*)&(*shape_tree)->data.children.upleft);
   250         SDL_FreeShapeTree((SDL_ShapeTree **)(char*)&(*shape_tree)->data.children.upright);
   251         SDL_FreeShapeTree((SDL_ShapeTree **)(char*)&(*shape_tree)->data.children.downleft);
   252         SDL_FreeShapeTree((SDL_ShapeTree **)(char*)&(*shape_tree)->data.children.downright);
   253     }
   254     SDL_free(*shape_tree);
   255     *shape_tree = NULL;
   256 }
   257 
   258 int
   259 SDL_SetWindowShape(SDL_Window *window,SDL_Surface *shape,SDL_WindowShapeMode *shape_mode)
   260 {
   261     int result;
   262     if(window == NULL || !SDL_IsShapedWindow(window))
   263         /* The window given was not a shapeable window. */
   264         return SDL_NONSHAPEABLE_WINDOW;
   265     if(shape == NULL)
   266         /* Invalid shape argument. */
   267         return SDL_INVALID_SHAPE_ARGUMENT;
   268 
   269     if(shape_mode != NULL)
   270         window->shaper->mode = *shape_mode;
   271     result = SDL_GetVideoDevice()->shape_driver.SetWindowShape(window->shaper,shape,shape_mode);
   272     window->shaper->hasshape = SDL_TRUE;
   273     if(window->shaper->userx != 0 && window->shaper->usery != 0) {
   274         SDL_SetWindowPosition(window,window->shaper->userx,window->shaper->usery);
   275         window->shaper->userx = 0;
   276         window->shaper->usery = 0;
   277     }
   278     return result;
   279 }
   280 
   281 static SDL_bool
   282 SDL_WindowHasAShape(SDL_Window *window)
   283 {
   284     if (window == NULL || !SDL_IsShapedWindow(window))
   285         return SDL_FALSE;
   286     return window->shaper->hasshape;
   287 }
   288 
   289 int
   290 SDL_GetShapedWindowMode(SDL_Window *window,SDL_WindowShapeMode *shape_mode)
   291 {
   292     if(window != NULL && SDL_IsShapedWindow(window)) {
   293         if(shape_mode == NULL) {
   294             if(SDL_WindowHasAShape(window))
   295                 /* The window given has a shape. */
   296                 return 0;
   297             else
   298                 /* The window given is shapeable but lacks a shape. */
   299                 return SDL_WINDOW_LACKS_SHAPE;
   300         }
   301         else {
   302             *shape_mode = window->shaper->mode;
   303             return 0;
   304         }
   305     }
   306     else
   307         /* The window given is not a valid shapeable window. */
   308         return SDL_NONSHAPEABLE_WINDOW;
   309 }