src/video/SDL_shape.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 09 Apr 2012 23:55:43 -0400
changeset 6305 601b0e251822
parent 6138 4c64952a58fb
child 6863 73be5b6b2a86
permissions -rwxr-xr-x
SDL_ExitProcess() was ignoring exit code parameter.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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     pixel = (Uint8*)shape->pixels;
    75     for(y = 0;y<shape->h;y++) {
    76         for(x=0;x<shape->w;x++) {
    77             alpha = 0;
    78             pixel_value = 0;
    79             pixel = (Uint8 *)(shape->pixels) + (y*shape->pitch) + (x*shape->format->BytesPerPixel);
    80             switch(shape->format->BytesPerPixel) {
    81                 case(1):
    82                     pixel_value = *(Uint8*)pixel;
    83                     break;
    84                 case(2):
    85                     pixel_value = *(Uint16*)pixel;
    86                     break;
    87                 case(3):
    88                     pixel_value = *(Uint32*)pixel & (~shape->format->Amask);
    89                     break;
    90                 case(4):
    91                     pixel_value = *(Uint32*)pixel;
    92                     break;
    93             }
    94             SDL_GetRGBA(pixel_value,shape->format,&r,&g,&b,&alpha);
    95             bitmap_pixel = y*shape->w + x;
    96             switch(mode.mode) {
    97                 case(ShapeModeDefault):
    98                     mask_value = (alpha >= 1 ? 1 : 0);
    99                     break;
   100                 case(ShapeModeBinarizeAlpha):
   101                     mask_value = (alpha >= mode.parameters.binarizationCutoff ? 1 : 0);
   102                     break;
   103                 case(ShapeModeReverseBinarizeAlpha):
   104                     mask_value = (alpha <= mode.parameters.binarizationCutoff ? 1 : 0);
   105                     break;
   106                 case(ShapeModeColorKey):
   107                     key = mode.parameters.colorKey;
   108                     mask_value = ((key.r != r || key.g != g || key.b != b) ? 1 : 0);
   109                     break;
   110             }
   111             bitmap[bitmap_pixel / ppb] |= mask_value << (7 - ((ppb - 1) - (bitmap_pixel % ppb)));
   112         }
   113     }
   114     if(SDL_MUSTLOCK(shape))
   115         SDL_UnlockSurface(shape);
   116 }
   117 
   118 static SDL_ShapeTree*
   119 RecursivelyCalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* mask,SDL_Rect dimensions) {
   120     int x = 0,y = 0;
   121     Uint8* pixel = NULL;
   122     Uint32 pixel_value = 0;
   123     Uint8 r = 0,g = 0,b = 0,a = 0;
   124     SDL_bool pixel_opaque = SDL_FALSE;
   125     int last_opaque = -1;
   126     SDL_Color key;
   127     SDL_ShapeTree* result = (SDL_ShapeTree*)SDL_malloc(sizeof(SDL_ShapeTree));
   128     SDL_Rect next = {0,0,0,0};
   129     for(y=dimensions.y;y<dimensions.y + dimensions.h;y++) {
   130         for(x=dimensions.x;x<dimensions.x + dimensions.w;x++) {
   131             pixel_value = 0;
   132             pixel = (Uint8 *)(mask->pixels) + (y*mask->pitch) + (x*mask->format->BytesPerPixel);
   133             switch(mask->format->BytesPerPixel) {
   134                 case(1):
   135                     pixel_value = *(Uint8*)pixel;
   136                     break;
   137                 case(2):
   138                     pixel_value = *(Uint16*)pixel;
   139                     break;
   140                 case(3):
   141                     pixel_value = *(Uint32*)pixel & (~mask->format->Amask);
   142                     break;
   143                 case(4):
   144                     pixel_value = *(Uint32*)pixel;
   145                     break;
   146             }
   147             SDL_GetRGBA(pixel_value,mask->format,&r,&g,&b,&a);
   148             switch(mode.mode) {
   149                 case(ShapeModeDefault):
   150                     pixel_opaque = (a >= 1 ? SDL_TRUE : SDL_FALSE);
   151                     break;
   152                 case(ShapeModeBinarizeAlpha):
   153                     pixel_opaque = (a >= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
   154                     break;
   155                 case(ShapeModeReverseBinarizeAlpha):
   156                     pixel_opaque = (a <= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
   157                     break;
   158                 case(ShapeModeColorKey):
   159                     key = mode.parameters.colorKey;
   160                     pixel_opaque = ((key.r != r || key.g != g || key.b != b) ? SDL_TRUE : SDL_FALSE);
   161                     break;
   162             }
   163             if(last_opaque == -1)
   164                 last_opaque = pixel_opaque;
   165             if(last_opaque != pixel_opaque) {
   166                 result->kind = QuadShape;
   167                 //These will stay the same.
   168                 next.w = dimensions.w / 2;
   169                 next.h = dimensions.h / 2;
   170                 //These will change from recursion to recursion.
   171                 next.x = dimensions.x;
   172                 next.y = dimensions.y;
   173                 result->data.children.upleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   174                 next.x += next.w;
   175                 //Unneeded: next.y = dimensions.y;
   176                 result->data.children.upright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   177                 next.x = dimensions.x;
   178                 next.y += next.h;
   179                 result->data.children.downleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   180                 next.x += next.w;
   181                 //Unneeded: next.y = dimensions.y + dimensions.h /2;
   182                 result->data.children.downright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
   183                 return result;
   184             }
   185         }
   186     }
   187     //If we never recursed, all the pixels in this quadrant have the same "value".
   188     result->kind = (last_opaque == SDL_TRUE ? OpaqueShape : TransparentShape);
   189     result->data.shape = dimensions;
   190     return result;
   191 }
   192 
   193 SDL_ShapeTree*
   194 SDL_CalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* shape) {
   195     SDL_Rect dimensions = {0,0,shape->w,shape->h};
   196     SDL_ShapeTree* result = NULL;
   197     if(SDL_MUSTLOCK(shape))
   198         SDL_LockSurface(shape);
   199     result = RecursivelyCalculateShapeTree(mode,shape,dimensions);
   200     if(SDL_MUSTLOCK(shape))
   201         SDL_UnlockSurface(shape);
   202     return result;
   203 }
   204 
   205 void
   206 SDL_TraverseShapeTree(SDL_ShapeTree *tree,SDL_TraversalFunction function,void* closure) {
   207     SDL_assert(tree != NULL);
   208     if(tree->kind == QuadShape) {
   209         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upleft,function,closure);
   210         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upright,function,closure);
   211         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downleft,function,closure);
   212         SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downright,function,closure);
   213     }
   214     else
   215         function(tree,closure);
   216 }
   217 
   218 void
   219 SDL_FreeShapeTree(SDL_ShapeTree** shape_tree) {
   220     if((*shape_tree)->kind == QuadShape) {
   221         SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.upleft);
   222         SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.upright);
   223         SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.downleft);
   224         SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.downright);
   225     }
   226     SDL_free(*shape_tree);
   227     *shape_tree = NULL;
   228 }
   229 
   230 int
   231 SDL_SetWindowShape(SDL_Window *window,SDL_Surface *shape,SDL_WindowShapeMode *shape_mode) {
   232     int result;
   233     if(window == NULL || !SDL_IsShapedWindow(window))
   234         //The window given was not a shapeable window.
   235         return SDL_NONSHAPEABLE_WINDOW;
   236     if(shape == NULL)
   237         //Invalid shape argument.
   238         return SDL_INVALID_SHAPE_ARGUMENT;
   239     
   240     if(shape_mode != NULL)
   241         window->shaper->mode = *shape_mode;
   242     result = SDL_GetVideoDevice()->shape_driver.SetWindowShape(window->shaper,shape,shape_mode);
   243     window->shaper->hasshape = SDL_TRUE;
   244     if(window->shaper->userx != 0 && window->shaper->usery != 0) {
   245         SDL_SetWindowPosition(window,window->shaper->userx,window->shaper->usery);
   246         window->shaper->userx = 0;
   247         window->shaper->usery = 0;
   248     }
   249     return result;
   250 }
   251 
   252 static SDL_bool
   253 SDL_WindowHasAShape(SDL_Window *window) {
   254     if (window == NULL || !SDL_IsShapedWindow(window))
   255         return SDL_FALSE;
   256     return window->shaper->hasshape;
   257 }
   258 
   259 int
   260 SDL_GetShapedWindowMode(SDL_Window *window,SDL_WindowShapeMode *shape_mode) {
   261     if(window != NULL && SDL_IsShapedWindow(window)) {
   262         if(shape_mode == NULL) {
   263             if(SDL_WindowHasAShape(window))
   264                 //The window given has a shape.
   265                 return 0;
   266             else
   267                 //The window given is shapeable but lacks a shape.
   268                 return SDL_WINDOW_LACKS_SHAPE;
   269         }
   270         else {
   271             *shape_mode = window->shaper->mode;
   272             return 0;
   273         }
   274     }
   275     else
   276         //The window given is not a valid shapeable window.
   277         return SDL_NONSHAPEABLE_WINDOW;
   278 }