Mercurial > sdl-ios-xcode
comparison 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 |
comparison
equal
deleted
inserted
replaced
4812:06a03d08cefb | 4813:5b4c7d7d8953 |
---|---|
21 */ | 21 */ |
22 | 22 |
23 #include <windows.h> | 23 #include <windows.h> |
24 #include "SDL_win32shape.h" | 24 #include "SDL_win32shape.h" |
25 | 25 |
26 SDL_Window* Win32_CreateShapedWindow(const char *title,unsigned int x,unsigned int y,unsigned int w,unsigned int h,Uint32 flags) { | |
27 return SDL_CreateWindow(title,x,y,w,h,flags); | |
28 } | |
29 | |
30 SDL_WindowShaper* Win32_CreateShaper(SDL_Window * window) { | 26 SDL_WindowShaper* Win32_CreateShaper(SDL_Window * window) { |
31 SDL_WindowShaper* result = malloc(sizeof(SDL_WindowShaper)); | 27 SDL_WindowShaper* result = malloc(sizeof(SDL_WindowShaper)); |
32 result->window = window; | 28 result->window = window; |
33 result->mode.mode = ShapeModeDefault; | 29 result->mode.mode = ShapeModeDefault; |
34 result->mode.parameters.binarizationCutoff = 1; | 30 result->mode.parameters.binarizationCutoff = 1; |
35 result->usershownflag = 0; | 31 result->usershownflag = 0; |
36 //Put some driver-data here. | 32 //Put some driver-data here. |
37 window->shaper = result; | 33 window->shaper = result; |
38 int resized_properly = X11ResizeWindowShape(window); | 34 int resized_properly = Win32_ResizeWindowShape(window); |
39 assert(resized_properly == 0); | 35 assert(resized_properly == 0); |
40 return result; | 36 return result; |
41 } | 37 } |
42 | 38 |
39 void CombineRectRegions(SDL_ShapeTree* node,HRGN* mask_region) { | |
40 if(node->kind == OpaqueShape) { | |
41 HRGN temp_region = CreateRectRgn(node->data.shape.x,node->data.shape.y,node->data.shape.w,node->data.shape.h); | |
42 CombineRgn(*mask_region,*mask_region,temp_region, RGN_OR); | |
43 DeleteObject(temp_region); | |
44 } | |
45 } | |
46 | |
43 int Win32_SetWindowShape(SDL_WindowShaper *shaper,SDL_Surface *shape,SDL_WindowShapeMode *shapeMode) { | 47 int Win32_SetWindowShape(SDL_WindowShaper *shaper,SDL_Surface *shape,SDL_WindowShapeMode *shapeMode) { |
44 assert(shaper != NULL && shape != NULL); | 48 assert(shaper != NULL && shape != NULL); |
45 if(!SDL_ISPIXELFORMAT_ALPHA(SDL_MasksToPixelFormatEnum(shape->format->BitsPerPixel,shape->format->Rmask,shape->format->Gmask,shape->format->Bmask,shape->format->Amask))) | 49 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) |
46 return -2; | 50 return SDL_INVALID_SHAPE_ARGUMENT; |
47 if(shape->w != shaper->window->w || shape->h != shaper->window->h) | 51 |
48 return -3; | 52 SDL_ShapeData *data = (SDL_ShapeData*)shaper->driverdata; |
53 data->mask_tree = SDL_CalculateShapeTree(shapeMode,shape,SDL_FALSE); | |
49 | 54 |
50 /* | 55 /* |
51 * Start with empty region | 56 * Start with empty region |
52 */ | 57 */ |
53 HRGN MaskRegion = CreateRectRgn(0, 0, 0, 0); | 58 HRGN mask_region = CreateRectRgn(0, 0, 0, 0); |
54 | 59 |
55 unsigned int pitch = shape->pitch; | 60 SDL_TraverseShapeTree(data->mask_tree,&CombineRectRegions,&mask_region); |
56 unsigned int width = shape->width; | |
57 unsigned int height = shape->height; | |
58 unsigned int dy = pitch - width; | |
59 | |
60 SDL_ShapeData *data = (SDL_ShapeData*)shaper->driverdata; | |
61 /* | |
62 * Transfer binarized mask image into workbuffer | |
63 */ | |
64 SDL_CalculateShapeBitmap(shaper->mode,shape,data->shapebuffer,1,0xff); | |
65 | |
66 //Move code over to here from AW_windowShape.c | |
67 Uint8 *pos1 = data->shapebuffer + width - 1; | |
68 Uint8 *pos2 = (Uint8*) pos1 + 1; | |
69 int x = 0,y = 0; | |
70 int visible = 0; | |
71 int vxmin = shape->width - 1; | |
72 int vxmax = -1; | |
73 int vymin = shape->height - 1; | |
74 int vymax = -1; | |
75 for (y = 0; y <height; y++) { | |
76 Uint8 inside = 0; | |
77 for (x = -1; x <width; x++) { | |
78 int newtargetcount; | |
79 POINT newtarget[5]; | |
80 /* | |
81 * Define local variables | |
82 */ | |
83 int newtargetcount; | |
84 POINT newtarget[5]; | |
85 | |
86 | |
87 /* | |
88 * Update visible region | |
89 */ | |
90 if (*curpos) | |
91 visible = 1; | |
92 /* | |
93 * Determine visible bounds | |
94 */ | |
95 if (x < vxmin) | |
96 vxmin = x; | |
97 if (x > vxmax) | |
98 vxmax = x; | |
99 if (y < vxymin) | |
100 vxymin = y; | |
101 if (y > vymax) | |
102 vymax = y; | |
103 | |
104 /* | |
105 * Check for starting point | |
106 */ | |
107 Uint8 *TL, *TR, *BL, *BR; | |
108 int target_x, target_y, lasttarget_x, lasttarget_y; | |
109 if (((!*curpos) && (*curpos2 == 0xFF)) || ((!*curpos2) && (*curpos == 0xFF))) { | |
110 if (!*curpos) { | |
111 BR = curpos2; | |
112 BL = (Uint8 *) (BR - 1); | |
113 TR = (Uint8 *) (BR - width); | |
114 TL = (Uint8 *) (TR - 1); | |
115 target_x = x; | |
116 target_y = y; | |
117 } | |
118 else { | |
119 BR = curpos2 + 1; | |
120 BL = (Uint8 *) (BR - 1); | |
121 TR = (Uint8 *) (BR - width); | |
122 TL = (Uint8 *) (TR - 1); | |
123 target_x = x + 1; | |
124 target_y = y; | |
125 } | |
126 | |
127 lasttarget_x = 0; | |
128 lasttarget_y = 0; | |
129 int firsttime = 1; | |
130 pos_array_pos = 0; | |
131 | |
132 while ((target_x != x) || (target_y != y) || firsttime) { | |
133 /* | |
134 * New array index | |
135 */ | |
136 firsttime = 0; | |
137 pos_array_pos++; | |
138 /* | |
139 * Check array index | |
140 */ | |
141 if (pos_array_pos >= 4096) { | |
142 SDL_SetError("Exceeded maximum number of polygon points."); | |
143 pos_array_pos--; | |
144 } | |
145 | |
146 /* | |
147 * Store point in array | |
148 */ | |
149 pos_array[pos_array_pos].x = target_x + 1; | |
150 pos_array[pos_array_pos].y = target_y; | |
151 | |
152 /* | |
153 * Mark the four poles as visited | |
154 */ | |
155 if (*TL) | |
156 *TL = 0x99; | |
157 if (*BL) | |
158 *BL = 0x99; | |
159 if (*TR) | |
160 *TR = 0x99; | |
161 if (*BR) | |
162 *BR = 0x99; | |
163 | |
164 newtargetcount = 0; | |
165 if ((*TL || *TR) && (*TL != *TR)) { | |
166 newtargetcount++; | |
167 newtarget[newtargetcount].x = 0; | |
168 newtarget[newtargetcount].y = -1; | |
169 } | |
170 | |
171 if ((*TR || *BR) && (*TR != *BR)) { | |
172 newtargetcount++; | |
173 newtarget[newtargetcount].x = 1; | |
174 newtarget[newtargetcount].y = 0; | |
175 } | |
176 | |
177 if ((*BL || *BR) && (*BL != *BR)) { | |
178 newtargetcount++; | |
179 newtarget[newtargetcount].x = 0; | |
180 newtarget[newtargetcount].y = 1; | |
181 } | |
182 | |
183 if ((*TL || *BL) && (*TL != *BL)) { | |
184 newtargetcount++; | |
185 newtarget[newtargetcount].x = -1; | |
186 newtarget[newtargetcount].y = 0; | |
187 } | |
188 | |
189 switch (newtargetcount) { | |
190 case 1: | |
191 SDL_SetError("Cropping error - Newtargetcount=1."); | |
192 return (-1); | |
193 break; | |
194 | |
195 case 2: | |
196 if ((target_x + newtarget[1].x != lasttarget_x) || (target_y + newtarget[1].y != lasttarget_y)) { | |
197 lasttarget_x = target_x; | |
198 lasttarget_y = target_y; | |
199 target_x = target_x + newtarget[1].x; | |
200 target_y = target_y + newtarget[1].y; | |
201 } | |
202 else { | |
203 lasttarget_x = target_x; | |
204 lasttarget_y = target_y; | |
205 target_x = target_x + newtarget[2].x; | |
206 target_y = target_y + newtarget[2].y; | |
207 } | |
208 break; | |
209 | |
210 case 3: | |
211 SDL_SetError("Cropping error - Newtargetcount=3."); | |
212 return (-1); | |
213 break; | |
214 | |
215 case 4: | |
216 if (lasttarget_x > target_x) { | |
217 lasttarget_x = target_x; | |
218 lasttarget_y = target_y; | |
219 if (*TR != 0x00) | |
220 target_y--; | |
221 else | |
222 target_y++; | |
223 } | |
224 else if (lasttarget_y > target_y) { | |
225 lasttarget_x = target_x; | |
226 lasttarget_y = target_y; | |
227 if (*BL != 0x00) | |
228 target_x--; | |
229 else | |
230 target_x++; | |
231 } | |
232 else if (lasttarget_x < target_x) { | |
233 lasttarget_x = target_x; | |
234 lasttarget_y = target_y; | |
235 if (*TL != 0x00) | |
236 target_y--; | |
237 else | |
238 target_y++; | |
239 } | |
240 else if (lasttarget_y < target_y) { | |
241 lasttarget_x = target_x; | |
242 lasttarget_y = target_y; | |
243 if (*TL != 0x00) | |
244 target_x--; | |
245 else | |
246 target_x++; | |
247 } | |
248 else { | |
249 SDL_SetError("Cropping error - no possible targets on newtargetcount=4."); | |
250 return (-1); | |
251 } | |
252 break; | |
253 | |
254 default: | |
255 SDL_SetError("Cropping error - Newtargetcount invalid."); | |
256 return (-1); | |
257 break; | |
258 } | |
259 | |
260 if (target_x > lasttarget_x) | |
261 TL = (Uint8 *) (TL + 1); | |
262 else if (target_x < lasttarget_x) | |
263 TL = (Uint8 *) (TL - 1); | |
264 else if (target_y > lasttarget_y) | |
265 TL = (Uint8 *) (TL + width); | |
266 else if (target_y < lasttarget_y) | |
267 TL = (Uint8 *) (TL - width); | |
268 else { | |
269 SDL_SetError("Cropping error - no new target."); | |
270 return (-1); | |
271 } | |
272 | |
273 BL = (Uint8 *) (TL + width); | |
274 TR = (Uint8 *) (TL + 1); | |
275 BR = (Uint8 *) (BL + 1); | |
276 } // End of while loop | |
277 | |
278 /* | |
279 * Apply the mask to the cropping region | |
280 */ | |
281 if (pos_array_pos >= 4) { | |
282 TempRegion = CreatePolygonRgn(&(pos_array[1]), pos_array_pos, WINDING); | |
283 if (TempRegion == NULL) { | |
284 SDL_SetError("Cropping error - unable to create polygon."); | |
285 return (-1); | |
286 } | |
287 | |
288 /* | |
289 * Add current region to final mask region | |
290 */ | |
291 if (inside) | |
292 CombineRgn(MaskRegion, MaskRegion, TempRegion, RGN_DIFF); | |
293 else | |
294 CombineRgn(MaskRegion, MaskRegion, TempRegion, RGN_OR); | |
295 | |
296 /* | |
297 * Remove temporary region | |
298 */ | |
299 DeleteObject(TempRegion); | |
300 } | |
301 | |
302 /* | |
303 * Switch sides | |
304 */ | |
305 inside = !inside; | |
306 } | |
307 else if ((*curpos) && (!*curpos2)) | |
308 inside = !inside; | |
309 else if ((!*curpos) && (*curpos2)) | |
310 inside = !inside; | |
311 | |
312 curpos++; | |
313 curpos2++; | |
314 } | |
315 curpos = (Uint8 *) (curpos + 2 * enlarge_mask - 1); | |
316 curpos2 = (Uint8 *) (curpos + 1); | |
317 } | |
318 | 61 |
319 /* | 62 /* |
320 * Set the new region mask for the window | 63 * Set the new region mask for the window |
321 */ | 64 */ |
322 SetWindowRgn((SDL_WindowData*)(shaper->window->driverdata)->hwnd, MaskRegion, TRUE); | 65 SetWindowRgn((SDL_WindowData*)(shaper->window->driverdata)->hwnd, mask_region, TRUE); |
323 | 66 |
324 /* | 67 return 0; |
325 * Return value | |
326 */ | |
327 return (0); | |
328 } | 68 } |
329 | 69 |
330 int Win32_ResizeWindowShape(SDL_Window *window) { | 70 int Win32_ResizeWindowShape(SDL_Window *window) { |
331 SDL_ShapeData* data = window->shaper->driverdata; | 71 SDL_ShapeData* data = window->shaper->driverdata; |
332 assert(data != NULL); | 72 assert(data != NULL); |
333 | 73 |
334 unsigned int buffersize = window->w * window->h; | 74 if(data->mask_tree != NULL) |
335 if(data->buffersize != buffersize || data->shapebuffer == NULL) { | 75 SDL_FreeShapeTree(&data->mask_tree); |
336 data->buffersize = buffersize; | |
337 if(data->shapebuffer != NULL) | |
338 free(data->shapebuffer); | |
339 data->shapebuffer = malloc(data->buffersize); | |
340 if(data->shapebuffer == NULL) { | |
341 SDL_SetError("Could not allocate memory for shaped-window bitmap."); | |
342 return -1; | |
343 } | |
344 } | |
345 else | |
346 memset(data->shapebuffer,0,data->buffersize); | |
347 | 76 |
348 window->shaper->usershownflag |= window->flags & SDL_WINDOW_SHOWN; | 77 window->shaper->usershownflag |= window->flags & SDL_WINDOW_SHOWN; |
349 | 78 |
350 return 0; | 79 return 0; |
351 } | 80 } |