src/video/SDL_shape.c
author Eli Gottlieb <eligottlieb@gmail.com>
Mon, 09 Aug 2010 20:27:45 -0400
changeset 4841 740e833b2c00
parent 4839 05d172e92b52
child 4843 0998d1b5dd23
permissions -rw-r--r--
Fixed overwriting of SDL_shape.c in merge.
eligottlieb@4765
     1
/*
eligottlieb@4765
     2
    SDL - Simple DirectMedia Layer
eligottlieb@4765
     3
    Copyright (C) 2010 Eli Gottlieb
eligottlieb@4765
     4
eligottlieb@4765
     5
    This library is free software; you can redistribute it and/or
eligottlieb@4765
     6
    modify it under the terms of the GNU Lesser General Public
eligottlieb@4765
     7
    License as published by the Free Software Foundation; either
eligottlieb@4765
     8
    version 2.1 of the License, or (at your option) any later version.
eligottlieb@4765
     9
eligottlieb@4765
    10
    This library is distributed in the hope that it will be useful,
eligottlieb@4765
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
eligottlieb@4765
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
eligottlieb@4765
    13
    Lesser General Public License for more details.
eligottlieb@4765
    14
eligottlieb@4765
    15
    You should have received a copy of the GNU Lesser General Public
eligottlieb@4765
    16
    License along with this library; if not, write to the Free Software
eligottlieb@4765
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
eligottlieb@4765
    18
eligottlieb@4765
    19
    Eli Gottlieb
eligottlieb@4765
    20
    eligottlieb@gmail.com
eligottlieb@4765
    21
*/
eligottlieb@4769
    22
#include "SDL_config.h"
eligottlieb@4776
    23
eligottlieb@4769
    24
#include "SDL.h"
eligottlieb@4841
    25
#include "SDL_assert.h"
eligottlieb@4769
    26
#include "SDL_video.h"
eligottlieb@4769
    27
#include "SDL_sysvideo.h"
eligottlieb@4782
    28
#include "SDL_pixels.h"
eligottlieb@4782
    29
#include "SDL_surface.h"
eligottlieb@4765
    30
#include "SDL_shape.h"
eligottlieb@4841
    31
#include "SDL_shape_internals.h"
eligottlieb@4766
    32
eligottlieb@4841
    33
SDL_Window* SDL_CreateShapedWindow(const char *title,unsigned int x,unsigned int y,unsigned int w,unsigned int h,Uint32 flags) {
eligottlieb@4841
    34
	SDL_Window *result = SDL_CreateWindow(title,x,y,w,h,SDL_WINDOW_BORDERLESS | flags & !SDL_WINDOW_FULLSCREEN & !SDL_WINDOW_SHOWN);
eligottlieb@4841
    35
	if(result != NULL) {
eligottlieb@4841
    36
		result->shaper = result->display->device->shape_driver.CreateShaper(result);
eligottlieb@4841
    37
		if(result->shaper != NULL) {
eligottlieb@4841
    38
			result->shaper->usershownflag = flags & SDL_WINDOW_SHOWN;
eligottlieb@4841
    39
			result->shaper->mode.mode = ShapeModeDefault;
eligottlieb@4841
    40
			result->shaper->mode.parameters.binarizationCutoff = 1;
eligottlieb@4841
    41
			result->shaper->hasshape = SDL_FALSE;
eligottlieb@4841
    42
			return result;
eligottlieb@4841
    43
		}
eligottlieb@4841
    44
		else {
eligottlieb@4841
    45
			SDL_DestroyWindow(result);
eligottlieb@4841
    46
			return NULL;
eligottlieb@4841
    47
		}
eligottlieb@4841
    48
	}
eligottlieb@4841
    49
	else
eligottlieb@4841
    50
		return NULL;
eligottlieb@4766
    51
}
eligottlieb@4766
    52
eligottlieb@4841
    53
