SDL_shape.c (11041B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 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 32SDL_Window* 33SDL_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 56SDL_bool 57SDL_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. */ 66void 67SDL_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 120static SDL_ShapeTree* 121RecursivelyCalculateShapeTree(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 206SDL_ShapeTree* 207SDL_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 219void 220SDL_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 233void 234SDL_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 246int 247SDL_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 269static SDL_bool 270SDL_WindowHasAShape(SDL_Window *window) 271{ 272 if (window == NULL || !SDL_IsShapedWindow(window)) 273 return SDL_FALSE; 274 return window->shaper->hasshape; 275} 276 277int 278SDL_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}