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