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