SDL_bool SDL_IsShapedWindow(const SDL_Window *window) {
eligottlieb@4841
    54
	if(window == NULL)
eligottlieb@4841
    55
		return SDL_FALSE;
eligottlieb@4841
    56
	else
eligottlieb@4841
    57
		return (SDL_bool)(window->shaper != NULL);
eligottlieb@4782
    58
}
eligottlieb@4782
    59
eligottlieb@4813
    60
/* REQUIRES that bitmap point to a w-by-h bitmap with ppb pixels-per-byte. */
eligottlieb@4841
    61
void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode,SDL_Surface *shape,Uint8* bitmap,Uint8 ppb) {
eligottlieb@4841
    62
	int x = 0;
eligottlieb@4841
    63
	int y = 0;
eligottlieb@4841
    64
	Uint8 r = 0,g = 0,b = 0,alpha = 0;
eligottlieb@4841
    65
	Uint8* pixel = NULL;
eligottlieb@4841
    66
	Uint32 bitmap_pixel,pixel_value = 0,mask_value = 0;
eligottlieb@4841
    67
	SDL_Color key;
eligottlieb@4841
    68
	if(SDL_MUSTLOCK(shape))
eligottlieb@4841
    69
		SDL_LockSurface(shape);
eligottlieb@4841
    70
	pixel = (Uint8*)shape->pixels;
eligottlieb@4841
    71
	for(y = 0;y<shape->h;y++) {
eligottlieb@4841
    72
		for(x=0;x<shape->w;x++) {
eligottlieb@4841
    73
			alpha = 0;
eligottlieb@4841
    74
			pixel_value = 0;
eligottlieb@4841
    75
			pixel = (Uint8 *)(shape->pixels) + (y*shape->pitch) + (x*shape->format->BytesPerPixel);
eligottlieb@4841
    76
			switch(shape->format->BytesPerPixel) {
eligottlieb@4841
    77
				case(1):
eligottlieb@4841
    78
					pixel_value = *(Uint8*)pixel;
eligottlieb@4841
    79
					break;
eligottlieb@4841
    80
				case(2):
eligottlieb@4841
    81
					pixel_value = *(Uint16*)pixel;
eligottlieb@4841
    82
					break;
eligottlieb@4841
    83
				case(3):
eligottlieb@4841
    84
					pixel_value = *(Uint32*)pixel & (~shape->format->Amask);
eligottlieb@4841
    85
					break;
eligottlieb@4841
    86
				case(4):
eligottlieb@4841
    87
					pixel_value = *(Uint32*)pixel;
eligottlieb@4841
    88
					break;
eligottlieb@4841
    89
			}
eligottlieb@4841
    90
			SDL_GetRGBA(pixel_value,shape->format,&r,&g,&b,&alpha);
eligottlieb@4841
    91
			bitmap_pixel = y*shape->w + x;
eligottlieb@4841
    92
			switch(mode.mode) {
eligottlieb@4841
    93
				case(ShapeModeDefault):
eligottlieb@4841
    94
					mask_value = (alpha >= 1 ? 1 : 0);
eligottlieb@4841
    95
					break;
eligottlieb@4841
    96
				case(ShapeModeBinarizeAlpha):
eligottlieb@4841
    97
					mask_value = (alpha >= mode.parameters.binarizationCutoff ? 1 : 0);
eligottlieb@4841
    98
					break;
eligottlieb@4841
    99
				case(ShapeModeReverseBinarizeAlpha):
eligottlieb@4841
   100
					mask_value = (alpha <= mode.parameters.binarizationCutoff ? 1 : 0);
eligottlieb@4841
   101
					break;
eligottlieb@4841
   102
				case(ShapeModeColorKey):
eligottlieb@4841
   103
					key = mode.parameters.colorKey;
eligottlieb@4841
   104
					mask_value = ((key.r != r && key.g != g && key.b != b) ? 1 : 0);
eligottlieb@4841
   105
					break;
eligottlieb@4841
   106
			}
eligottlieb@4841
   107
			bitmap[bitmap_pixel / ppb] |= mask_value << (7 - ((ppb - 1) - (bitmap_pixel % ppb)));
eligottlieb@4841
   108
		}
eligottlieb@4841
   109
	}
eligottlieb@4841
   110
	if(SDL_MUSTLOCK(shape))
eligottlieb@4841
   111
		SDL_UnlockSurface(shape);
eligottlieb@4769
   112
}
eligottlieb@4769
   113
eligottlieb@4841
   114
SDL_ShapeTree* RecursivelyCalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* mask,SDL_Rect dimensions) {
eligottlieb@4841
   115
	int x = 0,y = 0;
eligottlieb@4841
   116
	Uint8* pixel = NULL;
eligottlieb@4841
   117
	Uint32 pixel_value = 0;
eligottlieb@4841
   118
	Uint8 r = 0,g = 0,b = 0,a = 0;
eligottlieb@4841
   119
	SDL_bool pixel_opaque = SDL_FALSE;
eligottlieb@4841
   120
	int last_opaque = -1;
eligottlieb@4841
   121
	SDL_Color key;
eligottlieb@4841
   122
	SDL_ShapeTree* result = (SDL_ShapeTree*)SDL_malloc(sizeof(SDL_ShapeTree));
eligottlieb@4841
   123
	SDL_Rect next = {0,0,0,0};
eligottlieb@4841
   124
	for(y=dimensions.y;y<dimensions.y + dimensions.h;y++)
eligottlieb@4841
   125
		for(x=dimensions.x;x<dimensions.x + dimensions.w;x++) {
eligottlieb@4841
   126
			pixel_value = 0;
eligottlieb@4841
   127
			pixel = (Uint8 *)(mask->pixels) + (y*mask->pitch) + (x*mask->format->BytesPerPixel);
eligottlieb@4841
   128
			switch(mask->format->BytesPerPixel) {
eligottlieb@4841
   129
				case(1):
eligottlieb@4841
   130
					pixel_value = *(Uint8*)pixel;
eligottlieb@4841
   131
					break;
eligottlieb@4841
   132
				case(2):
eligottlieb@4841
   133
					pixel_value = *(Uint16*)pixel;
eligottlieb@4841
   134
					break;
eligottlieb@4841
   135
				case(3):
eligottlieb@4841
   136
					pixel_value = *(Uint32*)pixel & (~mask->format->Amask);
eligottlieb@4841
   137
					break;
eligottlieb@4841
   138
				case(4):
eligottlieb@4841
   139
					pixel_value = *(Uint32*)pixel;
eligottlieb@4841
   140
					break;
eligottlieb@4841
   141
			}
eligottlieb@4841
   142
			SDL_GetRGBA(pixel_value,mask->format,&r,&g,&b,&a);
eligottlieb@4841
   143
			switch(mode.mode) {
eligottlieb@4841
   144
				case(ShapeModeDefault):
eligottlieb@4841
   145
					pixel_opaque = (a >= 1 ? SDL_TRUE : SDL_FALSE);
eligottlieb@4841
   146
					break;
eligottlieb@4841
   147
				case(ShapeModeBinarizeAlpha):
eligottlieb@4841
   148
					pixel_opaque = (a >= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
eligottlieb@4841
   149
					break;
eligottlieb@4841
   150
				case(ShapeModeReverseBinarizeAlpha):
eligottlieb@4841
   151
					pixel_opaque = (a <= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
eligottlieb@4841
   152
					break;
eligottlieb@4841
   153
				case(ShapeModeColorKey):
eligottlieb@4841
   154
					key = mode.parameters.colorKey;
eligottlieb@4841
   155
					pixel_opaque = ((key.r == r && key.g == g && key.b == b) ? SDL_TRUE : SDL_FALSE);
eligottlieb@4841
   156
					break;
eligottlieb@4841
   157
			}
eligottlieb@4841
   158
			if(last_opaque == -1)
eligottlieb@4841
   159
				last_opaque = pixel_opaque;
eligottlieb@4841
   160
			if(last_opaque != pixel_opaque) {
eligottlieb@4841
   161
				result->kind = QuadShape;
eligottlieb@4841
   162
				//These will stay the same.
eligottlieb@4841
   163
				next.w = dimensions.w / 2;
eligottlieb@4841
   164
				next.h = dimensions.h / 2;
eligottlieb@4841
   165
				//These will change from recursion to recursion.
eligottlieb@4841
   166
				next.x = dimensions.x;
eligottlieb@4841
   167
				next.y = dimensions.y;
eligottlieb@4841
   168
				result->data.children.upleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
eligottlieb@4841
   169
				next.x = dimensions.w / 2;
eligottlieb@4841
   170
				//Unneeded: next.y = dimensions.y;
eligottlieb@4841
   171
				result->data.children.upright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
eligottlieb@4841
   172
				next.x = dimensions.x;
eligottlieb@4841
   173
				next.y = dimensions.h / 2;
eligottlieb@4841
   174
				result->data.children.downleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
eligottlieb@4841
   175
				next.x = dimensions.w / 2;
eligottlieb@4841
   176
				//Unneeded: next.y = dimensions.h / 2 + 1;
eligottlieb@4841
   177
				result->data.children.downright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
eligottlieb@4841
   178
				return result;
eligottlieb@4841
   179
			}
eligottlieb@4841
   180
		}
eligottlieb@4841
   181
	//If we never recursed, all the pixels in this quadrant have the same "value".
eligottlieb@4841
   182
	result->kind = (last_opaque == SDL_TRUE ? OpaqueShape : TransparentShape);
eligottlieb@4841
   183
	result->data.shape = dimensions;
eligottlieb@4841
   184
	return result;
eligottlieb@4813
   185
}
eligottlieb@4813
   186
eligottlieb@4841
   187
SDL_ShapeTree* SDL_CalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* shape) {
eligottlieb@4841
   188
	SDL_Rect dimensions = {0,0,shape->w,shape->h};
eligottlieb@4841
   189
	SDL_ShapeTree* result = NULL;
eligottlieb@4841
   190
	if(SDL_MUSTLOCK(shape))
eligottlieb@4841
   191
		SDL_LockSurface(shape);
eligottlieb@4841
   192
	result = RecursivelyCalculateShapeTree(mode,shape,dimensions);
eligottlieb@4841
   193
	if(SDL_MUSTLOCK(shape))
eligottlieb@4841
   194
		SDL_UnlockSurface(shape);
eligottlieb@4841
   195
	return result;
eligottlieb@4813
   196
}
eligottlieb@4813
   197
eligottlieb@4841
   198
void SDL_TraverseShapeTree(SDL_ShapeTree *tree,SDL_TraversalFunction function,void* closure) {
eligottlieb@4841
   199
	SDL_assert(tree != NULL);
eligottlieb@4841
   200
	if(tree->kind == QuadShape) {
eligottlieb@4841
   201
		SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upleft,function,closure);
eligottlieb@4841
   202
		SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upright,function,closure);
eligottlieb@4841
   203
		SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downleft,function,closure);
eligottlieb@4841
   204
		SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downright,function,closure);
eligottlieb@4841
   205
	}
eligottlieb@4841
   206
	else
eligottlieb@4841
   207
		function(tree,closure);
eligottlieb@4813
   208
}
eligottlieb@4813
   209
eligottlieb@4841
   210
void SDL_FreeShapeTree(SDL_ShapeTree** shapeTree) {
eligottlieb@4841
   211
	if((*shapeTree)->kind == QuadShape) {
eligottlieb@4841
   212
		SDL_FreeShapeTree((SDL_ShapeTree **)&(*shapeTree)->data.children.upleft);
eligottlieb@4841
   213
		SDL_FreeShapeTree((SDL_ShapeTree **)&(*shapeTree)->data.children.upright);
eligottlieb@4841
   214
		SDL_FreeShapeTree((SDL_ShapeTree **)&(*shapeTree)->data.children.downleft);
eligottlieb@4841
   215
		SDL_FreeShapeTree((SDL_ShapeTree **)&(*shapeTree)->data.children.downright);
eligottlieb@4841
   216
	}
eligottlieb@4841
   217
	SDL_free(*shapeTree);
eligottlieb@4841
   218
	*shapeTree = NULL;
eligottlieb@4813
   219
}
eligottlieb@4813
   220
