Commit 9a3f51f3 authored by Eli Gottlieb's avatar Eli Gottlieb

Wrote out the system for breaking shape-masks into quad-trees of rectangles,...

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.
parent 3433f102
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "SDL_pixels.h" #include "SDL_pixels.h"
#include "SDL_surface.h" #include "SDL_surface.h"
#include "SDL_shape.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* 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); 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) { ...@@ -55,7 +56,7 @@ SDL_bool SDL_IsShapedWindow(const SDL_Window *window) {
return (SDL_bool)(window->shaper != NULL); 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) { void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode,SDL_Surface *shape,Uint8* bitmap,Uint8 ppb,Uint8 value) {
int x = 0; int x = 0;
int y = 0; int y = 0;
...@@ -105,6 +106,111 @@ void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode,SDL_Surface *shape,Uint8* ...@@ -105,6 +106,111 @@ void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode,SDL_Surface *shape,Uint8*
SDL_UnlockSurface(shape); 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 SDL_SetWindowShape(SDL_Window *window,SDL_Surface *shape,SDL_WindowShapeMode *shapeMode) {
int result; int result;
if(window == NULL || !SDL_IsShapedWindow(window)) if(window == NULL || !SDL_IsShapedWindow(window))
......
...@@ -23,10 +23,6 @@ ...@@ -23,10 +23,6 @@
#include <windows.h> #include <windows.h>
#include "SDL_win32shape.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* Win32_CreateShaper(SDL_Window * window) {
SDL_WindowShaper* result = malloc(sizeof(SDL_WindowShaper)); SDL_WindowShaper* result = malloc(sizeof(SDL_WindowShaper));
result->window = window; result->window = window;
...@@ -35,315 +31,48 @@ SDL_WindowShaper* Win32_CreateShaper(SDL_Window * window) { ...@@ -35,315 +31,48 @@ SDL_WindowShaper* Win32_CreateShaper(SDL_Window * window) {
result->usershownflag = 0; result->usershownflag = 0;
//Put some driver-data here. //Put some driver-data here.
window->shaper = result; window->shaper = result;
int resized_properly = X11ResizeWindowShape(window); int resized_properly = Win32_ResizeWindowShape(window);
assert(resized_properly == 0); assert(resized_properly == 0);
return result; 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) { int Win32_SetWindowShape(SDL_WindowShaper *shaper,SDL_Surface *shape,SDL_WindowShapeMode *shapeMode) {
assert(shaper != NULL && shape != NULL); 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))) 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 -2; return SDL_INVALID_SHAPE_ARGUMENT;
if(shape->w != shaper->window->w || shape->h != shaper->window->h)
return -3;
/*
* 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; SDL_ShapeData *data = (SDL_ShapeData*)shaper->driverdata;
data->mask_tree = SDL_CalculateShapeTree(shapeMode,shape,SDL_FALSE);
/* /*
* Transfer binarized mask image into workbuffer * Start with empty region
*/ */
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 SDL_TraverseShapeTree(data->mask_tree,&CombineRectRegions,&mask_region);
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);
}
/* /*
* Set the new region mask for the window * 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 0;
* Return value
*/
return (0);
} }
int Win32_ResizeWindowShape(SDL_Window *window) { int Win32_ResizeWindowShape(SDL_Window *window) {
SDL_ShapeData* data = window->shaper->driverdata; SDL_ShapeData* data = window->shaper->driverdata;
assert(data != NULL); assert(data != NULL);
unsigned int buffersize = window->w * window->h; if(data->mask_tree != NULL)
if(data->buffersize != buffersize || data->shapebuffer == NULL) { SDL_FreeShapeTree(&data->mask_tree);
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);
window->shaper->usershownflag |= window->flags & SDL_WINDOW_SHOWN; window->shaper->usershownflag |= window->flags & SDL_WINDOW_SHOWN;
......
...@@ -28,13 +28,12 @@ ...@@ -28,13 +28,12 @@
#include "SDL_video.h" #include "SDL_video.h"
#include "SDL_shape.h" #include "SDL_shape.h"
#include "../SDL_sysvideo.h" #include "../SDL_sysvideo.h"
#include "../SDL_shape_internals.h"
typedef struct { typedef struct {
void* shapebuffer; SDL_ShapeTree *mask_tree;
Uint32 buffersize;
} SDL_ShapeData; } 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 SDL_WindowShaper* Win32_CreateShaper(SDL_Window * window);
extern int Win32_SetWindowShape(SDL_WindowShaper *shaper,SDL_Surface *shape,SDL_WindowShapeMode *shapeMode); extern int Win32_SetWindowShape(SDL_WindowShaper *shaper,SDL_Surface *shape,SDL_WindowShapeMode *shapeMode);
extern int Win32_ResizeWindowShape(SDL_Window *window); extern int Win32_ResizeWindowShape(SDL_Window *window);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment