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.
This commit is contained in:
parent
3433f10279
commit
9a3f51f3c5
3 changed files with 130 additions and 296 deletions
|
@ -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 @@ SDL_bool SDL_IsShapedWindow(const SDL_Window *window) {
|
|||
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 @@ void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode,SDL_Surface *shape,Uint8*
|
|||
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;y<dimensions.h;y++)
|
||||
for(x=dimensions.x;x<dimensions.w;x++) {
|
||||
pixel_value = 0;
|
||||
pixel = (Uint8 *)(mask->pixels) + (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))
|
||||
|
|
|
@ -23,10 +23,6 @@
|
|||
#include <windows.h>
|
||||
#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 @@ SDL_WindowShaper* Win32_CreateShaper(SDL_Window * window) {
|
|||
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);
|
||||
HRGN mask_region = 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);
|
||||
|
||||
//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 <height; y++) {
|
||||
Uint8 inside = 0;
|
||||
for (x = -1; x <width; x++) {
|
||||
int newtargetcount;
|
||||
POINT newtarget[5];
|
||||
/*
|
||||
* Define local variables
|
||||
*/
|
||||
int newtargetcount;
|
||||
POINT newtarget[5];
|
||||
|
||||
|
||||
/*
|
||||
* Update visible region
|
||||
*/
|
||||
if (*curpos)
|
||||
visible = 1;
|
||||
/*
|
||||
* Determine visible bounds
|
||||
*/
|
||||
if (x < vxmin)
|
||||
vxmin = x;
|
||||
if (x > 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);
|
||||
SetWindowRgn((SDL_WindowData*)(shaper->window->driverdata)->hwnd, mask_region, TRUE);
|
||||
|
||||
/*
|
||||
* Return value
|
||||
*/
|
||||
return (0);
|
||||
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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue