src/video/SDL_shape.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 14 Jul 2013 11:28:44 -0700
changeset 7776 d4a39491577f
parent 7678 286c42d7c5ed
child 8093 b43765095a6f
permissions -rw-r--r--
Added the platform specific messagebox function to the video function list
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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_config.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     for(y=dimensions.y;y<dimensions.y + dimensions.h;y++) {
   132         for(x=dimensions.x;x<dimensions.x + dimensions.w;x++) {
   133             pixel_value = 0;
   134             pixel = (Uint8 *)(mask->pixels) + (y*mask->pitch) + (x*mask->format->BytesPerPixel);
   135             switch(mask->format->BytesPerPixel) {
   136                 case(1):
   137                     pixel_value = *(Uint8*)pixel;
   138                     break;
   139                 case(2):
   140                     pixel_value = *(Uint16*)pixel;
   141                     break;
   142                 case(3):
   143                     pixel_value = *(Uint32*)pixel & (~mask->format->Amask);
   144                     break;
   145                 case(4):
   146                     pixel_value = *(Uint32*)pixel;
   147                     break;
   148             }
   149             SDL_GetRGBA(pixel_value,mask->format,&r,&g,&b,&a);
   150             switch(mode.mode) {
   151                 case(ShapeModeDefault):
   152                     pixel_opaque = (a >= 1 ? SDL_TRUE : SDL_FALSE);
   153                     break;
   154                 case(ShapeModeBinarizeAlpha):
   155                     pixel_opaque = (a >= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
   156                     break;
   157                 case(ShapeModeReverseBinarizeAlpha):
   158                     pixel_opaque = (a <= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
   159                     break;
   160                 case(ShapeModeColorKey):
   161                     key = mode.parameters.colorKey;
   162                     pixel_opaque = ((key.r != r || key.g != g || key.b != b) ? SDL_TRUE : SDL_FALSE);
   163                     break;
   164             }
   165             if(last_opaque == -1)
   166                 last_opaque = pixel_opaque;
   167             if(last_opaque != pixel_opaque) {
   168                 result->kind = QuadShape;
   169                 /* These will stay the same. */
   170                 next.w = dimensions.w / 2;
   171                 next.h = dimensions.h / 2;
   172                 /* These will change from recursion to recursion. */
   173                 next.x = dimensions.x;
   174                 next.y = dimensions.y;
   175                 result->data.children.upleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   176                 next.x += next.w;
   177                 /* Unneeded: next.y = dimensions.y; */
   178                 result->data.children.upright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   179                 next.x = dimensions.x;
   180                 next.y += next.h;
   181                 result->data.children.downleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   182                 next.x += next.w;
   183                 /* Unneeded: next.y = dimensions.y + dimensions.h /2; */
   184                 result->data.children.downright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   185                 return result;
   186             }
   187         }
   188     }
   189     /* If we never recursed, all the pixels in this quadrant have the same "value". */
   190     result->kind = (last_opaque == SDL_TRUE ? OpaqueShape : TransparentShape);
   191     result->data.shape = dimensions;
   192     return result;
   193 }
   194 
   195 SDL_ShapeTree*
   196 SDL_CalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* shape)
   197 {
   198     SDL_Rect dimensions = {0,0,shape->w,shape->h};
   199     SDL_ShapeTree* result = NULL;
   200     if(SDL_MUSTLOCK(shape))
   201         SDL_LockSurface(shape);
   202     result = RecursivelyCalculateShapeTree(mode,shape,dimensions);
   203     if(SDL_MUSTLOCK(shape))
   204         SDL_UnlockSurface(shape);
   205     return result;
   206 }
   207 
   208 void
   209 SDL_TraverseShapeTree(SDL_ShapeTree *tree,SDL_TraversalFunction function,void* closure)
   210 {
   211     SDL_assert(tree != NULL);
   212     if(tree->kind == QuadShape) {
   213         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upleft,function,closure);
   214         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upright,function,closure);
   215         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downleft,function,closure);
   216         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downright,function,closure);
   217     }
   218     else
   219         function(tree,closure);
   220 }
   221 
   222 void
   223 SDL_FreeShapeTree(SDL_ShapeTree** shape_tree)
   224 {
   225     if((*shape_tree)->kind == QuadShape) {
   226         SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.upleft);
   227         SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.upright);
   228         SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.downleft);
   229         SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.downright);
   230     }
   231     SDL_free(*shape_tree);
   232     *shape_tree = NULL;
   233 }
   234 
   235 int
   236 SDL_SetWindowShape(SDL_Window *window,SDL_Surface *shape,SDL_WindowShapeMode *shape_mode)
   237 {
   238     int result;
   239     if(window == NULL || !SDL_IsShapedWindow(window))
   240         /* The window given was not a shapeable window. */
   241         return SDL_NONSHAPEABLE_WINDOW;
   242     if(shape == NULL)
   243         /* Invalid shape argument. */
   244         return SDL_INVALID_SHAPE_ARGUMENT;
   245 
   246     if(shape_mode != NULL)
   247         window->shaper->mode = *shape_mode;
   248     result = SDL_GetVideoDevice()->shape_driver.SetWindowShape(window->shaper,shape,shape_mode);
   249     window->shaper->hasshape = SDL_TRUE;
   250     if(window->shaper->userx != 0 && window->shaper->usery != 0) {
   251         SDL_SetWindowPosition(window,window->shaper->userx,window->shaper->usery);
   252         window->shaper->userx = 0;
   253         window->shaper->usery = 0;
   254     }
   255     return result;
   256 }
   257 
   258 static SDL_bool
   259 SDL_WindowHasAShape(SDL_Window *window)
   260 {
   261     if (window == NULL || !SDL_IsShapedWindow(window))
   262         return SDL_FALSE;
   263     return window->shaper->hasshape;
   264 }
   265 
   266 int
   267 SDL_GetShapedWindowMode(SDL_Window *window,SDL_WindowShapeMode *shape_mode)
   268 {
   269     if(window != NULL && SDL_IsShapedWindow(window)) {
   270         if(shape_mode == NULL) {
   271             if(SDL_WindowHasAShape(window))
   272                 /* The window given has a shape. */
   273                 return 0;
   274             else
   275                 /* The window given is shapeable but lacks a shape. */
   276                 return SDL_WINDOW_LACKS_SHAPE;
   277         }
   278         else {
   279             *shape_mode = window->shaper->mode;
   280             return 0;
   281         }
   282     }
   283     else
   284         /* The window given is not a valid shapeable window. */
   285         return SDL_NONSHAPEABLE_WINDOW;
   286 }