diff src/video/win32/SDL_win32shape.c @ 4813:5b4c7d7d8953

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.
author Eli Gottlieb <eligottlieb@gmail.com>
date Wed, 28 Jul 2010 23:35:24 -0400
parents 329708ffe2a7
children 93402b9dd20c
line wrap: on
line diff
--- 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 <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 @@
 	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 <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);
-
-	/*
-	 * 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;