GLES2N64 (from mupen64plus-ae) plugin. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / gles2n64 / src / sdl2_compat.h
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 }