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 }