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