34cf4058 |
1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | |
22 | #include <SDL_surface.h> |
23 | |
24 | typedef struct |
25 | { |
26 | Uint8 *src; |
27 | int src_w, src_h; |
28 | int src_pitch; |
29 | int src_skip; |
30 | Uint8 *dst; |
31 | int dst_w, dst_h; |
32 | int dst_pitch; |
33 | int dst_skip; |
34 | SDL_PixelFormat *src_fmt; |
35 | SDL_PixelFormat *dst_fmt; |
36 | Uint8 *table; |
37 | int flags; |
38 | Uint32 colorkey; |
39 | Uint8 r, g, b, a; |
40 | } SDL_BlitInfo; |
41 | |
42 | /* Blit mapping definition */ |
43 | typedef struct SDL_BlitMap |
44 | { |
45 | SDL_Surface *dst; |
46 | int identity; |
47 | SDL_blit blit; |
48 | void *data; |
49 | SDL_BlitInfo info; |
50 | |
51 | /* the version count matches the destination; mismatch indicates |
52 | an invalid mapping */ |
53 | Uint32 dst_palette_version; |
54 | Uint32 src_palette_version; |
55 | } SDL_BlitMap; |
56 | |
57 | typedef struct SDL_VideoInfo |
58 | { |
59 | Uint32 hw_available:1; |
60 | Uint32 wm_available:1; |
61 | Uint32 UnusedBits1:6; |
62 | Uint32 UnusedBits2:1; |
63 | Uint32 blit_hw:1; |
64 | Uint32 blit_hw_CC:1; |
65 | Uint32 blit_hw_A:1; |
66 | Uint32 blit_sw:1; |
67 | Uint32 blit_sw_CC:1; |
68 | Uint32 blit_sw_A:1; |
69 | Uint32 blit_fill:1; |
70 | Uint32 UnusedBits3:16; |
71 | Uint32 video_mem; |
72 | |
73 | SDL_PixelFormat *vfmt; |
74 | |
75 | int current_w; |
76 | int current_h; |
77 | } SDL_VideoInfo; |
78 | |
79 | #define SDL_ANYFORMAT 0x00100000 |
80 | #define SDL_HWPALETTE 0x00200000 |
81 | #define SDL_FULLSCREEN 0x00800000 |
82 | #define SDL_RESIZABLE 0x01000000 |
83 | #define SDL_NOFRAME 0x02000000 |
84 | #define SDL_OPENGL 0x04000000 |
85 | #define SDL_HWSURFACE 0x08000001 /**< \note Not used */ |
86 | |
87 | #define SDL_BUTTON_WHEELUP 4 |
88 | #define SDL_BUTTON_WHEELDOWN 5 |
89 | |
90 | int initialized_video = 0; |
91 | |
92 | static SDL_Window *SDL_VideoWindow = NULL; |
93 | static SDL_Surface *SDL_WindowSurface = NULL; |
94 | static SDL_Surface *SDL_VideoSurface = NULL; |
95 | static SDL_Surface *SDL_ShadowSurface = NULL; |
96 | static SDL_Surface *SDL_PublicSurface = NULL; |
97 | static SDL_Rect SDL_VideoViewport; |
98 | static char *wm_title = NULL; |
99 | static Uint32 SDL_VideoFlags = 0; |
100 | static SDL_GLContext *SDL_VideoContext = NULL; |
101 | static SDL_Surface *SDL_VideoIcon; |
102 | |
103 | static void |
104 | SDL_WM_SetCaption(const char *title, const char *icon) |
105 | { |
106 | if (wm_title) { |
107 | SDL_free(wm_title); |
108 | } |
109 | if (title) { |
110 | wm_title = SDL_strdup(title); |
111 | } else { |
112 | wm_title = NULL; |
113 | } |
114 | SDL_SetWindowTitle(SDL_VideoWindow, wm_title); |
115 | } |
116 | |
117 | static int |
118 | GetVideoDisplay() |
119 | { |
120 | const char *variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_DISPLAY"); |
121 | if ( !variable ) { |
122 | variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_HEAD"); |
123 | } |
124 | if ( variable ) { |
125 | return SDL_atoi(variable); |
126 | } else { |
127 | return 0; |
128 | } |
129 | } |
130 | |
131 | static const SDL_VideoInfo * |
132 | SDL_GetVideoInfo(void) |
133 | { |
134 | static SDL_VideoInfo info; |
135 | SDL_DisplayMode mode; |
136 | |
137 | /* Memory leak, compatibility code, who cares? */ |
138 | if (!info.vfmt && SDL_GetDesktopDisplayMode(GetVideoDisplay(), &mode) == 0) { |
139 | info.vfmt = SDL_AllocFormat(mode.format); |
140 | info.current_w = mode.w; |
141 | info.current_h = mode.h; |
142 | } |
143 | return &info; |
144 | } |
145 | |
146 | static SDL_Rect ** |
147 | SDL_ListModes(const SDL_PixelFormat * format, Uint32 flags) |
148 | { |
149 | int i, nmodes; |
150 | SDL_Rect **modes; |
151 | |
152 | if (!initialized_video) { |
153 | return NULL; |
154 | } |
155 | |
156 | if (!(flags & SDL_FULLSCREEN)) { |
157 | return (SDL_Rect **) (-1); |
158 | } |
159 | |
160 | if (!format) { |
161 | format = SDL_GetVideoInfo()->vfmt; |
162 | } |
163 | |
164 | /* Memory leak, but this is a compatibility function, who cares? */ |
165 | nmodes = 0; |
166 | modes = NULL; |
167 | for (i = 0; i < SDL_GetNumDisplayModes(GetVideoDisplay()); ++i) { |
168 | SDL_DisplayMode mode; |
169 | int bpp; |
170 | |
171 | SDL_GetDisplayMode(GetVideoDisplay(), i, &mode); |
172 | if (!mode.w || !mode.h) { |
173 | return (SDL_Rect **) (-1); |
174 | } |
175 | |
176 | /* Copied from src/video/SDL_pixels.c:SDL_PixelFormatEnumToMasks */ |
177 | if (SDL_BYTESPERPIXEL(mode.format) <= 2) { |
178 | bpp = SDL_BITSPERPIXEL(mode.format); |
179 | } else { |
180 | bpp = SDL_BYTESPERPIXEL(mode.format) * 8; |
181 | } |
182 | |
183 | if (bpp != format->BitsPerPixel) { |
184 | continue; |
185 | } |
186 | if (nmodes > 0 && modes[nmodes - 1]->w == mode.w |
187 | && modes[nmodes - 1]->h == mode.h) { |
188 | continue; |
189 | } |
190 | |
191 | modes = (SDL_Rect**)SDL_realloc(modes, (nmodes + 2) * sizeof(*modes)); |
192 | if (!modes) { |
193 | return NULL; |
194 | } |
195 | modes[nmodes] = (SDL_Rect *) SDL_malloc(sizeof(SDL_Rect)); |
196 | if (!modes[nmodes]) { |
197 | return NULL; |
198 | } |
199 | modes[nmodes]->x = 0; |
200 | modes[nmodes]->y = 0; |
201 | modes[nmodes]->w = mode.w; |
202 | modes[nmodes]->h = mode.h; |
203 | ++nmodes; |
204 | } |
205 | if (modes) { |
206 | modes[nmodes] = NULL; |
207 | } |
208 | return modes; |
209 | } |
210 | |
211 | static void |
212 | SDL_UpdateRects(SDL_Surface * screen, int numrects, SDL_Rect * rects) |
213 | { |
214 | int i; |
215 | |
216 | if (screen == SDL_ShadowSurface) { |
217 | for (i = 0; i < numrects; ++i) { |
218 | SDL_BlitSurface(SDL_ShadowSurface, &rects[i], SDL_VideoSurface, |
219 | &rects[i]); |
220 | } |
221 | |
222 | /* Fall through to video surface update */ |
223 | screen = SDL_VideoSurface; |
224 | } |
225 | if (screen == SDL_VideoSurface) { |
226 | if (SDL_VideoViewport.x || SDL_VideoViewport.y) { |
227 | SDL_Rect *stackrects = SDL_stack_alloc(SDL_Rect, numrects); |
228 | SDL_Rect *stackrect; |
229 | const SDL_Rect *rect; |
230 | |
231 | /* Offset all the rectangles before updating */ |
232 | for (i = 0; i < numrects; ++i) { |
233 | rect = &rects[i]; |
234 | stackrect = &stackrects[i]; |
235 | stackrect->x = SDL_VideoViewport.x + rect->x; |
236 | stackrect->y = SDL_VideoViewport.y + rect->y; |
237 | stackrect->w = rect->w; |
238 | stackrect->h = rect->h; |
239 | } |
240 | SDL_UpdateWindowSurfaceRects(SDL_VideoWindow, stackrects, numrects); |
241 | SDL_stack_free(stackrects); |
242 | } else { |
243 | SDL_UpdateWindowSurfaceRects(SDL_VideoWindow, rects, numrects); |
244 | } |
245 | } |
246 | } |
247 | |
248 | static void |
249 | SDL_UpdateRect(SDL_Surface * screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h) |
250 | { |
251 | if (screen) { |
252 | SDL_Rect rect; |
253 | |
254 | /* Fill the rectangle */ |
255 | rect.x = (int) x; |
256 | rect.y = (int) y; |
257 | rect.w = (int) (w ? w : screen->w); |
258 | rect.h = (int) (h ? h : screen->h); |
259 | SDL_UpdateRects(screen, 1, &rect); |
260 | } |
261 | } |
262 | |
263 | static int |
264 | SDL_Flip(SDL_Surface * screen) |
265 | { |
266 | SDL_UpdateRect(screen, 0, 0, 0, 0); |
267 | return 0; |
268 | } |
269 | |
270 | /* |
271 | * Calculate the pad-aligned scanline width of a surface |
272 | */ |
273 | static int |
274 | SDL_CalculatePitch(SDL_Surface * surface) |
275 | { |
276 | int pitch; |
277 | |
278 | /* Surface should be 4-byte aligned for speed */ |
279 | pitch = surface->w * surface->format->BytesPerPixel; |
280 | switch (surface->format->BitsPerPixel) { |
281 | case 1: |
282 | pitch = (pitch + 7) / 8; |
283 | break; |
284 | case 4: |
285 | pitch = (pitch + 1) / 2; |
286 | break; |
287 | default: |
288 | break; |
289 | } |
290 | pitch = (pitch + 3) & ~3; /* 4-byte aligning */ |
291 | return (pitch); |
292 | } |
293 | |
294 | static void |
295 | SDL_InvalidateMap(SDL_BlitMap * map) |
296 | { |
297 | if (!map) { |
298 | return; |
299 | } |
300 | if (map->dst) { |
301 | /* Release our reference to the surface - see the note below */ |
302 | if (--map->dst->refcount <= 0) { |
303 | SDL_FreeSurface(map->dst); |
304 | } |
305 | } |
306 | map->dst = NULL; |
307 | map->src_palette_version = 0; |
308 | map->dst_palette_version = 0; |
309 | if (map->info.table) { |
310 | SDL_free(map->info.table); |
311 | map->info.table = NULL; |
312 | } |
313 | } |
314 | |
315 | static void |
316 | SDL_GL_SwapBuffers(void) |
317 | { |
318 | SDL_GL_SwapWindow(SDL_VideoWindow); |
319 | } |
320 | |
321 | static int |
322 | SDL_WM_ToggleFullScreen(SDL_Surface * surface) |
323 | { |
324 | int length; |
325 | void *pixels; |
326 | Uint8 *src, *dst; |
327 | int row; |
328 | int window_w; |
329 | int window_h; |
330 | |
331 | if (!SDL_PublicSurface) { |
332 | SDL_SetError("SDL_SetVideoMode() hasn't been called"); |
333 | return 0; |
334 | } |
335 | |
336 | /* Copy the old bits out */ |
337 | length = SDL_PublicSurface->w * SDL_PublicSurface->format->BytesPerPixel; |
338 | pixels = SDL_malloc(SDL_PublicSurface->h * length); |
339 | if (pixels && SDL_PublicSurface->pixels) { |
340 | src = (Uint8*)SDL_PublicSurface->pixels; |
341 | dst = (Uint8*)pixels; |
342 | for (row = 0; row < SDL_PublicSurface->h; ++row) { |
343 | SDL_memcpy(dst, src, length); |
344 | src += SDL_PublicSurface->pitch; |
345 | dst += length; |
346 | } |
347 | } |
348 | |
349 | /* Do the physical mode switch */ |
350 | if (SDL_GetWindowFlags(SDL_VideoWindow) & SDL_WINDOW_FULLSCREEN) { |
351 | if (SDL_SetWindowFullscreen(SDL_VideoWindow, 0) < 0) { |
352 | return 0; |
353 | } |
354 | SDL_PublicSurface->flags &= ~SDL_FULLSCREEN; |
355 | } else { |
356 | if (SDL_SetWindowFullscreen(SDL_VideoWindow, 1) < 0) { |
357 | return 0; |
358 | } |
359 | SDL_PublicSurface->flags |= SDL_FULLSCREEN; |
360 | } |
361 | |
362 | /* Recreate the screen surface */ |
363 | SDL_WindowSurface = SDL_GetWindowSurface(SDL_VideoWindow); |
364 | if (!SDL_WindowSurface) { |
365 | /* We're totally hosed... */ |
366 | return 0; |
367 | } |
368 | |
369 | /* Center the public surface in the window surface */ |
370 | SDL_GetWindowSize(SDL_VideoWindow, &window_w, &window_h); |
371 | SDL_VideoViewport.x = (window_w - SDL_VideoSurface->w)/2; |
372 | SDL_VideoViewport.y = (window_h - SDL_VideoSurface->h)/2; |
373 | SDL_VideoViewport.w = SDL_VideoSurface->w; |
374 | SDL_VideoViewport.h = SDL_VideoSurface->h; |
375 | |
376 | /* Do some shuffling behind the application's back if format changes */ |
377 | if (SDL_VideoSurface->format->format != SDL_WindowSurface->format->format) { |
378 | if (SDL_ShadowSurface) { |
379 | if (SDL_ShadowSurface->format->format == SDL_WindowSurface->format->format) { |
380 | /* Whee! We don't need a shadow surface anymore! */ |
381 | SDL_VideoSurface->flags &= ~SDL_DONTFREE; |
382 | SDL_FreeSurface(SDL_VideoSurface); |
383 | SDL_free(SDL_ShadowSurface->pixels); |
384 | SDL_VideoSurface = SDL_ShadowSurface; |
385 | SDL_VideoSurface->flags |= SDL_PREALLOC; |
386 | SDL_ShadowSurface = NULL; |
387 | } else { |
388 | /* No problem, just change the video surface format */ |
389 | SDL_FreeFormat(SDL_VideoSurface->format); |
390 | SDL_VideoSurface->format = SDL_WindowSurface->format; |
391 | SDL_VideoSurface->format->refcount++; |
392 | SDL_InvalidateMap(SDL_ShadowSurface->map); |
393 | } |
394 | } else { |
395 | /* We can make the video surface the shadow surface */ |
396 | SDL_ShadowSurface = SDL_VideoSurface; |
397 | SDL_ShadowSurface->pitch = SDL_CalculatePitch(SDL_ShadowSurface); |
398 | SDL_ShadowSurface->pixels = SDL_malloc(SDL_ShadowSurface->h * SDL_ShadowSurface->pitch); |
399 | if (!SDL_ShadowSurface->pixels) { |
400 | /* Uh oh, we're hosed */ |
401 | SDL_ShadowSurface = NULL; |
402 | return 0; |
403 | } |
404 | SDL_ShadowSurface->flags &= ~SDL_PREALLOC; |
405 | |
406 | SDL_VideoSurface = SDL_CreateRGBSurfaceFrom(NULL, 0, 0, 32, 0, 0, 0, 0, 0); |
407 | SDL_VideoSurface->flags = SDL_ShadowSurface->flags; |
408 | SDL_VideoSurface->flags |= SDL_PREALLOC; |
409 | SDL_FreeFormat(SDL_VideoSurface->format); |
410 | SDL_VideoSurface->format = SDL_WindowSurface->format; |
411 | SDL_VideoSurface->format->refcount++; |
412 | SDL_VideoSurface->w = SDL_ShadowSurface->w; |
413 | SDL_VideoSurface->h = SDL_ShadowSurface->h; |
414 | } |
415 | } |
416 | |
417 | /* Update the video surface */ |
418 | SDL_VideoSurface->pitch = SDL_WindowSurface->pitch; |
419 | SDL_VideoSurface->pixels = (void *)((Uint8 *)SDL_WindowSurface->pixels + |
420 | SDL_VideoViewport.y * SDL_VideoSurface->pitch + |
421 | SDL_VideoViewport.x * SDL_VideoSurface->format->BytesPerPixel); |
422 | SDL_SetClipRect(SDL_VideoSurface, NULL); |
423 | |
424 | /* Copy the old bits back */ |
425 | if (pixels) { |
426 | src = (Uint8*)pixels; |
427 | dst = (Uint8*)SDL_PublicSurface->pixels; |
428 | for (row = 0; row < SDL_PublicSurface->h; ++row) { |
429 | SDL_memcpy(dst, src, length); |
430 | src += length; |
431 | dst += SDL_PublicSurface->pitch; |
432 | } |
433 | SDL_Flip(SDL_PublicSurface); |
434 | SDL_free(pixels); |
435 | } |
436 | |
437 | /* We're done! */ |
438 | return 1; |
439 | } |
440 | |
441 | static void |
442 | ClearVideoSurface() |
443 | { |
444 | if (SDL_ShadowSurface) { |
445 | SDL_FillRect(SDL_ShadowSurface, NULL, |
446 | SDL_MapRGB(SDL_ShadowSurface->format, 0, 0, 0)); |
447 | } |
448 | SDL_FillRect(SDL_WindowSurface, NULL, 0); |
449 | SDL_UpdateWindowSurface(SDL_VideoWindow); |
450 | } |
451 | |
452 | static int |
453 | SDL_ResizeVideoMode(int width, int height, int bpp, Uint32 flags) |
454 | { |
455 | int w, h; |
456 | |
457 | /* We can't resize something we don't have... */ |
458 | if (!SDL_VideoSurface) { |
459 | return -1; |
460 | } |
461 | |
462 | /* We probably have to recreate the window in fullscreen mode */ |
463 | if (flags & SDL_FULLSCREEN) { |
464 | return -1; |
465 | } |
466 | |
467 | /* I don't think there's any change we can gracefully make in flags */ |
468 | if (flags != SDL_VideoFlags) { |
469 | return -1; |
470 | } |
471 | if (bpp != SDL_VideoSurface->format->BitsPerPixel) { |
472 | return -1; |
473 | } |
474 | |
475 | /* Resize the window */ |
476 | SDL_GetWindowSize(SDL_VideoWindow, &w, &h); |
477 | if (w != width || h != height) { |
478 | SDL_SetWindowSize(SDL_VideoWindow, width, height); |
479 | } |
480 | |
481 | /* If we're in OpenGL mode, just resize the stub surface and we're done! */ |
482 | if (flags & SDL_OPENGL) { |
483 | SDL_VideoSurface->w = width; |
484 | SDL_VideoSurface->h = height; |
485 | return 0; |
486 | } |
487 | |
488 | SDL_WindowSurface = SDL_GetWindowSurface(SDL_VideoWindow); |
489 | if (!SDL_WindowSurface) { |
490 | return -1; |
491 | } |
492 | if (SDL_VideoSurface->format != SDL_WindowSurface->format) { |
493 | return -1; |
494 | } |
495 | SDL_VideoSurface->w = width; |
496 | SDL_VideoSurface->h = height; |
497 | SDL_VideoSurface->pixels = SDL_WindowSurface->pixels; |
498 | SDL_VideoSurface->pitch = SDL_WindowSurface->pitch; |
499 | SDL_SetClipRect(SDL_VideoSurface, NULL); |
500 | |
501 | if (SDL_ShadowSurface) { |
502 | SDL_ShadowSurface->w = width; |
503 | SDL_ShadowSurface->h = height; |
504 | SDL_ShadowSurface->pitch = SDL_CalculatePitch(SDL_ShadowSurface); |
505 | SDL_ShadowSurface->pixels = |
506 | SDL_realloc(SDL_ShadowSurface->pixels, |
507 | SDL_ShadowSurface->h * SDL_ShadowSurface->pitch); |
508 | SDL_SetClipRect(SDL_ShadowSurface, NULL); |
509 | SDL_InvalidateMap(SDL_ShadowSurface->map); |
510 | } else { |
511 | SDL_PublicSurface = SDL_VideoSurface; |
512 | } |
513 | |
514 | ClearVideoSurface(); |
515 | |
516 | return 0; |
517 | } |
518 | |
519 | static int |
520 | SDL_CompatEventFilter(void *userdata, SDL_Event * event) |
521 | { |
522 | SDL_Event fake; |
523 | |
524 | switch (event->type) { |
525 | case SDL_WINDOWEVENT: |
526 | switch (event->window.event) { |
527 | case SDL_WINDOWEVENT_CLOSE: |
528 | fake.type = SDL_QUIT; |
529 | SDL_PushEvent(&fake); |
530 | break; |
531 | } |
532 | case SDL_TEXTINPUT: |
533 | { |
534 | /* FIXME: Generate an old style key repeat event if needed */ |
535 | //printf("TEXTINPUT: '%s'\n", event->text.text); |
536 | break; |
537 | } |
538 | case SDL_MOUSEMOTION: |
539 | { |
540 | event->motion.x -= SDL_VideoViewport.x; |
541 | event->motion.y -= SDL_VideoViewport.y; |
542 | break; |
543 | } |
544 | case SDL_MOUSEBUTTONDOWN: |
545 | case SDL_MOUSEBUTTONUP: |
546 | { |
547 | event->button.x -= SDL_VideoViewport.x; |
548 | event->button.y -= SDL_VideoViewport.y; |
549 | break; |
550 | } |
551 | case SDL_MOUSEWHEEL: |
552 | { |
553 | Uint8 button; |
554 | int x, y; |
555 | |
556 | if (event->wheel.y == 0) { |
557 | break; |
558 | } |
559 | |
560 | SDL_GetMouseState(&x, &y); |
561 | |
562 | if (event->wheel.y > 0) { |
563 | button = SDL_BUTTON_WHEELUP; |
564 | } else { |
565 | button = SDL_BUTTON_WHEELDOWN; |
566 | } |
567 | |
568 | fake.button.button = button; |
569 | fake.button.x = x; |
570 | fake.button.y = y; |
571 | fake.button.windowID = event->wheel.windowID; |
572 | |
573 | fake.type = SDL_MOUSEBUTTONDOWN; |
574 | fake.button.state = SDL_PRESSED; |
575 | SDL_PushEvent(&fake); |
576 | |
577 | fake.type = SDL_MOUSEBUTTONUP; |
578 | fake.button.state = SDL_RELEASED; |
579 | SDL_PushEvent(&fake); |
580 | break; |
581 | } |
582 | |
583 | } |
584 | return 1; |
585 | } |
586 | |
587 | static void |
588 | GetEnvironmentWindowPosition(int w, int h, int *x, int *y) |
589 | { |
590 | int display = GetVideoDisplay(); |
591 | const char *window = SDL_getenv("SDL_VIDEO_WINDOW_POS"); |
592 | const char *center = SDL_getenv("SDL_VIDEO_CENTERED"); |
593 | if (window) { |
594 | if (SDL_sscanf(window, "%d,%d", x, y) == 2) { |
595 | return; |
596 | } |
597 | if (SDL_strcmp(window, "center") == 0) { |
598 | center = window; |
599 | } |
600 | } |
601 | if (center) { |
602 | *x = SDL_WINDOWPOS_CENTERED_DISPLAY(display); |
603 | *y = SDL_WINDOWPOS_CENTERED_DISPLAY(display); |
604 | } |
605 | } |
606 | |
607 | static SDL_Surface * |
608 | SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) |
609 | { |
610 | SDL_DisplayMode desktop_mode; |
611 | int display = GetVideoDisplay(); |
612 | int window_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display); |
613 | int window_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display); |
614 | int window_w; |
615 | int window_h; |
616 | Uint32 window_flags; |
617 | Uint32 surface_flags; |
618 | |
619 | if (!initialized_video) { |
620 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0) { |
621 | return NULL; |
622 | } |
623 | initialized_video = 1; |
624 | } |
625 | |
626 | SDL_GetDesktopDisplayMode(display, &desktop_mode); |
627 | |
628 | if (width == 0) { |
629 | width = desktop_mode.w; |
630 | } |
631 | if (height == 0) { |
632 | height = desktop_mode.h; |
633 | } |
634 | if (bpp == 0) { |
635 | bpp = SDL_BITSPERPIXEL(desktop_mode.format); |
636 | } |
637 | |
638 | /* See if we can simply resize the existing window and surface */ |
639 | if (SDL_ResizeVideoMode(width, height, bpp, flags) == 0) { |
640 | return SDL_PublicSurface; |
641 | } |
642 | |
643 | /* Destroy existing window */ |
644 | SDL_PublicSurface = NULL; |
645 | if (SDL_ShadowSurface) { |
646 | SDL_ShadowSurface->flags &= ~SDL_DONTFREE; |
647 | SDL_FreeSurface(SDL_ShadowSurface); |
648 | SDL_ShadowSurface = NULL; |
649 | } |
650 | if (SDL_VideoSurface) { |
651 | SDL_VideoSurface->flags &= ~SDL_DONTFREE; |
652 | SDL_FreeSurface(SDL_VideoSurface); |
653 | SDL_VideoSurface = NULL; |
654 | } |
655 | if (SDL_VideoContext) { |
656 | /* SDL_GL_MakeCurrent(0, NULL); *//* Doesn't do anything */ |
657 | SDL_GL_DeleteContext(SDL_VideoContext); |
658 | SDL_VideoContext = NULL; |
659 | } |
660 | if (SDL_VideoWindow) { |
661 | SDL_GetWindowPosition(SDL_VideoWindow, &window_x, &window_y); |
662 | SDL_DestroyWindow(SDL_VideoWindow); |
663 | } |
664 | |
665 | /* Set up the event filter */ |
666 | if (!SDL_GetEventFilter(NULL, NULL)) { |
667 | SDL_SetEventFilter(SDL_CompatEventFilter, NULL); |
668 | } |
669 | |
670 | /* Create a new window */ |
671 | window_flags = SDL_WINDOW_SHOWN; |
672 | if (flags & SDL_FULLSCREEN) { |
673 | window_flags |= SDL_WINDOW_FULLSCREEN; |
674 | } |
675 | if (flags & SDL_OPENGL) { |
676 | window_flags |= SDL_WINDOW_OPENGL; |
677 | } |
678 | if (flags & SDL_RESIZABLE) { |
679 | window_flags |= SDL_WINDOW_RESIZABLE; |
680 | } |
681 | if (flags & SDL_NOFRAME) { |
682 | window_flags |= SDL_WINDOW_BORDERLESS; |
683 | } |
684 | GetEnvironmentWindowPosition(width, height, &window_x, &window_y); |
685 | SDL_VideoWindow = |
686 | SDL_CreateWindow(wm_title, window_x, window_y, width, height, |
687 | window_flags); |
688 | if (!SDL_VideoWindow) { |
689 | return NULL; |
690 | } |
691 | SDL_SetWindowIcon(SDL_VideoWindow, SDL_VideoIcon); |
692 | |
693 | window_flags = SDL_GetWindowFlags(SDL_VideoWindow); |
694 | surface_flags = 0; |
695 | if (window_flags & SDL_WINDOW_FULLSCREEN) { |
696 | surface_flags |= SDL_FULLSCREEN; |
697 | } |
698 | if ((window_flags & SDL_WINDOW_OPENGL) && (flags & SDL_OPENGL)) { |
699 | surface_flags |= SDL_OPENGL; |
700 | } |
701 | if (window_flags & SDL_WINDOW_RESIZABLE) { |
702 | surface_flags |= SDL_RESIZABLE; |
703 | } |
704 | if (window_flags & SDL_WINDOW_BORDERLESS) { |
705 | surface_flags |= SDL_NOFRAME; |
706 | } |
707 | |
708 | SDL_VideoFlags = flags; |
709 | |
710 | /* If we're in OpenGL mode, just create a stub surface and we're done! */ |
711 | if (flags & SDL_OPENGL) { |
712 | SDL_VideoContext = (SDL_GLContext *)SDL_GL_CreateContext(SDL_VideoWindow); |
713 | if (!SDL_VideoContext) { |
714 | return NULL; |
715 | } |
716 | if (SDL_GL_MakeCurrent(SDL_VideoWindow, SDL_VideoContext) < 0) { |
717 | return NULL; |
718 | } |
719 | SDL_VideoSurface = |
720 | SDL_CreateRGBSurfaceFrom(NULL, width, height, bpp, 0, 0, 0, 0, 0); |
721 | if (!SDL_VideoSurface) { |
722 | return NULL; |
723 | } |
724 | SDL_VideoSurface->flags |= surface_flags; |
725 | SDL_PublicSurface = SDL_VideoSurface; |
726 | return SDL_PublicSurface; |
727 | } |
728 | |
729 | /* Create the screen surface */ |
730 | SDL_WindowSurface = SDL_GetWindowSurface(SDL_VideoWindow); |
731 | if (!SDL_WindowSurface) { |
732 | return NULL; |
733 | } |
734 | |
735 | /* Center the public surface in the window surface */ |
736 | SDL_GetWindowSize(SDL_VideoWindow, &window_w, &window_h); |
737 | SDL_VideoViewport.x = (window_w - width)/2; |
738 | SDL_VideoViewport.y = (window_h - height)/2; |
739 | SDL_VideoViewport.w = width; |
740 | SDL_VideoViewport.h = height; |
741 | |
742 | SDL_VideoSurface = SDL_CreateRGBSurfaceFrom(NULL, 0, 0, 32, 0, 0, 0, 0, 0); |
743 | SDL_VideoSurface->flags |= surface_flags; |
744 | SDL_VideoSurface->flags |= SDL_DONTFREE; |
745 | SDL_FreeFormat(SDL_VideoSurface->format); |
746 | SDL_VideoSurface->format = SDL_WindowSurface->format; |
747 | SDL_VideoSurface->format->refcount++; |
748 | SDL_VideoSurface->w = width; |
749 | SDL_VideoSurface->h = height; |
750 | SDL_VideoSurface->pitch = SDL_WindowSurface->pitch; |
751 | SDL_VideoSurface->pixels = (void *)((Uint8 *)SDL_WindowSurface->pixels + |
752 | SDL_VideoViewport.y * SDL_VideoSurface->pitch + |
753 | SDL_VideoViewport.x * SDL_VideoSurface->format->BytesPerPixel); |
754 | SDL_SetClipRect(SDL_VideoSurface, NULL); |
755 | |
756 | /* Create a shadow surface if necessary */ |
757 | if ((bpp != SDL_VideoSurface->format->BitsPerPixel) |
758 | && !(flags & SDL_ANYFORMAT)) { |
759 | SDL_ShadowSurface = |
760 | SDL_CreateRGBSurface(0, width, height, bpp, 0, 0, 0, 0); |
761 | if (!SDL_ShadowSurface) { |
762 | return NULL; |
763 | } |
764 | SDL_ShadowSurface->flags |= surface_flags; |
765 | SDL_ShadowSurface->flags |= SDL_DONTFREE; |
766 | |
767 | /* 8-bit SDL_ShadowSurface surfaces report that they have exclusive palette */ |
768 | if (SDL_ShadowSurface->format->palette) { |
769 | SDL_ShadowSurface->flags |= SDL_HWPALETTE; |
770 | //TODO SDL_DitherColors(SDL_ShadowSurface->format->palette->colors, |
771 | // SDL_ShadowSurface->format->BitsPerPixel); |
772 | } |
773 | SDL_FillRect(SDL_ShadowSurface, NULL, |
774 | SDL_MapRGB(SDL_ShadowSurface->format, 0, 0, 0)); |
775 | } |
776 | SDL_PublicSurface = |
777 | (SDL_ShadowSurface ? SDL_ShadowSurface : SDL_VideoSurface); |
778 | |
779 | ClearVideoSurface(); |
780 | |
781 | /* We're finally done! */ |
782 | return SDL_PublicSurface; |
783 | } |