sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_shape.c (11309B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 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_video.h"
     25 #include "SDL_sysvideo.h"
     26 #include "SDL_pixels.h"
     27 #include "SDL_surface.h"
     28 #include "SDL_shape.h"
     29 #include "SDL_shape_internals.h"
     30 
     31 SDL_Window*
     32 SDL_CreateShapedWindow(const char *title,unsigned int x,unsigned int y,unsigned int w,unsigned int h,Uint32 flags)
     33 {
     34     SDL_Window *result = NULL;
     35     result = SDL_CreateWindow(title,-1000,-1000,w,h,(flags | SDL_WINDOW_BORDERLESS) & (~SDL_WINDOW_FULLSCREEN) & (~SDL_WINDOW_RESIZABLE) /* & (~SDL_WINDOW_SHOWN) */);
     36     if(result != NULL) {
     37         if (SDL_GetVideoDevice()->shape_driver.CreateShaper == NULL) {
     38             SDL_DestroyWindow(result);
     39             return NULL;
     40         }
     41         result->shaper = SDL_GetVideoDevice()->shape_driver.CreateShaper(result);
     42         if(result->shaper != NULL) {
     43             result->shaper->userx = x;
     44             result->shaper->usery = y;
     45             result->shaper->mode.mode = ShapeModeDefault;
     46             result->shaper->mode.parameters.binarizationCutoff = 1;
     47             result->shaper->hasshape = SDL_FALSE;
     48             return result;
     49         }
     50         else {
     51             SDL_DestroyWindow(result);
     52             return NULL;
     53         }
     54     }
     55     else
     56         return NULL;
     57 }
     58 
     59 SDL_bool
     60 SDL_IsShapedWindow(const SDL_Window *window)
     61 {
     62     if(window == NULL)
     63         return SDL_FALSE;
     64     else
     65         return (SDL_bool)(window->shaper != NULL);
     66 }
     67 
     68 /* REQUIRES that bitmap point to a w-by-h bitmap with ppb pixels-per-byte. */
     69 void
     70 SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode,SDL_Surface *shape,Uint8* bitmap,Uint8 ppb)
     71 {
     72     int x = 0;
     73     int y = 0;
     74     Uint8 r = 0,g = 0,b = 0,alpha = 0;
     75     Uint8* pixel = NULL;
     76     Uint32 pixel_value = 0,mask_value = 0;
     77     int bytes_per_scanline = (shape->w + (ppb - 1)) / ppb;
     78     Uint8 *bitmap_scanline;
     79     SDL_Color key;
     80     if(SDL_MUSTLOCK(shape))
     81         SDL_LockSurface(shape);
     82     for(y = 0;y<shape->h;y++) {
     83         bitmap_scanline = bitmap + y * bytes_per_scanline;
     84         for(x=0;x<shape->w;x++) {
     85             alpha = 0;
     86             pixel_value = 0;
     87             pixel = (Uint8 *)(shape->pixels) + (y*shape->pitch) + (x*shape->format->BytesPerPixel);
     88             switch(shape->format->BytesPerPixel) {
     89                 case(1):
     90                     pixel_value = *pixel;
     91                     break;
     92                 case(2):
     93                     pixel_value = *(Uint16*)pixel;
     94                     break;
     95                 case(3):
     96                     pixel_value = *(Uint32*)pixel & (~shape->format->Amask);
     97                     break;
     98                 case(4):
     99                     pixel_value = *(Uint32*)pixel;
    100                     break;
    101             }
    102             SDL_GetRGBA(pixel_value,shape->format,&r,&g,&b,&alpha);
    103             switch(mode.mode) {
    104                 case(ShapeModeDefault):
    105                     mask_value = (alpha >= 1 ? 1 : 0);
    106                     break;
    107                 case(ShapeModeBinarizeAlpha):
    108                     mask_value = (alpha >= mode.parameters.binarizationCutoff ? 1 : 0);
    109                     break;
    110                 case(ShapeModeReverseBinarizeAlpha):
    111                     mask_value = (alpha <= mode.parameters.binarizationCutoff ? 1 : 0);
    112                     break;
    113                 case(ShapeModeColorKey):
    114                     key = mode.parameters.colorKey;
    115                     mask_value = ((key.r != r || key.g != g || key.b != b) ? 1 : 0);
    116                     break;
    117             }
    118             bitmap_scanline[x / ppb] |= mask_value << (x % ppb);
    119         }
    120     }
    121     if(SDL_MUSTLOCK(shape))
    122         SDL_UnlockSurface(shape);
    123 }
    124 
    125 static SDL_ShapeTree*
    126 RecursivelyCalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* mask,SDL_Rect dimensions) {
    127     int x = 0,y = 0;
    128     Uint8* pixel = NULL;
    129     Uint32 pixel_value = 0;
    130     Uint8 r = 0,g = 0,b = 0,a = 0;
    131     SDL_bool pixel_opaque = SDL_FALSE;
    132     int last_opaque = -1;
    133     SDL_Color key;
    134     SDL_ShapeTree* result = (SDL_ShapeTree*)SDL_malloc(sizeof(SDL_ShapeTree));
    135     SDL_Rect next = {0,0,0,0};
    136 
    137     for(y=dimensions.y;y<dimensions.y + dimensions.h;y++) {
    138         for(x=dimensions.x;x<dimensions.x + dimensions.w;x++) {
    139             pixel_value = 0;
    140             pixel = (Uint8 *)(mask->pixels) + (y*mask->pitch) + (x*mask->format->BytesPerPixel);
    141             switch(mask->format->BytesPerPixel) {
    142                 case(1):
    143                     pixel_value = *pixel;
    144                     break;
    145                 case(2):
    146                     pixel_value = *(Uint16*)pixel;
    147                     break;
    148                 case(3):
    149                     pixel_value = *(Uint32*)pixel & (~mask->format->Amask);
    150                     break;
    151                 case(4):
    152                     pixel_value = *(Uint32*)pixel;
    153                     break;
    154             }
    155             SDL_GetRGBA(pixel_value,mask->format,&r,&g,&b,&a);
    156             switch(mode.mode) {
    157                 case(ShapeModeDefault):
    158                     pixel_opaque = (a >= 1 ? SDL_TRUE : SDL_FALSE);
    159                     break;
    160                 case(ShapeModeBinarizeAlpha):
    161                     pixel_opaque = (a >= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
    162                     break;
    163                 case(ShapeModeReverseBinarizeAlpha):
    164                     pixel_opaque = (a <= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
    165                     break;
    166                 case(ShapeModeColorKey):
    167                     key = mode.parameters.colorKey;
    168                     pixel_opaque = ((key.r != r || key.g != g || key.b != b) ? SDL_TRUE : SDL_FALSE);
    169                     break;
    170             }
    171             if(last_opaque == -1)
    172                 last_opaque = pixel_opaque;
    173             if(last_opaque != pixel_opaque) {
    174                 const int halfwidth = dimensions.w / 2;
    175                 const int halfheight = dimensions.h / 2;
    176 
    177                 result->kind = QuadShape;
    178 
    179                 next.x = dimensions.x;
    180                 next.y = dimensions.y;
    181                 next.w = halfwidth;
    182                 next.h = halfheight;
    183                 result->data.children.upleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
    184 
    185                 next.x = dimensions.x + halfwidth;
    186                 next.w = dimensions.w - halfwidth;
    187                 result->data.children.upright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
    188 
    189                 next.x = dimensions.x;
    190                 next.w = halfwidth;
    191                 next.y = dimensions.y + halfheight;
    192                 next.h = dimensions.h - halfheight;
    193                 result->data.children.downleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
    194 
    195                 next.x = dimensions.x + halfwidth;
    196                 next.w = dimensions.w - halfwidth;
    197                 result->data.children.downright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
    198 
    199                 return result;
    200             }
    201         }
    202     }
    203 
    204 
    205     /* If we never recursed, all the pixels in this quadrant have the same "value". */
    206     result->kind = (last_opaque == SDL_TRUE ? OpaqueShape : TransparentShape);
    207     result->data.shape = dimensions;
    208     return result;
    209 }
    210 
    211 SDL_ShapeTree*
    212 SDL_CalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* shape)
    213 {
    214     SDL_Rect dimensions;
    215     SDL_ShapeTree* result = NULL;
    216 
    217     dimensions.x = 0;
    218     dimensions.y = 0;
    219     dimensions.w = shape->w;
    220     dimensions.h = shape->h;
    221 
    222     if(SDL_MUSTLOCK(shape))
    223         SDL_LockSurface(shape);
    224     result = RecursivelyCalculateShapeTree(mode,shape,dimensions);
    225     if(SDL_MUSTLOCK(shape))
    226         SDL_UnlockSurface(shape);
    227     return result;
    228 }
    229 
    230 void
    231 SDL_TraverseShapeTree(SDL_ShapeTree *tree,SDL_TraversalFunction function,void* closure)
    232 {
    233     SDL_assert(tree != NULL);
    234     if(tree->kind == QuadShape) {
    235         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upleft,function,closure);
    236         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upright,function,closure);
    237         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downleft,function,closure);
    238         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downright,function,closure);
    239     }
    240     else
    241         function(tree,closure);
    242 }
    243 
    244 void
    245 SDL_FreeShapeTree(SDL_ShapeTree** shape_tree)
    246 {
    247     if((*shape_tree)->kind == QuadShape) {
    248         SDL_FreeShapeTree((SDL_ShapeTree **)(char*)&(*shape_tree)->data.children.upleft);
    249         SDL_FreeShapeTree((SDL_ShapeTree **)(char*)&(*shape_tree)->data.children.upright);
    250         SDL_FreeShapeTree((SDL_ShapeTree **)(char*)&(*shape_tree)->data.children.downleft);
    251         SDL_FreeShapeTree((SDL_ShapeTree **)(char*)&(*shape_tree)->data.children.downright);
    252     }
    253     SDL_free(*shape_tree);
    254     *shape_tree = NULL;
    255 }
    256 
    257 int
    258 SDL_SetWindowShape(SDL_Window *window,SDL_Surface *shape,SDL_WindowShapeMode *shape_mode)
    259 {
    260     int result;
    261     if(window == NULL || !SDL_IsShapedWindow(window))
    262         /* The window given was not a shapeable window. */
    263         return SDL_NONSHAPEABLE_WINDOW;
    264     if(shape == NULL)
    265         /* Invalid shape argument. */
    266         return SDL_INVALID_SHAPE_ARGUMENT;
    267 
    268     if(shape_mode != NULL)
    269         window->shaper->mode = *shape_mode;
    270     result = SDL_GetVideoDevice()->shape_driver.SetWindowShape(window->shaper,shape,shape_mode);
    271     window->shaper->hasshape = SDL_TRUE;
    272     if(window->shaper->userx != 0 && window->shaper->usery != 0) {
    273         SDL_SetWindowPosition(window,window->shaper->userx,window->shaper->usery);
    274         window->shaper->userx = 0;
    275         window->shaper->usery = 0;
    276     }
    277     return result;
    278 }
    279 
    280 static SDL_bool
    281 SDL_WindowHasAShape(SDL_Window *window)
    282 {
    283     if (window == NULL || !SDL_IsShapedWindow(window))
    284         return SDL_FALSE;
    285     return window->shaper->hasshape;
    286 }
    287 
    288 int
    289 SDL_GetShapedWindowMode(SDL_Window *window,SDL_WindowShapeMode *shape_mode)
    290 {
    291     if(window != NULL && SDL_IsShapedWindow(window)) {
    292         if(shape_mode == NULL) {
    293             if(SDL_WindowHasAShape(window))
    294                 /* The window given has a shape. */
    295                 return 0;
    296             else
    297                 /* The window given is shapeable but lacks a shape. */
    298                 return SDL_WINDOW_LACKS_SHAPE;
    299         }
    300         else {
    301             *shape_mode = window->shaper->mode;
    302             return 0;
    303         }
    304     }
    305     else
    306         /* The window given is not a valid shapeable window. */
    307         return SDL_NONSHAPEABLE_WINDOW;
    308 }