eligottlieb@4841
   221
int SDL_SetWindowShape(SDL_Window *window,SDL_Surface *shape,SDL_WindowShapeMode *shapeMode) {
eligottlieb@4841
   222
	int result;
eligottlieb@4841
   223
	if(window == NULL || !SDL_IsShapedWindow(window))
eligottlieb@4841
   224
		//The window given was not a shapeable window.
eligottlieb@4841
   225
		return SDL_NONSHAPEABLE_WINDOW;
eligottlieb@4841
   226
	if(shape == NULL)
eligottlieb@4841
   227
		//Invalid shape argument.
eligottlieb@4841
   228
		return SDL_INVALID_SHAPE_ARGUMENT;
eligottlieb@4841
   229
	
eligottlieb@4841
   230
	if(shapeMode != NULL)
eligottlieb@4841
   231
		window->shaper->mode = *shapeMode;
eligottlieb@4841
   232
	//TODO: Platform-specific implementations of SetWindowShape.  X11 is finished.  Win32 is finished.  Debugging is in progress on both.
eligottlieb@4841
   233
	result = window->display->device->shape_driver.SetWindowShape(window->shaper,shape,shapeMode);
eligottlieb@4841
   234
	window->shaper->hasshape = SDL_TRUE;
eligottlieb@4841
   235
	if((window->shaper->usershownflag & SDL_WINDOW_SHOWN) == SDL_WINDOW_SHOWN) {
eligottlieb@4841
   236
		SDL_ShowWindow(window);
eligottlieb@4841
   237
		window->shaper->usershownflag &= !SDL_WINDOW_SHOWN;
eligottlieb@4841
   238
	}
eligottlieb@4841
   239
	return result;
eligottlieb@4782
   240
}
eligottlieb@4782
   241
eligottlieb@4841
   242
SDL_bool SDL_WindowHasAShape(SDL_Window *window) {
eligottlieb@4841
   243
	if (window == NULL || !SDL_IsShapedWindow(window))
eligottlieb@4841
   244
		return SDL_FALSE;
eligottlieb@4841
   245
	return window->shaper->hasshape;
eligottlieb@4778
   246
}
eligottlieb@4778
   247
eligottlieb@4841
   248
int SDL_GetShapedWindowMode(SDL_Window *window,SDL_WindowShapeMode *shapeMode) {
eligottlieb@4841
   249
	if(window != NULL && SDL_IsShapedWindow(window)) {
eligottlieb@4841
   250
		if(shapeMode == NULL) {
eligottlieb@4841
   251
			if(SDL_WindowHasAShape(window))
eligottlieb@4841
   252
				//The window given has a shape.
eligottlieb@4841
   253
				return 0;
eligottlieb@4841
   254
			else
eligottlieb@4841
   255
				//The window given is shapeable but lacks a shape.
eligottlieb@4841
   256
				return SDL_WINDOW_LACKS_SHAPE;
eligottlieb@4841
   257
		}
eligottlieb@4841
   258
		else {
eligottlieb@4841
   259
			*shapeMode = window->shaper->mode;
eligottlieb@4841
   260
			return 0;
eligottlieb@4841
   261
		}
eligottlieb@4841
   262
	}
eligottlieb@4841
   263
	else
eligottlieb@4841
   264
		//The window given is not a valid shapeable window.
eligottlieb@4841
   265
		return SDL_NONSHAPEABLE_WINDOW;
eligottlieb@4778
   266
}