# HG changeset patch # User Eli Gottlieb # Date 1280374524 14400 # Node ID 5b4c7d7d89537866392a6fb17ae9a6b7812324e4 # Parent 06a03d08cefbc6b6984d0b11fbd833cf2cd0ac20 Wrote out the system for breaking shape-masks into quad-trees of rectangles, and added code to conglomerate those quad-trees of rectangles into regions for setting shapes under Win32. diff -r 06a03d08cefb -r 5b4c7d7d8953 src/video/SDL_shape.c --- a/src/video/SDL_shape.c Mon Jul 26 21:49:32 2010 -0400 +++ b/src/video/SDL_shape.c Wed Jul 28 23:35:24 2010 -0400 @@ -27,6 +27,7 @@ #include "SDL_pixels.h" #include "SDL_surface.h" #include "SDL_shape.h" +#include "SDL_shape_internals.h" SDL_Window* SDL_CreateShapedWindow(const char *title,unsigned int x,unsigned int y,unsigned int w,unsigned int h,Uint32 flags) { SDL_Window *result = SDL_CreateWindow(title,x,y,w,h,SDL_WINDOW_BORDERLESS | flags & !SDL_WINDOW_FULLSCREEN & !SDL_WINDOW_SHOWN); @@ -55,7 +56,7 @@ return (SDL_bool)(window->shaper != NULL); } -/* REQUIRES that bitmap point to a w-by-h bitmap with 1bpp. */ +/* REQUIRES that bitmap point to a w-by-h bitmap with ppb pixels-per-byte. */ void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode,SDL_Surface *shape,Uint8* bitmap,Uint8 ppb,Uint8 value) { int x = 0; int y = 0; @@ -105,6 +106,111 @@ SDL_UnlockSurface(shape); } +SDL_ShapeTree* RecursivelyCalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* mask,SDL_bool invert,SDL_Rect dimensions) { + int x = 0,y = 0; + Uint8* pixel = NULL; + Uint32 pixel_value = 0; + Uint8 r = 0,g = 0,b = 0,a = 0; + SDL_bool pixel_transparent = SDL_FALSE; + int last_transparent = -1; + SDL_Color key; + SDL_ShapeTree* result = malloc(sizeof(SDL_ShapeTree)); + SDL_Rect next = {0,0,0,0}; + for(y=dimensions.y;ypixels) + (y*mask->pitch) + (x*mask->format->BytesPerPixel); + switch(mask->format->BytesPerPixel) { + case(1): + pixel_value = *(Uint8*)pixel; + break; + case(2): + pixel_value = *(Uint16*)pixel; + break; + case(4): + pixel_value = *(Uint32*)pixel; + break; + } + SDL_GetRGBA(pixel_value,mask->format,&r,&g,&b,&a); + switch(mode.mode) { + case(ShapeModeDefault): + pixel_transparent = (a >= 1 ? !invert : invert); + break; + case(ShapeModeBinarizeAlpha): + pixel_transparent = (a >= mode.parameters.binarizationCutoff ? !invert : invert); + break; + case(ShapeModeReverseBinarizeAlpha): + pixel_transparent = (a <= mode.parameters.binarizationCutoff ? !invert : invert); + break; + case(ShapeModeColorKey): + key = mode.parameters.colorKey; + pixel_transparent = ((key.r == r && key.g == g && key.b == b) ? !invert : invert); + break; + } + if(last_transparent == -1) { + last_transparent = pixel_transparent; + break; + } + if(last_transparent != pixel_transparent) { + result->kind = QuadShape; + //These will stay the same. + next.w = dimensions.w / 2; + next.h = dimensions.h / 2; + //These will change from recursion to recursion. + next.x = dimensions.x; + next.y = dimensions.y; + result->data.children.upleft = RecursivelyCalculateShapeTree(mode,mask,invert,next); + next.x = dimensions.w / 2 + 1; + //Unneeded: next.y = dimensions.y; + result->data.children.upright = RecursivelyCalculateShapeTree(mode,mask,invert,next); + next.x = dimensions.x; + next.y = dimensions.h / 2 + 1; + result->data.children.downleft = RecursivelyCalculateShapeTree(mode,mask,invert,next); + next.x = dimensions.w / 2 + 1; + //Unneeded: next.y = dimensions.h / 2 + 1; + result->data.children.downright = RecursivelyCalculateShapeTree(mode,mask,invert,next); + return result; + } + } + //If we never recursed, all the pixels in this quadrant have the same "value". + result->kind = (last_transparent == SDL_FALSE ? OpaqueShape : TransparentShape); + result->data.shape = dimensions; + return result; +} + +SDL_ShapeTree* SDL_CalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* shape,SDL_bool invert) { + SDL_Rect dimensions = {0,0,shape->w,shape->h}; + SDL_ShapeTree* result = NULL; + if(SDL_MUSTLOCK(shape)) + SDL_LockSurface(shape); + result = RecursivelyCalculateShapeTree(mode,shape,invert,dimensions); + if(SDL_MUSTLOCK(shape)) + SDL_UnlockSurface(shape); + return result; +} + +void SDL_TraverseShapeTree(SDL_ShapeTree *tree,void(*function)(SDL_ShapeTree*,void*),void* closure) { + if(tree->kind == QuadShape) { + SDL_TraverseShapeTree(tree->data.children.upleft,function,closure); + SDL_TraverseShapeTree(tree->data.children.upright,function,closure); + SDL_TraverseShapeTree(tree->data.children.downleft,function,closure); + SDL_TraverseShapeTree(tree->data.children.downright,function,closure); + } + else + function(tree,closure); +} + +void SDL_FreeShapeTree(SDL_ShapeTree** shapeTree) { + if((*shapeTree)->kind == QuadShape) { + SDL_FreeShapeTree(&(*shapeTree)->data.children.upleft); + SDL_FreeShapeTree(&(*shapeTree)->data.children.upright); + SDL_FreeShapeTree(&(*shapeTree)->data.children.downleft); + SDL_FreeShapeTree(&(*shapeTree)->data.children.downright); + } + free(*shapeTree); + *shapeTree = NULL; +} + int SDL_SetWindowShape(SDL_Window *window,SDL_Surface *shape,SDL_WindowShapeMode *shapeMode) { int result; if(window == NULL || !SDL_IsShapedWindow(window)) diff -r 06a03d08cefb -r 5b4c7d7d8953 src/video/win32/SDL_win32shape.c --- a/src/video/win32/SDL_win32shape.c Mon Jul 26 21:49:32 2010 -0400 +++ b/src/video/win32/SDL_win32shape.c Wed Jul 28 23:35:24 2010 -0400 @@ -23,10 +23,6 @@ #include #include "SDL_win32shape.h" -SDL_Window* Win32_CreateShapedWindow(const char *title,unsigned int x,unsigned int y,unsigned int w,unsigned int h,Uint32 flags) { - return SDL_CreateWindow(title,x,y,w,h,flags); -} - SDL_WindowShaper* Win32_CreateShaper(SDL_Window * window) { SDL_WindowShaper* result = malloc(sizeof(SDL_WindowShaper)); result->window = window; @@ -35,315 +31,48 @@ result->usershownflag = 0; //Put some driver-data here. window->shaper = result; - int resized_properly = X11ResizeWindowShape(window); + int resized_properly = Win32_ResizeWindowShape(window); assert(resized_properly == 0); return result; } +void CombineRectRegions(SDL_ShapeTree* node,HRGN* mask_region) { + if(node->kind == OpaqueShape) { + HRGN temp_region = CreateRectRgn(node->data.shape.x,node->data.shape.y,node->data.shape.w,node->data.shape.h); + CombineRgn(*mask_region,*mask_region,temp_region, RGN_OR); + DeleteObject(temp_region); + } +} + int Win32_SetWindowShape(SDL_WindowShaper *shaper,SDL_Surface *shape,SDL_WindowShapeMode *shapeMode) { assert(shaper != NULL && shape != NULL); - if(!SDL_ISPIXELFORMAT_ALPHA(SDL_MasksToPixelFormatEnum(shape->format->BitsPerPixel,shape->format->Rmask,shape->format->Gmask,shape->format->Bmask,shape->format->Amask))) - return -2; - if(shape->w != shaper->window->w || shape->h != shaper->window->h) - return -3; + if(!SDL_ISPIXELFORMAT_ALPHA(SDL_MasksToPixelFormatEnum(shape->format->BitsPerPixel,shape->format->Rmask,shape->format->Gmask,shape->format->Bmask,shape->format->Amask)) && shapeMode->mode != ShapeModeColorKey || shape->w != shaper->window->w || shape->h != shaper->window->h) + return SDL_INVALID_SHAPE_ARGUMENT; + + SDL_ShapeData *data = (SDL_ShapeData*)shaper->driverdata; + data->mask_tree = SDL_CalculateShapeTree(shapeMode,shape,SDL_FALSE); /* * Start with empty region */ - HRGN MaskRegion = CreateRectRgn(0, 0, 0, 0); - - unsigned int pitch = shape->pitch; - unsigned int width = shape->width; - unsigned int height = shape->height; - unsigned int dy = pitch - width; - - SDL_ShapeData *data = (SDL_ShapeData*)shaper->driverdata; - /* - * Transfer binarized mask image into workbuffer - */ - SDL_CalculateShapeBitmap(shaper->mode,shape,data->shapebuffer,1,0xff); + HRGN mask_region = CreateRectRgn(0, 0, 0, 0); - //Move code over to here from AW_windowShape.c - Uint8 *pos1 = data->shapebuffer + width - 1; - Uint8 *pos2 = (Uint8*) pos1 + 1; - int x = 0,y = 0; - int visible = 0; - int vxmin = shape->width - 1; - int vxmax = -1; - int vymin = shape->height - 1; - int vymax = -1; - for (y = 0; y vxmax) - vxmax = x; - if (y < vxymin) - vxymin = y; - if (y > vymax) - vymax = y; - - /* - * Check for starting point - */ - Uint8 *TL, *TR, *BL, *BR; - int target_x, target_y, lasttarget_x, lasttarget_y; - if (((!*curpos) && (*curpos2 == 0xFF)) || ((!*curpos2) && (*curpos == 0xFF))) { - if (!*curpos) { - BR = curpos2; - BL = (Uint8 *) (BR - 1); - TR = (Uint8 *) (BR - width); - TL = (Uint8 *) (TR - 1); - target_x = x; - target_y = y; - } - else { - BR = curpos2 + 1; - BL = (Uint8 *) (BR - 1); - TR = (Uint8 *) (BR - width); - TL = (Uint8 *) (TR - 1); - target_x = x + 1; - target_y = y; - } - - lasttarget_x = 0; - lasttarget_y = 0; - int firsttime = 1; - pos_array_pos = 0; - - while ((target_x != x) || (target_y != y) || firsttime) { - /* - * New array index - */ - firsttime = 0; - pos_array_pos++; - /* - * Check array index - */ - if (pos_array_pos >= 4096) { - SDL_SetError("Exceeded maximum number of polygon points."); - pos_array_pos--; - } - - /* - * Store point in array - */ - pos_array[pos_array_pos].x = target_x + 1; - pos_array[pos_array_pos].y = target_y; - - /* - * Mark the four poles as visited - */ - if (*TL) - *TL = 0x99; - if (*BL) - *BL = 0x99; - if (*TR) - *TR = 0x99; - if (*BR) - *BR = 0x99; - - newtargetcount = 0; - if ((*TL || *TR) && (*TL != *TR)) { - newtargetcount++; - newtarget[newtargetcount].x = 0; - newtarget[newtargetcount].y = -1; - } - - if ((*TR || *BR) && (*TR != *BR)) { - newtargetcount++; - newtarget[newtargetcount].x = 1; - newtarget[newtargetcount].y = 0; - } - - if ((*BL || *BR) && (*BL != *BR)) { - newtargetcount++; - newtarget[newtargetcount].x = 0; - newtarget[newtargetcount].y = 1; - } - - if ((*TL || *BL) && (*TL != *BL)) { - newtargetcount++; - newtarget[newtargetcount].x = -1; - newtarget[newtargetcount].y = 0; - } - - switch (newtargetcount) { - case 1: - SDL_SetError("Cropping error - Newtargetcount=1."); - return (-1); - break; - - case 2: - if ((target_x + newtarget[1].x != lasttarget_x) || (target_y + newtarget[1].y != lasttarget_y)) { - lasttarget_x = target_x; - lasttarget_y = target_y; - target_x = target_x + newtarget[1].x; - target_y = target_y + newtarget[1].y; - } - else { - lasttarget_x = target_x; - lasttarget_y = target_y; - target_x = target_x + newtarget[2].x; - target_y = target_y + newtarget[2].y; - } - break; - - case 3: - SDL_SetError("Cropping error - Newtargetcount=3."); - return (-1); - break; - - case 4: - if (lasttarget_x > target_x) { - lasttarget_x = target_x; - lasttarget_y = target_y; - if (*TR != 0x00) - target_y--; - else - target_y++; - } - else if (lasttarget_y > target_y) { - lasttarget_x = target_x; - lasttarget_y = target_y; - if (*BL != 0x00) - target_x--; - else - target_x++; - } - else if (lasttarget_x < target_x) { - lasttarget_x = target_x; - lasttarget_y = target_y; - if (*TL != 0x00) - target_y--; - else - target_y++; - } - else if (lasttarget_y < target_y) { - lasttarget_x = target_x; - lasttarget_y = target_y; - if (*TL != 0x00) - target_x--; - else - target_x++; - } - else { - SDL_SetError("Cropping error - no possible targets on newtargetcount=4."); - return (-1); - } - break; - - default: - SDL_SetError("Cropping error - Newtargetcount invalid."); - return (-1); - break; - } - - if (target_x > lasttarget_x) - TL = (Uint8 *) (TL + 1); - else if (target_x < lasttarget_x) - TL = (Uint8 *) (TL - 1); - else if (target_y > lasttarget_y) - TL = (Uint8 *) (TL + width); - else if (target_y < lasttarget_y) - TL = (Uint8 *) (TL - width); - else { - SDL_SetError("Cropping error - no new target."); - return (-1); - } - - BL = (Uint8 *) (TL + width); - TR = (Uint8 *) (TL + 1); - BR = (Uint8 *) (BL + 1); - } // End of while loop - - /* - * Apply the mask to the cropping region - */ - if (pos_array_pos >= 4) { - TempRegion = CreatePolygonRgn(&(pos_array[1]), pos_array_pos, WINDING); - if (TempRegion == NULL) { - SDL_SetError("Cropping error - unable to create polygon."); - return (-1); - } - - /* - * Add current region to final mask region - */ - if (inside) - CombineRgn(MaskRegion, MaskRegion, TempRegion, RGN_DIFF); - else - CombineRgn(MaskRegion, MaskRegion, TempRegion, RGN_OR); - - /* - * Remove temporary region - */ - DeleteObject(TempRegion); - } - - /* - * Switch sides - */ - inside = !inside; - } - else if ((*curpos) && (!*curpos2)) - inside = !inside; - else if ((!*curpos) && (*curpos2)) - inside = !inside; - - curpos++; - curpos2++; - } - curpos = (Uint8 *) (curpos + 2 * enlarge_mask - 1); - curpos2 = (Uint8 *) (curpos + 1); - } + SDL_TraverseShapeTree(data->mask_tree,&CombineRectRegions,&mask_region); /* * Set the new region mask for the window */ - SetWindowRgn((SDL_WindowData*)(shaper->window->driverdata)->hwnd, MaskRegion, TRUE); - - /* - * Return value - */ - return (0); + SetWindowRgn((SDL_WindowData*)(shaper->window->driverdata)->hwnd, mask_region, TRUE); + + return 0; } int Win32_ResizeWindowShape(SDL_Window *window) { SDL_ShapeData* data = window->shaper->driverdata; assert(data != NULL); - unsigned int buffersize = window->w * window->h; - if(data->buffersize != buffersize || data->shapebuffer == NULL) { - data->buffersize = buffersize; - if(data->shapebuffer != NULL) - free(data->shapebuffer); - data->shapebuffer = malloc(data->buffersize); - if(data->shapebuffer == NULL) { - SDL_SetError("Could not allocate memory for shaped-window bitmap."); - return -1; - } - } - else - memset(data->shapebuffer,0,data->buffersize); + if(data->mask_tree != NULL) + SDL_FreeShapeTree(&data->mask_tree); window->shaper->usershownflag |= window->flags & SDL_WINDOW_SHOWN; diff -r 06a03d08cefb -r 5b4c7d7d8953 src/video/win32/SDL_win32shape.h --- a/src/video/win32/SDL_win32shape.h Mon Jul 26 21:49:32 2010 -0400 +++ b/src/video/win32/SDL_win32shape.h Wed Jul 28 23:35:24 2010 -0400 @@ -28,13 +28,12 @@ #include "SDL_video.h" #include "SDL_shape.h" #include "../SDL_sysvideo.h" +#include "../SDL_shape_internals.h" typedef struct { - void* shapebuffer; - Uint32 buffersize; + SDL_ShapeTree *mask_tree; } SDL_ShapeData; -extern SDL_Window* Win32_CreateShapedWindow(const char *title,unsigned int x,unsigned int y,unsigned int w,unsigned int h,Uint32 flags); extern SDL_WindowShaper* Win32_CreateShaper(SDL_Window * window); extern int Win32_SetWindowShape(SDL_WindowShaper *shaper,SDL_Surface *shape,SDL_WindowShapeMode *shapeMode); extern int Win32_ResizeWindowShape(SDL_Window *window);