src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 26 Jul 2006 03:12:05 +0000
changeset 1942 4371d679ee12
parent 1941 bf09d535e014
child 1944 91f41fc124a7
permissions -rw-r--r--
Hopefully glSDL has been superceded by the OpenGL render driver.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     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     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* The high-level video driver subsystem */
    25 
    26 #include "SDL.h"
    27 #include "SDL_sysvideo.h"
    28 #include "SDL_blit.h"
    29 #include "SDL_pixels_c.h"
    30 #include "SDL_renderer_gl.h"
    31 #include "SDL_renderer_sw.h"
    32 #include "../events/SDL_sysevents.h"
    33 #include "../events/SDL_events_c.h"
    34 
    35 #if SDL_VIDEO_OPENGL
    36 #include "SDL_opengl.h"
    37 
    38 /* On Windows, windows.h defines CreateWindow */
    39 #ifdef CreateWindow
    40 #undef CreateWindow
    41 #endif
    42 #endif /* SDL_VIDEO_OPENGL */
    43 
    44 /* Available video drivers */
    45 static VideoBootStrap *bootstrap[] = {
    46 #if SDL_VIDEO_DRIVER_COCOA
    47     &COCOA_bootstrap,
    48 #endif
    49 #if SDL_VIDEO_DRIVER_X11
    50     &X11_bootstrap,
    51 #endif
    52 #if SDL_VIDEO_DRIVER_NANOX
    53     &NX_bootstrap,
    54 #endif
    55 #if SDL_VIDEO_DRIVER_IPOD
    56     &iPod_bootstrap,
    57 #endif
    58 #if SDL_VIDEO_DRIVER_QTOPIA
    59     &Qtopia_bootstrap,
    60 #endif
    61 #if SDL_VIDEO_DRIVER_WSCONS
    62     &WSCONS_bootstrap,
    63 #endif
    64 #if SDL_VIDEO_DRIVER_FBCON
    65     &FBCON_bootstrap,
    66 #endif
    67 #if SDL_VIDEO_DRIVER_DIRECTFB
    68     &DirectFB_bootstrap,
    69 #endif
    70 #if SDL_VIDEO_DRIVER_PS2GS
    71     &PS2GS_bootstrap,
    72 #endif
    73 #if SDL_VIDEO_DRIVER_GGI
    74     &GGI_bootstrap,
    75 #endif
    76 #if SDL_VIDEO_DRIVER_VGL
    77     &VGL_bootstrap,
    78 #endif
    79 #if SDL_VIDEO_DRIVER_SVGALIB
    80     &SVGALIB_bootstrap,
    81 #endif
    82 #if SDL_VIDEO_DRIVER_GAPI
    83     &GAPI_bootstrap,
    84 #endif
    85 #if SDL_VIDEO_DRIVER_WIN32
    86     &WIN32_bootstrap,
    87 #endif
    88 #if SDL_VIDEO_DRIVER_BWINDOW
    89     &BWINDOW_bootstrap,
    90 #endif
    91 #if SDL_VIDEO_DRIVER_TOOLBOX
    92     &TOOLBOX_bootstrap,
    93 #endif
    94 #if SDL_VIDEO_DRIVER_DRAWSPROCKET
    95     &DSp_bootstrap,
    96 #endif
    97 #if SDL_VIDEO_DRIVER_CYBERGRAPHICS
    98     &CGX_bootstrap,
    99 #endif
   100 #if SDL_VIDEO_DRIVER_PHOTON
   101     &ph_bootstrap,
   102 #endif
   103 #if SDL_VIDEO_DRIVER_EPOC
   104     &EPOC_bootstrap,
   105 #endif
   106 #if SDL_VIDEO_DRIVER_XBIOS
   107     &XBIOS_bootstrap,
   108 #endif
   109 #if SDL_VIDEO_DRIVER_GEM
   110     &GEM_bootstrap,
   111 #endif
   112 #if SDL_VIDEO_DRIVER_PICOGUI
   113     &PG_bootstrap,
   114 #endif
   115 #if SDL_VIDEO_DRIVER_DC
   116     &DC_bootstrap,
   117 #endif
   118 #if SDL_VIDEO_DRIVER_RISCOS
   119     &RISCOS_bootstrap,
   120 #endif
   121 #if SDL_VIDEO_DRIVER_OS2FS
   122     &OS2FSLib_bootstrap,
   123 #endif
   124 #if SDL_VIDEO_DRIVER_AALIB
   125     &AALIB_bootstrap,
   126 #endif
   127 #if SDL_VIDEO_DRIVER_DUMMY
   128     &DUMMY_bootstrap,
   129 #endif
   130     NULL
   131 };
   132 
   133 static SDL_VideoDevice *_this = NULL;
   134 
   135 /* Various local functions */
   136 int SDL_VideoInit(const char *driver_name, Uint32 flags);
   137 void SDL_VideoQuit(void);
   138 
   139 static int
   140 cmpmodes(const void *A, const void *B)
   141 {
   142     SDL_DisplayMode a = *(const SDL_DisplayMode *) A;
   143     SDL_DisplayMode b = *(const SDL_DisplayMode *) B;
   144 
   145     if (a.w != b.w) {
   146         return b.w - a.w;
   147     }
   148     if (a.h != b.h) {
   149         return b.h - a.h;
   150     }
   151     if (SDL_BITSPERPIXEL(a.format) != SDL_BITSPERPIXEL(b.format)) {
   152         return SDL_BITSPERPIXEL(b.format) - SDL_BITSPERPIXEL(a.format);
   153     }
   154     if (a.refresh_rate != b.refresh_rate) {
   155         return b.refresh_rate - a.refresh_rate;
   156     }
   157     return 0;
   158 }
   159 
   160 static void
   161 SDL_UninitializedVideo()
   162 {
   163     SDL_SetError("Video subsystem has not been initialized");
   164 }
   165 
   166 int
   167 SDL_GetNumVideoDrivers(void)
   168 {
   169     return SDL_arraysize(bootstrap) - 1;
   170 }
   171 
   172 const char *
   173 SDL_GetVideoDriver(int index)
   174 {
   175     if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
   176         return bootstrap[index]->name;
   177     }
   178     return NULL;
   179 }
   180 
   181 /*
   182  * Initialize the video and event subsystems -- determine native pixel format
   183  */
   184 int
   185 SDL_VideoInit(const char *driver_name, Uint32 flags)
   186 {
   187     SDL_VideoDevice *video;
   188     int index;
   189     int i;
   190 
   191     /* Toggle the event thread flags, based on OS requirements */
   192 #if defined(MUST_THREAD_EVENTS)
   193     flags |= SDL_INIT_EVENTTHREAD;
   194 #elif defined(CANT_THREAD_EVENTS)
   195     if ((flags & SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD) {
   196         SDL_SetError("OS doesn't support threaded events");
   197         return -1;
   198     }
   199 #endif
   200 
   201     /* Start the event loop */
   202     if (SDL_StartEventLoop(flags) < 0) {
   203         return -1;
   204     }
   205 
   206     /* Check to make sure we don't overwrite '_this' */
   207     if (_this != NULL) {
   208         SDL_VideoQuit();
   209     }
   210 
   211     /* Select the proper video driver */
   212     index = 0;
   213     video = NULL;
   214     if (driver_name == NULL) {
   215         driver_name = SDL_getenv("SDL_VIDEODRIVER");
   216     }
   217     if (driver_name != NULL) {
   218         for (i = 0; bootstrap[i]; ++i) {
   219             if (SDL_strncmp(bootstrap[i]->name, driver_name,
   220                             SDL_strlen(bootstrap[i]->name)) == 0) {
   221                 if (bootstrap[i]->available()) {
   222                     video = bootstrap[i]->create(index);
   223                 }
   224                 break;
   225             }
   226         }
   227     } else {
   228         for (i = 0; bootstrap[i]; ++i) {
   229             if (bootstrap[i]->available()) {
   230                 video = bootstrap[i]->create(index);
   231                 if (video != NULL) {
   232                     break;
   233                 }
   234             }
   235         }
   236     }
   237     if (video == NULL) {
   238         if (driver_name) {
   239             SDL_SetError("%s not available", driver_name);
   240         } else {
   241             SDL_SetError("No available video device");
   242         }
   243         return -1;
   244     }
   245     _this = video;
   246     _this->name = bootstrap[i]->name;
   247     _this->next_object_id = 1;
   248 
   249 
   250     /* Set some very sane GL defaults */
   251     _this->gl_config.driver_loaded = 0;
   252     _this->gl_config.dll_handle = NULL;
   253     _this->gl_config.red_size = 3;
   254     _this->gl_config.green_size = 3;
   255     _this->gl_config.blue_size = 2;
   256     _this->gl_config.alpha_size = 0;
   257     _this->gl_config.buffer_size = 0;
   258     _this->gl_config.depth_size = 16;
   259     _this->gl_config.stencil_size = 0;
   260     _this->gl_config.double_buffer = 1;
   261     _this->gl_config.accum_red_size = 0;
   262     _this->gl_config.accum_green_size = 0;
   263     _this->gl_config.accum_blue_size = 0;
   264     _this->gl_config.accum_alpha_size = 0;
   265     _this->gl_config.stereo = 0;
   266     _this->gl_config.multisamplebuffers = 0;
   267     _this->gl_config.multisamplesamples = 0;
   268     _this->gl_config.accelerated = -1;  /* not known, don't set */
   269 
   270     /* Initialize the video subsystem */
   271     if (_this->VideoInit(_this) < 0) {
   272         SDL_VideoQuit();
   273         return -1;
   274     }
   275 
   276     /* Make sure some displays were added */
   277     if (_this->num_displays == 0) {
   278         SDL_SetError("The video driver did not add any displays");
   279         SDL_VideoQuit();
   280         return (-1);
   281     }
   282 
   283     /* The software renderer is always available */
   284     for (i = 0; i < _this->num_displays; ++i) {
   285 #if SDL_VIDEO_OPENGL
   286         SDL_AddRenderDriver(i, &GL_RenderDriver);
   287 #endif
   288         if (_this->displays[i].num_render_drivers > 0) {
   289             SDL_AddRenderDriver(i, &SW_RenderDriver);
   290         }
   291     }
   292 
   293     /* We're ready to go! */
   294     return 0;
   295 }
   296 
   297 const char *
   298 SDL_GetCurrentVideoDriver()
   299 {
   300     if (!_this) {
   301         SDL_UninitializedVideo();
   302         return NULL;
   303     }
   304     return _this->name;
   305 }
   306 
   307 SDL_VideoDevice *
   308 SDL_GetVideoDevice()
   309 {
   310     return _this;
   311 }
   312 
   313 int
   314 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
   315 {
   316     SDL_VideoDisplay display;
   317 
   318     SDL_zero(display);
   319     if (desktop_mode) {
   320         display.desktop_mode = *desktop_mode;
   321     }
   322     display.current_mode = display.desktop_mode;
   323 
   324     return SDL_AddVideoDisplay(&display);
   325 }
   326 
   327 int
   328 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
   329 {
   330     SDL_VideoDisplay *displays;
   331     int index = -1;
   332 
   333     displays =
   334         SDL_realloc(_this->displays,
   335                     (_this->num_displays + 1) * sizeof(*displays));
   336     if (displays) {
   337         index = _this->num_displays++;
   338         displays[index] = *display;
   339         displays[index].device = _this;
   340         _this->displays = displays;
   341     } else {
   342         SDL_OutOfMemory();
   343     }
   344     return index;
   345 }
   346 
   347 int
   348 SDL_GetNumVideoDisplays(void)
   349 {
   350     if (!_this) {
   351         SDL_UninitializedVideo();
   352         return 0;
   353     }
   354     return _this->num_displays;
   355 }
   356 
   357 int
   358 SDL_SelectVideoDisplay(int index)
   359 {
   360     if (!_this) {
   361         SDL_UninitializedVideo();
   362         return (-1);
   363     }
   364     if (index >= 0) {
   365         if (index >= _this->num_displays) {
   366             SDL_SetError("index must be in the range 0 - %d",
   367                          _this->num_displays - 1);
   368             return -1;
   369         }
   370         _this->current_display = index;
   371     }
   372     return _this->current_display;
   373 }
   374 
   375 SDL_bool
   376 SDL_AddDisplayMode(int displayIndex, const SDL_DisplayMode * mode)
   377 {
   378     SDL_VideoDisplay *display = &_this->displays[displayIndex];
   379     SDL_DisplayMode *modes;
   380     int i, nmodes;
   381 
   382     /* Make sure we don't already have the mode in the list */
   383     modes = display->display_modes;
   384     nmodes = display->num_display_modes;
   385     for (i = nmodes; i--;) {
   386         if (SDL_memcmp(mode, &modes[i], sizeof(*mode)) == 0) {
   387             return SDL_FALSE;
   388         }
   389     }
   390 
   391     /* Go ahead and add the new mode */
   392     if (nmodes == display->max_display_modes) {
   393         modes =
   394             SDL_realloc(modes,
   395                         (display->max_display_modes + 32) * sizeof(*modes));
   396         if (!modes) {
   397             return SDL_FALSE;
   398         }
   399         display->display_modes = modes;
   400         display->max_display_modes += 32;
   401     }
   402     modes[nmodes] = *mode;
   403     display->num_display_modes++;
   404 
   405     return SDL_TRUE;
   406 }
   407 
   408 int
   409 SDL_GetNumDisplayModes()
   410 {
   411     if (_this) {
   412         SDL_VideoDisplay *display = &SDL_CurrentDisplay;
   413         if (!display->num_display_modes && _this->GetDisplayModes) {
   414             _this->GetDisplayModes(_this);
   415             SDL_qsort(display->display_modes, display->num_display_modes,
   416                       sizeof(SDL_DisplayMode), cmpmodes);
   417         }
   418         return display->num_display_modes;
   419     }
   420     return 0;
   421 }
   422 
   423 const SDL_DisplayMode *
   424 SDL_GetDisplayMode(int index)
   425 {
   426     if (index < 0 || index >= SDL_GetNumDisplayModes()) {
   427         SDL_SetError("index must be in the range of 0 - %d",
   428                      SDL_GetNumDisplayModes() - 1);
   429         return NULL;
   430     }
   431     return &SDL_CurrentDisplay.display_modes[index];
   432 }
   433 
   434 const SDL_DisplayMode *
   435 SDL_GetDesktopDisplayMode(void)
   436 {
   437     if (_this) {
   438         return &SDL_CurrentDisplay.desktop_mode;
   439     }
   440     return NULL;
   441 }
   442 
   443 const SDL_DisplayMode *
   444 SDL_GetCurrentDisplayMode(void)
   445 {
   446     if (_this) {
   447         return &SDL_CurrentDisplay.current_mode;
   448     }
   449     return NULL;
   450 }
   451 
   452 SDL_DisplayMode *
   453 SDL_GetClosestDisplayMode(const SDL_DisplayMode * mode,
   454                           SDL_DisplayMode * closest)
   455 {
   456     Uint32 target_format;
   457     int target_refresh_rate;
   458     int i;
   459     SDL_DisplayMode *current, *match;
   460 
   461     if (!_this || !mode || !closest) {
   462         return NULL;
   463     }
   464 
   465     /* Default to the desktop format */
   466     if (mode->format) {
   467         target_format = mode->format;
   468     } else {
   469         target_format = SDL_CurrentDisplay.desktop_mode.format;
   470     }
   471 
   472     /* Default to the desktop refresh rate */
   473     if (mode->refresh_rate) {
   474         target_refresh_rate = mode->refresh_rate;
   475     } else {
   476         target_refresh_rate = SDL_CurrentDisplay.desktop_mode.refresh_rate;
   477     }
   478 
   479     match = NULL;
   480     for (i = 0; i < SDL_GetNumDisplayModes(); ++i) {
   481         current = &SDL_CurrentDisplay.display_modes[i];
   482 
   483         if ((current->w && current->h) &&
   484             (current->w < mode->w || current->h < mode->h)) {
   485             /* Out of sorted modes large enough here */
   486             break;
   487         }
   488         if (!match || current->w < match->w || current->h < match->h) {
   489             match = current;
   490             continue;
   491         }
   492         if (current->format != match->format) {
   493             /* Sorted highest depth to lowest */
   494             if (current->format == target_format ||
   495                 (SDL_BITSPERPIXEL(current->format) >=
   496                  SDL_BITSPERPIXEL(target_format)
   497                  && SDL_PIXELTYPE(current->format) ==
   498                  SDL_PIXELTYPE(target_format))) {
   499                 match = current;
   500             }
   501             continue;
   502         }
   503         if (current->refresh_rate != match->refresh_rate) {
   504             /* Sorted highest refresh to lowest */
   505             if (current->refresh_rate >= target_refresh_rate) {
   506                 match = current;
   507             }
   508         }
   509     }
   510     if (match) {
   511         if (match->format) {
   512             closest->format = match->format;
   513         } else {
   514             closest->format = mode->format;
   515         }
   516         if (match->w && match->h) {
   517             closest->w = match->w;
   518             closest->h = match->h;
   519         } else {
   520             closest->w = mode->w;
   521             closest->h = mode->h;
   522         }
   523         if (match->refresh_rate) {
   524             closest->refresh_rate = match->refresh_rate;
   525         } else {
   526             closest->refresh_rate = mode->refresh_rate;
   527         }
   528         closest->driverdata = match->driverdata;
   529 
   530         /* Pick some reasonable defaults if the app and driver don't care */
   531         if (!closest->format) {
   532             closest->format = SDL_PixelFormat_RGB888;
   533         }
   534         if (!closest->w) {
   535             closest->w = 640;
   536         }
   537         if (!closest->h) {
   538             closest->h = 480;
   539         }
   540         return closest;
   541     }
   542     return NULL;
   543 }
   544 
   545 int
   546 SDL_SetDisplayMode(const SDL_DisplayMode * mode)
   547 {
   548     SDL_VideoDisplay *display;
   549     SDL_DisplayMode display_mode;
   550     int i, ncolors;
   551 
   552     if (!_this) {
   553         SDL_UninitializedVideo();
   554         return -1;
   555     }
   556 
   557     if (!mode) {
   558         mode = SDL_GetDesktopDisplayMode();
   559     }
   560     display = &SDL_CurrentDisplay;
   561     display_mode = *mode;
   562 
   563     /* Default to the current mode */
   564     if (!display_mode.format) {
   565         display_mode.format = display->current_mode.format;
   566     }
   567     if (!display_mode.w) {
   568         display_mode.w = display->current_mode.w;
   569     }
   570     if (!display_mode.h) {
   571         display_mode.h = display->current_mode.h;
   572     }
   573     if (!display_mode.refresh_rate) {
   574         display_mode.refresh_rate = display->current_mode.refresh_rate;
   575     }
   576 
   577     /* Get a good video mode, the closest one possible */
   578     if (!SDL_GetClosestDisplayMode(&display_mode, &display_mode)) {
   579         SDL_SetError("No video mode large enough for %dx%d",
   580                      display_mode.w, display_mode.h);
   581         return -1;
   582     }
   583 
   584     /* See if there's anything left to do */
   585     if (SDL_memcmp
   586         (&display_mode, SDL_GetCurrentDisplayMode(),
   587          sizeof(display_mode)) == 0) {
   588         return 0;
   589     }
   590 
   591     /* Actually change the display mode */
   592     if (_this->SetDisplayMode(_this, &display_mode) < 0) {
   593         return -1;
   594     }
   595     display->current_mode = display_mode;
   596 
   597     /* Set up a palette, if necessary */
   598     if (SDL_ISPIXELFORMAT_INDEXED(display_mode.format)) {
   599         ncolors = (1 << SDL_BITSPERPIXEL(display_mode.format));
   600     } else {
   601         ncolors = 0;
   602     }
   603     if ((!ncolors && display->palette) || (ncolors && !display->palette)
   604         || (ncolors && ncolors != display->palette->ncolors)) {
   605         if (display->palette) {
   606             SDL_FreePalette(display->palette);
   607             display->palette = NULL;
   608         }
   609         if (ncolors) {
   610             display->palette = SDL_AllocPalette(ncolors);
   611             if (!display->palette) {
   612                 return -1;
   613             }
   614             SDL_DitherColors(display->palette->colors,
   615                              SDL_BITSPERPIXEL(display_mode.format));
   616         }
   617     }
   618 
   619     /* Move any fullscreen windows into position */
   620     for (i = 0; i < display->num_windows; ++i) {
   621         SDL_Window *window = &display->windows[i];
   622         if (FULLSCREEN_VISIBLE(window)) {
   623             SDL_SetWindowPosition(window->id,
   624                                   ((display_mode.w - window->w) / 2),
   625                                   ((display_mode.h - window->h) / 2));
   626         }
   627     }
   628 
   629     return 0;
   630 }
   631 
   632 int
   633 SDL_SetFullscreenDisplayMode(const SDL_DisplayMode * mode)
   634 {
   635     SDL_VideoDisplay *display;
   636     int i;
   637 
   638     if (!_this) {
   639         SDL_UninitializedVideo();
   640         return -1;
   641     }
   642 
   643     display = &SDL_CurrentDisplay;
   644     if (mode) {
   645         SDL_GetClosestDisplayMode(mode, &display->desired_mode);
   646         display->fullscreen_mode = &display->desired_mode;
   647     } else {
   648         display->fullscreen_mode = NULL;
   649     }
   650 
   651     /* Actually set the mode if we have a fullscreen window visible */
   652     for (i = 0; i < display->num_windows; ++i) {
   653         SDL_Window *window = &display->windows[i];
   654         if (FULLSCREEN_VISIBLE(window)) {
   655             return SDL_SetDisplayMode(display->fullscreen_mode);
   656         }
   657     }
   658     return 0;
   659 }
   660 
   661 const SDL_DisplayMode *
   662 SDL_GetFullscreenDisplayMode(void)
   663 {
   664     if (_this) {
   665         return SDL_CurrentDisplay.fullscreen_mode;
   666     }
   667     return NULL;
   668 }
   669 
   670 int
   671 SDL_SetDisplayPalette(const SDL_Color * colors, int firstcolor, int ncolors)
   672 {
   673     SDL_Palette *palette;
   674     int status = 0;
   675 
   676     if (!_this) {
   677         SDL_UninitializedVideo();
   678         return -1;
   679     }
   680     palette = SDL_CurrentDisplay.palette;
   681     if (!palette) {
   682         SDL_SetError("Display mode does not have a palette");
   683         return -1;
   684     }
   685 
   686     status = SDL_SetPaletteColors(palette, colors, firstcolor, ncolors);
   687 
   688     if (_this->SetDisplayPalette) {
   689         if (_this->SetDisplayPalette(_this, palette) < 0) {
   690             status = -1;
   691         }
   692     }
   693     return status;
   694 }
   695 
   696 int
   697 SDL_GetDisplayPalette(SDL_Color * colors, int firstcolor, int ncolors)
   698 {
   699     SDL_Palette *palette;
   700 
   701     if (!_this) {
   702         SDL_UninitializedVideo();
   703         return -1;
   704     }
   705 
   706     palette = SDL_CurrentDisplay.palette;
   707     if (!palette->ncolors) {
   708         SDL_SetError("Display mode does not have a palette");
   709         return -1;
   710     }
   711 
   712     if (firstcolor < 0 || (firstcolor + ncolors) > palette->ncolors) {
   713         SDL_SetError("Palette indices are out of range");
   714         return -1;
   715     }
   716 
   717     SDL_memcpy(colors, &palette->colors[firstcolor],
   718                ncolors * sizeof(*colors));
   719     return 0;
   720 }
   721 
   722 SDL_WindowID
   723 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
   724 {
   725     const Uint32 allowed_flags = (SDL_WINDOW_FULLSCREEN |
   726                                   SDL_WINDOW_OPENGL |
   727                                   SDL_WINDOW_SHOWN |
   728                                   SDL_WINDOW_BORDERLESS |
   729                                   SDL_WINDOW_RESIZABLE |
   730                                   SDL_WINDOW_MAXIMIZED |
   731                                   SDL_WINDOW_MINIMIZED |
   732                                   SDL_WINDOW_INPUT_GRABBED);
   733     SDL_VideoDisplay *display;
   734     SDL_Window window;
   735     int num_windows;
   736     SDL_Window *windows;
   737 
   738     if (!_this) {
   739         SDL_UninitializedVideo();
   740         return 0;
   741     }
   742 
   743     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
   744         SDL_SetError("No OpenGL support in video driver");
   745         return 0;
   746     }
   747 
   748     SDL_zero(window);
   749     window.id = _this->next_object_id++;
   750     window.title = title ? SDL_strdup(title) : NULL;
   751     window.x = x;
   752     window.y = y;
   753     window.w = w;
   754     window.h = h;
   755     window.flags = (flags & allowed_flags);
   756     window.display = _this->current_display;
   757 
   758     if (_this->CreateWindow && _this->CreateWindow(_this, &window) < 0) {
   759         if (window.title) {
   760             SDL_free(window.title);
   761         }
   762         return 0;
   763     }
   764 
   765     display = &SDL_CurrentDisplay;
   766     num_windows = display->num_windows;
   767     windows =
   768         SDL_realloc(display->windows, (num_windows + 1) * sizeof(*windows));
   769     if (!windows) {
   770         if (_this->DestroyWindow) {
   771             _this->DestroyWindow(_this, &window);
   772         }
   773         if (window.title) {
   774             SDL_free(window.title);
   775         }
   776         return 0;
   777     }
   778     windows[num_windows] = window;
   779     display->windows = windows;
   780     display->num_windows++;
   781 
   782     if (FULLSCREEN_VISIBLE(&window)) {
   783         /* Hide any other fullscreen windows */
   784         int i;
   785         for (i = 0; i < display->num_windows; ++i) {
   786             SDL_Window *other = &display->windows[i];
   787             if (other->id != window.id && FULLSCREEN_VISIBLE(other)) {
   788                 SDL_MinimizeWindow(other->id);
   789             }
   790         }
   791         SDL_SetDisplayMode(display->fullscreen_mode);
   792     }
   793 
   794     return window.id;
   795 }
   796 
   797 SDL_WindowID
   798 SDL_CreateWindowFrom(const void *data)
   799 {
   800     SDL_VideoDisplay *display;
   801     SDL_Window window;
   802     int num_windows;
   803     SDL_Window *windows;
   804 
   805     if (!_this) {
   806         SDL_UninitializedVideo();
   807         return (0);
   808     }
   809 
   810     SDL_zero(window);
   811     window.id = _this->next_object_id++;
   812     window.display = _this->current_display;
   813 
   814     if (!_this->CreateWindowFrom ||
   815         _this->CreateWindowFrom(_this, &window, data) < 0) {
   816         return 0;
   817     }
   818 
   819     display = &SDL_CurrentDisplay;
   820     num_windows = display->num_windows;
   821     windows =
   822         SDL_realloc(display->windows, (num_windows + 1) * sizeof(*windows));
   823     if (!windows) {
   824         if (_this->DestroyWindow) {
   825             _this->DestroyWindow(_this, &window);
   826         }
   827         if (window.title) {
   828             SDL_free(window.title);
   829         }
   830         return 0;
   831     }
   832     windows[num_windows] = window;
   833     display->windows = windows;
   834     display->num_windows++;
   835 
   836     return window.id;
   837 }
   838 
   839 int
   840 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
   841 {
   842     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
   843         SDL_SetError("No OpenGL support in video driver");
   844         return -1;
   845     }
   846     if (_this->DestroyWindow) {
   847         _this->DestroyWindow(_this, window);
   848     }
   849     window->flags = flags;
   850     return _this->CreateWindow(_this, window);
   851 }
   852 
   853 SDL_Window *
   854 SDL_GetWindowFromID(SDL_WindowID windowID)
   855 {
   856     int i, j;
   857 
   858     if (!_this) {
   859         SDL_UninitializedVideo();
   860         return NULL;
   861     }
   862 
   863     for (i = 0; i < _this->num_displays; ++i) {
   864         SDL_VideoDisplay *display = &_this->displays[i];
   865         for (j = 0; j < display->num_windows; ++j) {
   866             SDL_Window *window = &display->windows[j];
   867             if (window->id == windowID) {
   868                 return window;
   869             }
   870         }
   871     }
   872     return NULL;
   873 }
   874 
   875 SDL_VideoDisplay *
   876 SDL_GetDisplayFromWindow(SDL_Window * window)
   877 {
   878     if (!_this) {
   879         SDL_UninitializedVideo();
   880         return NULL;
   881     }
   882     return &_this->displays[window->display];
   883 }
   884 
   885 Uint32
   886 SDL_GetWindowFlags(SDL_WindowID windowID)
   887 {
   888     SDL_Window *window = SDL_GetWindowFromID(windowID);
   889 
   890     if (!window) {
   891         return 0;
   892     }
   893     return window->flags;
   894 }
   895 
   896 void
   897 SDL_SetWindowTitle(SDL_WindowID windowID, const char *title)
   898 {
   899     SDL_Window *window = SDL_GetWindowFromID(windowID);
   900 
   901     if (!window) {
   902         return;
   903     }
   904     if (window->title) {
   905         SDL_free(window->title);
   906     }
   907     window->title = SDL_strdup(title);
   908 
   909     if (_this->SetWindowTitle) {
   910         _this->SetWindowTitle(_this, window);
   911     }
   912 }
   913 
   914 const char *
   915 SDL_GetWindowTitle(SDL_WindowID windowID)
   916 {
   917     SDL_Window *window = SDL_GetWindowFromID(windowID);
   918 
   919     if (!window) {
   920         return NULL;
   921     }
   922     return window->title;
   923 }
   924 
   925 void
   926 SDL_SetWindowData(SDL_WindowID windowID, void *userdata)
   927 {
   928     SDL_Window *window = SDL_GetWindowFromID(windowID);
   929 
   930     if (!window) {
   931         return;
   932     }
   933     window->userdata = userdata;
   934 }
   935 
   936 void *
   937 SDL_GetWindowData(SDL_WindowID windowID)
   938 {
   939     SDL_Window *window = SDL_GetWindowFromID(windowID);
   940 
   941     if (!window) {
   942         return NULL;
   943     }
   944     return window->userdata;
   945 }
   946 
   947 void
   948 SDL_SetWindowPosition(SDL_WindowID windowID, int x, int y)
   949 {
   950     SDL_Window *window = SDL_GetWindowFromID(windowID);
   951 
   952     if (!window) {
   953         return;
   954     }
   955 
   956     if (x != SDL_WINDOWPOS_UNDEFINED) {
   957         window->x = x;
   958     }
   959     if (y != SDL_WINDOWPOS_UNDEFINED) {
   960         window->y = y;
   961     }
   962 
   963     if (_this->SetWindowPosition) {
   964         _this->SetWindowPosition(_this, window);
   965     }
   966 }
   967 
   968 void
   969 SDL_GetWindowPosition(SDL_WindowID windowID, int *x, int *y)
   970 {
   971     SDL_Window *window = SDL_GetWindowFromID(windowID);
   972 
   973     if (!window) {
   974         return;
   975     }
   976     if (x) {
   977         *x = window->x;
   978     }
   979     if (y) {
   980         *y = window->y;
   981     }
   982 }
   983 
   984 void
   985 SDL_SetWindowSize(SDL_WindowID windowID, int w, int h)
   986 {
   987     SDL_Window *window = SDL_GetWindowFromID(windowID);
   988 
   989     if (!window) {
   990         return;
   991     }
   992 
   993     window->w = w;
   994     window->h = h;
   995 
   996     if (_this->SetWindowSize) {
   997         _this->SetWindowSize(_this, window);
   998     }
   999 }
  1000 
  1001 void
  1002 SDL_GetWindowSize(SDL_WindowID windowID, int *w, int *h)
  1003 {
  1004     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1005 
  1006     if (!window) {
  1007         return;
  1008     }
  1009     if (w) {
  1010         *w = window->w;
  1011     }
  1012     if (h) {
  1013         *h = window->h;
  1014     }
  1015 }
  1016 
  1017 void
  1018 SDL_ShowWindow(SDL_WindowID windowID)
  1019 {
  1020     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1021 
  1022     if (!window || (window->flags & SDL_WINDOW_SHOWN)) {
  1023         return;
  1024     }
  1025 
  1026     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1027 
  1028     if (_this->ShowWindow) {
  1029         _this->ShowWindow(_this, window);
  1030     }
  1031 }
  1032 
  1033 void
  1034 SDL_HideWindow(SDL_WindowID windowID)
  1035 {
  1036     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1037 
  1038     if (!window || !(window->flags & SDL_WINDOW_SHOWN)) {
  1039         return;
  1040     }
  1041 
  1042     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1043 
  1044     if (_this->HideWindow) {
  1045         _this->HideWindow(_this, window);
  1046     }
  1047 }
  1048 
  1049 void
  1050 SDL_RaiseWindow(SDL_WindowID windowID)
  1051 {
  1052     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1053 
  1054     if (!window) {
  1055         return;
  1056     }
  1057 
  1058     if (_this->RaiseWindow) {
  1059         _this->RaiseWindow(_this, window);
  1060     }
  1061 }
  1062 
  1063 void
  1064 SDL_MaximizeWindow(SDL_WindowID windowID)
  1065 {
  1066     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1067 
  1068     if (!window || (window->flags & SDL_WINDOW_MAXIMIZED)) {
  1069         return;
  1070     }
  1071 
  1072     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
  1073 
  1074     if (_this->MaximizeWindow) {
  1075         _this->MaximizeWindow(_this, window);
  1076     }
  1077 }
  1078 
  1079 void
  1080 SDL_MinimizeWindow(SDL_WindowID windowID)
  1081 {
  1082     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1083 
  1084     if (!window || (window->flags & SDL_WINDOW_MINIMIZED)) {
  1085         return;
  1086     }
  1087 
  1088     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
  1089 
  1090     if (_this->MinimizeWindow) {
  1091         _this->MinimizeWindow(_this, window);
  1092     }
  1093 }
  1094 
  1095 void
  1096 SDL_RestoreWindow(SDL_WindowID windowID)
  1097 {
  1098     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1099 
  1100     if (!window
  1101         || (window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1102         return;
  1103     }
  1104 
  1105     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_RESTORED, 0, 0);
  1106 
  1107     if (_this->RestoreWindow) {
  1108         _this->RestoreWindow(_this, window);
  1109     }
  1110 }
  1111 
  1112 int
  1113 SDL_SetWindowFullscreen(SDL_WindowID windowID, int fullscreen)
  1114 {
  1115     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1116 
  1117     if (!window) {
  1118         return -1;
  1119     }
  1120 
  1121     if (fullscreen) {
  1122         fullscreen = SDL_WINDOW_FULLSCREEN;
  1123     }
  1124     if ((window->flags & SDL_WINDOW_FULLSCREEN) == fullscreen) {
  1125         return 0;
  1126     }
  1127 
  1128     if (fullscreen) {
  1129         window->flags |= SDL_WINDOW_FULLSCREEN;
  1130 
  1131         if (FULLSCREEN_VISIBLE(window)) {
  1132             SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
  1133 
  1134             /* Hide any other fullscreen windows */
  1135             int i;
  1136             for (i = 0; i < display->num_windows; ++i) {
  1137                 SDL_Window *other = &display->windows[i];
  1138                 if (other->id != windowID && FULLSCREEN_VISIBLE(other)) {
  1139                     SDL_MinimizeWindow(other->id);
  1140                 }
  1141             }
  1142 
  1143             SDL_SetDisplayMode(display->fullscreen_mode);
  1144         }
  1145     } else {
  1146         window->flags &= ~SDL_WINDOW_FULLSCREEN;
  1147 
  1148         if (FULLSCREEN_VISIBLE(window)) {
  1149             SDL_SetDisplayMode(NULL);
  1150         }
  1151     }
  1152     return 0;
  1153 }
  1154 
  1155 void
  1156 SDL_SetWindowGrab(SDL_WindowID windowID, int mode)
  1157 {
  1158     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1159 
  1160     if (!window || (!!mode == !!(window->flags & SDL_WINDOW_INPUT_GRABBED))) {
  1161         return;
  1162     }
  1163 
  1164     if (mode) {
  1165         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1166     } else {
  1167         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  1168     }
  1169 
  1170     if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) {
  1171         _this->SetWindowGrab(_this, window);
  1172     }
  1173 }
  1174 
  1175 int
  1176 SDL_GetWindowGrab(SDL_WindowID windowID)
  1177 {
  1178     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1179 
  1180     if (!window) {
  1181         return 0;
  1182     }
  1183 
  1184     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  1185 }
  1186 
  1187 void
  1188 SDL_OnWindowShown(SDL_Window * window)
  1189 {
  1190 }
  1191 
  1192 void
  1193 SDL_OnWindowHidden(SDL_Window * window)
  1194 {
  1195 }
  1196 
  1197 void
  1198 SDL_OnWindowFocusGained(SDL_Window * window)
  1199 {
  1200     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
  1201 
  1202     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1203         SDL_SetDisplayMode(display->fullscreen_mode);
  1204     }
  1205     if (display->gamma && _this->SetDisplayGammaRamp) {
  1206         _this->SetDisplayGammaRamp(_this, display->gamma);
  1207     }
  1208     if ((window->flags & SDL_WINDOW_INPUT_GRABBED) && _this->SetWindowGrab) {
  1209         _this->SetWindowGrab(_this, window);
  1210     }
  1211 }
  1212 
  1213 void
  1214 SDL_OnWindowFocusLost(SDL_Window * window)
  1215 {
  1216     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
  1217 
  1218     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1219         SDL_MinimizeWindow(window->id);
  1220         SDL_SetDisplayMode(NULL);
  1221     }
  1222     if (display->gamma && _this->SetDisplayGammaRamp) {
  1223         _this->SetDisplayGammaRamp(_this, display->saved_gamma);
  1224     }
  1225     if ((window->flags & SDL_WINDOW_INPUT_GRABBED) && _this->SetWindowGrab) {
  1226         _this->SetWindowGrab(_this, window);
  1227     }
  1228 }
  1229 
  1230 SDL_WindowID
  1231 SDL_GetFocusWindow(void)
  1232 {
  1233     SDL_VideoDisplay *display;
  1234     int i;
  1235 
  1236     if (!_this) {
  1237         return 0;
  1238     }
  1239 
  1240     display = &SDL_CurrentDisplay;
  1241     for (i = 0; i < display->num_windows; ++i) {
  1242         SDL_Window *window = &display->windows[i];
  1243 
  1244         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1245             return window->id;
  1246         }
  1247     }
  1248     return 0;
  1249 }
  1250 
  1251 void
  1252 SDL_DestroyWindow(SDL_WindowID windowID)
  1253 {
  1254     int i, j;
  1255 
  1256     if (!_this) {
  1257         return;
  1258     }
  1259 
  1260     /* Restore video mode, etc. */
  1261     SDL_SendWindowEvent(windowID, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
  1262 
  1263     for (i = 0; i < _this->num_displays; ++i) {
  1264         SDL_VideoDisplay *display = &_this->displays[i];
  1265         for (j = 0; j < display->num_windows; ++j) {
  1266             SDL_Window *window = &display->windows[j];
  1267             if (window->id != windowID) {
  1268                 continue;
  1269             }
  1270             if (window->renderer) {
  1271                 SDL_DestroyRenderer(window->id);
  1272             }
  1273             if (_this->DestroyWindow) {
  1274                 _this->DestroyWindow(_this, window);
  1275             }
  1276             if (window->title) {
  1277                 SDL_free(window->title);
  1278             }
  1279             if (j != display->num_windows - 1) {
  1280                 SDL_memcpy(&display->windows[i],
  1281                            &display->windows[i + 1],
  1282                            (display->num_windows - i - 1) * sizeof(*window));
  1283             }
  1284             --display->num_windows;
  1285             return;
  1286         }
  1287     }
  1288 }
  1289 
  1290 void
  1291 SDL_AddRenderDriver(int displayIndex, const SDL_RenderDriver * driver)
  1292 {
  1293     SDL_VideoDisplay *display = &_this->displays[displayIndex];
  1294     SDL_RenderDriver *render_drivers;
  1295 
  1296     render_drivers =
  1297         SDL_realloc(display->render_drivers,
  1298                     (display->num_render_drivers +
  1299                      1) * sizeof(*render_drivers));
  1300     if (render_drivers) {
  1301         render_drivers[display->num_render_drivers] = *driver;
  1302         display->render_drivers = render_drivers;
  1303         display->num_render_drivers++;
  1304     }
  1305 }
  1306 
  1307 int
  1308 SDL_GetNumRenderers(void)
  1309 {
  1310     if (_this) {
  1311         return SDL_CurrentDisplay.num_render_drivers;
  1312     }
  1313     return 0;
  1314 }
  1315 
  1316 int
  1317 SDL_GetRendererInfo(int index, SDL_RendererInfo * info)
  1318 {
  1319     if (!_this) {
  1320         SDL_UninitializedVideo();
  1321         return -1;
  1322     }
  1323 
  1324     if (index >= SDL_GetNumRenderers()) {
  1325         SDL_SetError("index must be in the range of 0 - %d",
  1326                      SDL_GetNumRenderers() - 1);
  1327         return -1;
  1328     }
  1329     if (index < 0) {
  1330         if (!SDL_CurrentDisplay.current_renderer) {
  1331             SDL_SetError("There is no current renderer");
  1332             return -1;
  1333         }
  1334         *info = SDL_CurrentDisplay.current_renderer->info;
  1335     } else {
  1336         *info = SDL_CurrentDisplay.render_drivers[index].info;
  1337     }
  1338     return 0;
  1339 }
  1340 
  1341 int
  1342 SDL_CreateRenderer(SDL_WindowID windowID, int index, Uint32 flags)
  1343 {
  1344     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1345 
  1346     if (!window) {
  1347         return 0;
  1348     }
  1349 
  1350     if (index < 0) {
  1351         const char *override = SDL_getenv("SDL_VIDEO_RENDERER");
  1352         int n = SDL_GetNumRenderers();
  1353         for (index = 0; index < n; ++index) {
  1354             SDL_RenderDriver *driver =
  1355                 &SDL_CurrentDisplay.render_drivers[index];
  1356 
  1357             if (override) {
  1358                 if (SDL_strcasecmp(override, driver->info.name) == 0) {
  1359                     break;
  1360                 }
  1361             } else {
  1362                 if ((driver->info.flags & flags) == flags) {
  1363                     break;
  1364                 }
  1365             }
  1366         }
  1367         if (index == n) {
  1368             SDL_SetError("Couldn't find matching render driver");
  1369             return -1;
  1370         }
  1371     }
  1372 
  1373     if (index >= SDL_GetNumRenderers()) {
  1374         SDL_SetError("index must be -1 or in the range of 0 - %d",
  1375                      SDL_GetNumRenderers() - 1);
  1376         return -1;
  1377     }
  1378 
  1379     /* Free any existing renderer */
  1380     SDL_DestroyRenderer(windowID);
  1381 
  1382     /* Create a new renderer instance */
  1383     window->renderer =
  1384         SDL_CurrentDisplay.render_drivers[index].CreateRenderer(window,
  1385                                                                 flags);
  1386     SDL_SelectRenderer(window->id);
  1387 
  1388     return 0;
  1389 }
  1390 
  1391 int
  1392 SDL_SelectRenderer(SDL_WindowID windowID)
  1393 {
  1394     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1395     SDL_Renderer *renderer;
  1396 
  1397     if (!window || !window->renderer) {
  1398         return -1;
  1399     }
  1400     renderer = window->renderer;
  1401     if (renderer && renderer->ActivateRenderer) {
  1402         if (renderer->ActivateRenderer(renderer) < 0) {
  1403             return -1;
  1404         }
  1405     }
  1406     SDL_CurrentDisplay.current_renderer = renderer;
  1407     return 0;
  1408 }
  1409 
  1410 SDL_TextureID
  1411 SDL_CreateTexture(Uint32 format, int access, int w, int h)
  1412 {
  1413     int hash;
  1414     SDL_Renderer *renderer;
  1415     SDL_Texture *texture;
  1416 
  1417     if (!_this) {
  1418         SDL_UninitializedVideo();
  1419         return 0;
  1420     }
  1421 
  1422     renderer = SDL_CurrentDisplay.current_renderer;
  1423     if (!renderer || !renderer->CreateTexture) {
  1424         return 0;
  1425     }
  1426 
  1427     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
  1428     if (!texture) {
  1429         SDL_OutOfMemory();
  1430         return 0;
  1431     }
  1432 
  1433     texture->id = _this->next_object_id++;
  1434     texture->format = format;
  1435     texture->access = access;
  1436     texture->w = w;
  1437     texture->h = h;
  1438     texture->renderer = renderer;
  1439 
  1440     if (renderer->CreateTexture(renderer, texture) < 0) {
  1441         if (renderer->DestroyTexture) {
  1442             renderer->DestroyTexture(renderer, texture);
  1443         }
  1444         SDL_free(texture);
  1445         return 0;
  1446     }
  1447 
  1448     hash = (texture->id % SDL_arraysize(SDL_CurrentDisplay.textures));
  1449     texture->next = SDL_CurrentDisplay.textures[hash];
  1450     SDL_CurrentDisplay.textures[hash] = texture;
  1451 
  1452     return texture->id;
  1453 }
  1454 
  1455 SDL_TextureID
  1456 SDL_CreateTextureFromSurface(Uint32 format, int access, SDL_Surface * surface)
  1457 {
  1458     SDL_TextureID textureID;
  1459     Uint32 surface_flags = surface->flags;
  1460     SDL_PixelFormat *fmt = surface->format;
  1461     Uint8 alpha;
  1462     SDL_Rect bounds;
  1463     SDL_Surface dst;
  1464     int bpp;
  1465     Uint32 Rmask, Gmask, Bmask, Amask;
  1466 
  1467     if (!surface) {
  1468         SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
  1469         return 0;
  1470     }
  1471 
  1472     if (format) {
  1473         if (!SDL_PixelFormatEnumToMasks
  1474             (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1475             SDL_SetError("Unknown pixel format");
  1476             return 0;
  1477         }
  1478     } else {
  1479         if (fmt->Amask || !(surface_flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA))) {
  1480             bpp = fmt->BitsPerPixel;
  1481             Rmask = fmt->Rmask;
  1482             Gmask = fmt->Gmask;
  1483             Bmask = fmt->Bmask;
  1484             Amask = fmt->Amask;
  1485         } else {
  1486             /* Need a format with alpha */
  1487             bpp = 32;
  1488             Rmask = 0x00FF0000;
  1489             Gmask = 0x0000FF00;
  1490             Bmask = 0x000000FF;
  1491             Amask = 0xFF000000;
  1492         }
  1493         format = SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
  1494         if (!format) {
  1495             SDL_SetError("Unknown pixel format");
  1496             return 0;
  1497         }
  1498     }
  1499 
  1500     textureID = SDL_CreateTexture(format, access, surface->w, surface->h);
  1501     if (!textureID) {
  1502         return 0;
  1503     }
  1504 
  1505     /* Set up a destination surface for the texture update */
  1506     SDL_zero(dst);
  1507     dst.format = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask);
  1508     if (!dst.format) {
  1509         SDL_DestroyTexture(textureID);
  1510         return 0;
  1511     }
  1512     dst.w = surface->w;
  1513     dst.h = surface->h;
  1514     if (SDL_LockTexture(textureID, NULL, 1, &dst.pixels, &dst.pitch) == 0) {
  1515         dst.flags |= SDL_PREALLOC;
  1516     } else {
  1517         dst.pitch = SDL_CalculatePitch(&dst);
  1518         dst.pixels = SDL_malloc(dst.h * dst.pitch);
  1519         if (!dst.pixels) {
  1520             SDL_DestroyTexture(textureID);
  1521             SDL_FreeFormat(dst.format);
  1522             SDL_OutOfMemory();
  1523             return 0;
  1524         }
  1525     }
  1526 
  1527     /* Copy the palette if any */
  1528     if (SDL_ISPIXELFORMAT_INDEXED(format)) {
  1529         if (fmt->palette) {
  1530             SDL_SetTexturePalette(textureID, fmt->palette->colors, 0,
  1531                                   fmt->palette->ncolors);
  1532             SDL_SetSurfacePalette(&dst, fmt->palette);
  1533         } else {
  1534             dst.format->palette =
  1535                 SDL_AllocPalette((1 << SDL_BITSPERPIXEL(format)));
  1536             if (!dst.format->palette) {
  1537                 SDL_DestroyTexture(textureID);
  1538                 SDL_FreeFormat(dst.format);
  1539                 return 0;
  1540             }
  1541             SDL_DitherColors(dst.format->palette->colors,
  1542                              SDL_BITSPERPIXEL(format));
  1543         }
  1544     }
  1545 
  1546     /* Make the texture transparent if the surface has colorkey */
  1547     if (surface_flags & SDL_SRCCOLORKEY) {
  1548         int row;
  1549         int length = dst.w * dst.format->BytesPerPixel;
  1550         Uint8 *p = (Uint8 *) dst.pixels;
  1551         for (row = 0; row < dst.h; ++row) {
  1552             SDL_memset(p, 0, length);
  1553             p += dst.pitch;
  1554         }
  1555     }
  1556 
  1557     /* Copy over the alpha channel */
  1558     if (surface_flags & SDL_SRCALPHA) {
  1559         if (fmt->Amask) {
  1560             surface->flags &= ~SDL_SRCALPHA;
  1561         } else {
  1562             /* FIXME: Need to make sure the texture has an alpha channel
  1563              *        and copy 'alpha' into the texture alpha channel.
  1564              */
  1565             alpha = surface->format->alpha;
  1566             SDL_SetAlpha(surface, 0, 0);
  1567         }
  1568     }
  1569 
  1570     /* Copy over the image data */
  1571     bounds.x = 0;
  1572     bounds.y = 0;
  1573     bounds.w = surface->w;
  1574     bounds.h = surface->h;
  1575     SDL_LowerBlit(surface, &bounds, &dst, &bounds);
  1576 
  1577     /* Clean up the original surface */
  1578     if ((surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
  1579         Uint32 aflags = surface_flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
  1580         if (fmt->Amask) {
  1581             surface->flags |= SDL_SRCALPHA;
  1582         } else {
  1583             SDL_SetAlpha(surface, aflags, alpha);
  1584         }
  1585     }
  1586 
  1587     /* Update the texture */
  1588     if (dst.flags & SDL_PREALLOC) {
  1589         SDL_UnlockTexture(textureID);
  1590     } else {
  1591         SDL_UpdateTexture(textureID, NULL, dst.pixels, dst.pitch);
  1592         SDL_free(dst.pixels);
  1593     }
  1594     SDL_FreeFormat(dst.format);
  1595 
  1596     return textureID;
  1597 }
  1598 
  1599 static __inline__ SDL_Texture *
  1600 SDL_GetTextureFromID(SDL_TextureID textureID)
  1601 {
  1602     int hash;
  1603     SDL_Texture *texture;
  1604 
  1605     if (!_this) {
  1606         return NULL;
  1607     }
  1608 
  1609     hash = (textureID % SDL_arraysize(SDL_CurrentDisplay.textures));
  1610     for (texture = SDL_CurrentDisplay.textures[hash]; texture;
  1611          texture = texture->next) {
  1612         if (texture->id == textureID) {
  1613             return texture;
  1614         }
  1615     }
  1616     return NULL;
  1617 }
  1618 
  1619 int
  1620 SDL_QueryTexture(SDL_TextureID textureID, Uint32 * format, int *access,
  1621                  int *w, int *h)
  1622 {
  1623     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1624 
  1625     if (!texture) {
  1626         return -1;
  1627     }
  1628 
  1629     if (format) {
  1630         *format = texture->format;
  1631     }
  1632     if (access) {
  1633         *access = texture->access;
  1634     }
  1635     if (w) {
  1636         *w = texture->w;
  1637     }
  1638     if (h) {
  1639         *h = texture->h;
  1640     }
  1641     return 0;
  1642 }
  1643 
  1644 int
  1645 SDL_QueryTexturePixels(SDL_TextureID textureID, void **pixels, int *pitch)
  1646 {
  1647     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1648     SDL_Renderer *renderer;
  1649 
  1650     if (!texture) {
  1651         return -1;
  1652     }
  1653 
  1654     renderer = texture->renderer;
  1655     if (!renderer->QueryTexturePixels) {
  1656         return -1;
  1657     }
  1658     return renderer->QueryTexturePixels(renderer, texture, pixels, pitch);
  1659 }
  1660 
  1661 int
  1662 SDL_SetTexturePalette(SDL_TextureID textureID, const SDL_Color * colors,
  1663                       int firstcolor, int ncolors)
  1664 {
  1665     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1666     SDL_Renderer *renderer;
  1667 
  1668     if (!texture) {
  1669         return -1;
  1670     }
  1671 
  1672     renderer = texture->renderer;
  1673     if (!renderer->SetTexturePalette) {
  1674         return -1;
  1675     }
  1676     return renderer->SetTexturePalette(renderer, texture, colors, firstcolor,
  1677                                        ncolors);
  1678 }
  1679 
  1680 int
  1681 SDL_GetTexturePalette(SDL_TextureID textureID, SDL_Color * colors,
  1682                       int firstcolor, int ncolors)
  1683 {
  1684     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1685     SDL_Renderer *renderer;
  1686 
  1687     if (!texture) {
  1688         return -1;
  1689     }
  1690 
  1691     renderer = texture->renderer;
  1692     if (!renderer->GetTexturePalette) {
  1693         return -1;
  1694     }
  1695     return renderer->GetTexturePalette(renderer, texture, colors, firstcolor,
  1696                                        ncolors);
  1697 }
  1698 
  1699 int
  1700 SDL_UpdateTexture(SDL_TextureID textureID, const SDL_Rect * rect,
  1701                   const void *pixels, int pitch)
  1702 {
  1703     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1704     SDL_Renderer *renderer;
  1705     SDL_Rect full_rect;
  1706 
  1707     if (!texture) {
  1708         return -1;
  1709     }
  1710 
  1711     renderer = texture->renderer;
  1712     if (!renderer->UpdateTexture) {
  1713         return -1;
  1714     }
  1715 
  1716     if (!rect) {
  1717         full_rect.x = 0;
  1718         full_rect.y = 0;
  1719         full_rect.w = texture->w;
  1720         full_rect.h = texture->h;
  1721         rect = &full_rect;
  1722     }
  1723 
  1724     return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
  1725 }
  1726 
  1727 int
  1728 SDL_LockTexture(SDL_TextureID textureID, const SDL_Rect * rect, int markDirty,
  1729                 void **pixels, int *pitch)
  1730 {
  1731     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1732     SDL_Renderer *renderer;
  1733     SDL_Rect full_rect;
  1734 
  1735     if (!texture) {
  1736         return -1;
  1737     }
  1738 
  1739     renderer = texture->renderer;
  1740     if (!renderer->LockTexture) {
  1741         return -1;
  1742     }
  1743 
  1744     if (!rect) {
  1745         full_rect.x = 0;
  1746         full_rect.y = 0;
  1747         full_rect.w = texture->w;
  1748         full_rect.h = texture->h;
  1749         rect = &full_rect;
  1750     }
  1751 
  1752     return renderer->LockTexture(renderer, texture, rect, markDirty, pixels,
  1753                                  pitch);
  1754 }
  1755 
  1756 void
  1757 SDL_UnlockTexture(SDL_TextureID textureID)
  1758 {
  1759     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1760     SDL_Renderer *renderer;
  1761 
  1762     if (!texture) {
  1763         return;
  1764     }
  1765 
  1766     renderer = texture->renderer;
  1767     if (!renderer->UnlockTexture) {
  1768         return;
  1769     }
  1770     renderer->UnlockTexture(renderer, texture);
  1771 }
  1772 
  1773 void
  1774 SDL_DirtyTexture(SDL_TextureID textureID, int numrects,
  1775                  const SDL_Rect * rects)
  1776 {
  1777     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1778     SDL_Renderer *renderer;
  1779 
  1780     if (!texture) {
  1781         return;
  1782     }
  1783 
  1784     renderer = texture->renderer;
  1785     if (!renderer->DirtyTexture) {
  1786         return;
  1787     }
  1788     renderer->DirtyTexture(renderer, texture, numrects, rects);
  1789 }
  1790 
  1791 int
  1792 SDL_RenderFill(const SDL_Rect * rect, Uint32 color)
  1793 {
  1794     SDL_Renderer *renderer;
  1795     SDL_Window *window;
  1796     SDL_Rect real_rect;
  1797 
  1798     if (!_this) {
  1799         SDL_UninitializedVideo();
  1800         return -1;
  1801     }
  1802 
  1803     renderer = SDL_CurrentDisplay.current_renderer;
  1804     if (!renderer || !renderer->RenderFill) {
  1805         return -1;
  1806     }
  1807 
  1808     window = SDL_GetWindowFromID(renderer->window);
  1809     real_rect.x = 0;
  1810     real_rect.y = 0;
  1811     real_rect.w = window->w;
  1812     real_rect.h = window->h;
  1813     if (rect) {
  1814         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  1815             return 0;
  1816         }
  1817     }
  1818 
  1819     return renderer->RenderFill(renderer, &real_rect, color);
  1820 }
  1821 
  1822 int
  1823 SDL_RenderCopy(SDL_TextureID textureID, const SDL_Rect * srcrect,
  1824                const SDL_Rect * dstrect, int blendMode, int scaleMode)
  1825 {
  1826     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1827     SDL_Renderer *renderer;
  1828     SDL_Window *window;
  1829     SDL_Rect real_srcrect;
  1830     SDL_Rect real_dstrect;
  1831 
  1832     if (!texture || texture->renderer != SDL_CurrentDisplay.current_renderer) {
  1833         return -1;
  1834     }
  1835 
  1836     renderer = SDL_CurrentDisplay.current_renderer;
  1837     if (!renderer || !renderer->RenderCopy) {
  1838         return -1;
  1839     }
  1840 
  1841     window = SDL_GetWindowFromID(renderer->window);
  1842     if (srcrect) {
  1843         real_srcrect = *srcrect;
  1844     } else {
  1845         real_srcrect.x = 0;
  1846         real_srcrect.y = 0;
  1847         real_srcrect.w = texture->w;
  1848         real_srcrect.h = texture->h;
  1849     }
  1850     if (dstrect) {
  1851         real_dstrect = *dstrect;
  1852     } else {
  1853         real_dstrect.x = 0;
  1854         real_dstrect.y = 0;
  1855         real_dstrect.w = window->w;
  1856         real_dstrect.h = window->h;
  1857     }
  1858 
  1859     return renderer->RenderCopy(renderer, texture, &real_srcrect,
  1860                                 &real_dstrect, blendMode, scaleMode);
  1861 }
  1862 
  1863 void
  1864 SDL_RenderPresent(void)
  1865 {
  1866     SDL_Renderer *renderer;
  1867 
  1868     if (!_this) {
  1869         SDL_UninitializedVideo();
  1870         return;
  1871     }
  1872 
  1873     renderer = SDL_CurrentDisplay.current_renderer;
  1874     if (!renderer || !renderer->RenderPresent) {
  1875         return;
  1876     }
  1877     renderer->RenderPresent(renderer);
  1878 }
  1879 
  1880 void
  1881 SDL_DestroyTexture(SDL_TextureID textureID)
  1882 {
  1883     int hash;
  1884     SDL_Texture *prev, *texture;
  1885     SDL_Renderer *renderer;
  1886 
  1887     if (!_this) {
  1888         SDL_UninitializedVideo();
  1889         return;
  1890     }
  1891 
  1892     /* Look up the texture in the hash table */
  1893     hash = (textureID % SDL_arraysize(SDL_CurrentDisplay.textures));
  1894     prev = NULL;
  1895     for (texture = SDL_CurrentDisplay.textures[hash]; texture;
  1896          prev = texture, texture = texture->next) {
  1897         if (texture->id == textureID) {
  1898             break;
  1899         }
  1900     }
  1901     if (!texture) {
  1902         return;
  1903     }
  1904 
  1905     /* Unlink the texture from the list */
  1906     if (prev) {
  1907         prev->next = texture->next;
  1908     } else {
  1909         SDL_CurrentDisplay.textures[hash] = texture->next;
  1910     }
  1911 
  1912     /* Free the texture */
  1913     renderer = texture->renderer;
  1914     renderer->DestroyTexture(renderer, texture);
  1915     SDL_free(texture);
  1916 }
  1917 
  1918 void
  1919 SDL_DestroyRenderer(SDL_WindowID windowID)
  1920 {
  1921     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1922     SDL_Renderer *renderer;
  1923     int i;
  1924 
  1925     if (!window) {
  1926         return;
  1927     }
  1928 
  1929     renderer = window->renderer;
  1930     if (!renderer) {
  1931         return;
  1932     }
  1933 
  1934     /* Free existing textures for this renderer */
  1935     for (i = 0; i < SDL_arraysize(SDL_CurrentDisplay.textures); ++i) {
  1936         SDL_Texture *texture;
  1937         SDL_Texture *prev = NULL;
  1938         SDL_Texture *next;
  1939         for (texture = SDL_CurrentDisplay.textures[i]; texture;
  1940              texture = next) {
  1941             next = texture->next;
  1942             if (texture->renderer == renderer) {
  1943                 if (prev) {
  1944                     prev->next = next;
  1945                 } else {
  1946                     SDL_CurrentDisplay.textures[i] = next;
  1947                 }
  1948                 renderer->DestroyTexture(renderer, texture);
  1949                 SDL_free(texture);
  1950             } else {
  1951                 prev = texture;
  1952             }
  1953         }
  1954     }
  1955 
  1956     /* Free the renderer instance */
  1957     renderer->DestroyRenderer(renderer);
  1958 
  1959     /* Clear references */
  1960     window->renderer = NULL;
  1961     if (SDL_CurrentDisplay.current_renderer == renderer) {
  1962         SDL_CurrentDisplay.current_renderer = NULL;
  1963     }
  1964 }
  1965 
  1966 void
  1967 SDL_VideoQuit(void)
  1968 {
  1969     int i, j;
  1970 
  1971     if (!_this) {
  1972         return;
  1973     }
  1974 
  1975     /* Halt event processing before doing anything else */
  1976     SDL_StopEventLoop();
  1977 
  1978     /* Clean up the system video */
  1979     for (i = _this->num_displays; i--;) {
  1980         SDL_VideoDisplay *display = &_this->displays[i];
  1981         for (j = display->num_windows; j--;) {
  1982             SDL_DestroyWindow(display->windows[i].id);
  1983         }
  1984         if (display->windows) {
  1985             SDL_free(display->windows);
  1986             display->windows = NULL;
  1987         }
  1988         display->num_windows = 0;
  1989     }
  1990     _this->VideoQuit(_this);
  1991 
  1992     for (i = _this->num_displays; i--;) {
  1993         SDL_VideoDisplay *display = &_this->displays[i];
  1994         for (j = display->num_display_modes; j--;) {
  1995             if (display->display_modes[j].driverdata) {
  1996                 SDL_free(display->display_modes[j].driverdata);
  1997                 display->display_modes[j].driverdata = NULL;
  1998             }
  1999         }
  2000         if (display->display_modes) {
  2001             SDL_free(display->display_modes);
  2002             display->display_modes = NULL;
  2003         }
  2004         if (display->desktop_mode.driverdata) {
  2005             SDL_free(display->desktop_mode.driverdata);
  2006             display->desktop_mode.driverdata = NULL;
  2007         }
  2008         if (display->palette) {
  2009             SDL_FreePalette(display->palette);
  2010             display->palette = NULL;
  2011         }
  2012         if (display->gamma) {
  2013             SDL_free(display->gamma);
  2014         }
  2015         if (display->driverdata) {
  2016             SDL_free(display->driverdata);
  2017         }
  2018     }
  2019     if (_this->displays) {
  2020         SDL_free(_this->displays);
  2021         _this->displays = NULL;
  2022     }
  2023     _this->free(_this);
  2024     _this = NULL;
  2025 }
  2026 
  2027 int
  2028 SDL_GL_LoadLibrary(const char *path)
  2029 {
  2030     int retval;
  2031 
  2032     if (!_this) {
  2033         SDL_UninitializedVideo();
  2034         return -1;
  2035     }
  2036 
  2037     if (_this->GL_LoadLibrary) {
  2038         retval = _this->GL_LoadLibrary(_this, path);
  2039     } else {
  2040         SDL_SetError("No dynamic GL support in video driver");
  2041         retval = -1;
  2042     }
  2043     return (retval);
  2044 }
  2045 
  2046 void *
  2047 SDL_GL_GetProcAddress(const char *proc)
  2048 {
  2049     void *func;
  2050 
  2051     if (!_this) {
  2052         SDL_UninitializedVideo();
  2053         return NULL;
  2054     }
  2055 
  2056     func = NULL;
  2057     if (_this->GL_GetProcAddress) {
  2058         if (_this->gl_config.driver_loaded) {
  2059             func = _this->GL_GetProcAddress(_this, proc);
  2060         } else {
  2061             SDL_SetError("No GL driver has been loaded");
  2062         }
  2063     } else {
  2064         SDL_SetError("No dynamic GL support in video driver");
  2065     }
  2066     return func;
  2067 }
  2068 
  2069 SDL_bool
  2070 SDL_GL_ExtensionSupported(const char *extension)
  2071 {
  2072 #if SDL_VIDEO_OPENGL
  2073     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2074     const char *extensions;
  2075     const char *start;
  2076     const char *where, *terminator;
  2077 
  2078     /* Extension names should not have spaces. */
  2079     where = SDL_strchr(extension, ' ');
  2080     if (where || *extension == '\0') {
  2081         return SDL_FALSE;
  2082     }
  2083 
  2084     /* See if there's an environment variable override */
  2085     start = SDL_getenv(extension);
  2086     if (start && *start == '0') {
  2087         return SDL_FALSE;
  2088     }
  2089 
  2090     /* Lookup the available extensions */
  2091     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2092     if (glGetStringFunc) {
  2093         extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2094     } else {
  2095         extensions = NULL;
  2096     }
  2097     if (!extensions) {
  2098         return SDL_FALSE;
  2099     }
  2100 
  2101     /* It takes a bit of care to be fool-proof about parsing the
  2102      * OpenGL extensions string. Don't be fooled by sub-strings,
  2103      * etc. */
  2104 
  2105     start = extensions;
  2106 
  2107     for (;;) {
  2108         where = SDL_strstr(start, extension);
  2109         if (!where)
  2110             break;
  2111 
  2112         terminator = where + SDL_strlen(extension);
  2113         if (where == start || *(where - 1) == ' ')
  2114             if (*terminator == ' ' || *terminator == '\0')
  2115                 return SDL_TRUE;
  2116 
  2117         start = terminator;
  2118     }
  2119     return SDL_FALSE;
  2120 #else
  2121     return SDL_FALSE;
  2122 #endif
  2123 }
  2124 
  2125 int
  2126 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2127 {
  2128 #if SDL_VIDEO_OPENGL
  2129     int retval;
  2130 
  2131     if (!_this) {
  2132         SDL_UninitializedVideo();
  2133         return -1;
  2134     }
  2135 
  2136     retval = 0;
  2137     switch (attr) {
  2138     case SDL_GL_RED_SIZE:
  2139         _this->gl_config.red_size = value;
  2140         break;
  2141     case SDL_GL_GREEN_SIZE:
  2142         _this->gl_config.green_size = value;
  2143         break;
  2144     case SDL_GL_BLUE_SIZE:
  2145         _this->gl_config.blue_size = value;
  2146         break;
  2147     case SDL_GL_ALPHA_SIZE:
  2148         _this->gl_config.alpha_size = value;
  2149         break;
  2150     case SDL_GL_DOUBLEBUFFER:
  2151         _this->gl_config.double_buffer = value;
  2152         break;
  2153     case SDL_GL_BUFFER_SIZE:
  2154         _this->gl_config.buffer_size = value;
  2155         break;
  2156     case SDL_GL_DEPTH_SIZE:
  2157         _this->gl_config.depth_size = value;
  2158         break;
  2159     case SDL_GL_STENCIL_SIZE:
  2160         _this->gl_config.stencil_size = value;
  2161         break;
  2162     case SDL_GL_ACCUM_RED_SIZE:
  2163         _this->gl_config.accum_red_size = value;
  2164         break;
  2165     case SDL_GL_ACCUM_GREEN_SIZE:
  2166         _this->gl_config.accum_green_size = value;
  2167         break;
  2168     case SDL_GL_ACCUM_BLUE_SIZE:
  2169         _this->gl_config.accum_blue_size = value;
  2170         break;
  2171     case SDL_GL_ACCUM_ALPHA_SIZE:
  2172         _this->gl_config.accum_alpha_size = value;
  2173         break;
  2174     case SDL_GL_STEREO:
  2175         _this->gl_config.stereo = value;
  2176         break;
  2177     case SDL_GL_MULTISAMPLEBUFFERS:
  2178         _this->gl_config.multisamplebuffers = value;
  2179         break;
  2180     case SDL_GL_MULTISAMPLESAMPLES:
  2181         _this->gl_config.multisamplesamples = value;
  2182         break;
  2183     case SDL_GL_ACCELERATED_VISUAL:
  2184         _this->gl_config.accelerated = value;
  2185         break;
  2186     default:
  2187         SDL_SetError("Unknown OpenGL attribute");
  2188         retval = -1;
  2189         break;
  2190     }
  2191     return retval;
  2192 #else
  2193     SDL_Unsupported();
  2194     return -1;
  2195 #endif /* SDL_VIDEO_OPENGL */
  2196 }
  2197 
  2198 int
  2199 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2200 {
  2201 #if SDL_VIDEO_OPENGL
  2202     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2203     GLenum attrib = 0;
  2204 
  2205     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2206     if (!glGetIntegervFunc) {
  2207         return -1;
  2208     }
  2209     switch (attr) {
  2210     case SDL_GL_RED_SIZE:
  2211         attrib = GL_RED_BITS;
  2212         break;
  2213     case SDL_GL_BLUE_SIZE:
  2214         attrib = GL_BLUE_BITS;
  2215         break;
  2216     case SDL_GL_GREEN_SIZE:
  2217         attrib = GL_GREEN_BITS;
  2218         break;
  2219     case SDL_GL_ALPHA_SIZE:
  2220         attrib = GL_ALPHA_BITS;
  2221         break;
  2222     case SDL_GL_DOUBLEBUFFER:
  2223         attrib = GL_DOUBLEBUFFER;
  2224         break;
  2225     case SDL_GL_DEPTH_SIZE:
  2226         attrib = GL_DEPTH_BITS;
  2227         break;
  2228     case SDL_GL_STENCIL_SIZE:
  2229         attrib = GL_STENCIL_BITS;
  2230         break;
  2231     case SDL_GL_ACCUM_RED_SIZE:
  2232         attrib = GL_ACCUM_RED_BITS;
  2233         break;
  2234     case SDL_GL_ACCUM_GREEN_SIZE:
  2235         attrib = GL_ACCUM_GREEN_BITS;
  2236         break;
  2237     case SDL_GL_ACCUM_BLUE_SIZE:
  2238         attrib = GL_ACCUM_BLUE_BITS;
  2239         break;
  2240     case SDL_GL_ACCUM_ALPHA_SIZE:
  2241         attrib = GL_ACCUM_ALPHA_BITS;
  2242         break;
  2243     case SDL_GL_STEREO:
  2244         attrib = GL_STEREO;
  2245         break;
  2246     case SDL_GL_MULTISAMPLEBUFFERS:
  2247         attrib = GL_SAMPLE_BUFFERS_ARB;
  2248         break;
  2249     case SDL_GL_MULTISAMPLESAMPLES:
  2250         attrib = GL_SAMPLES_ARB;
  2251         break;
  2252     case SDL_GL_BUFFER_SIZE:
  2253         {
  2254             GLint bits = 0;
  2255             GLint component;
  2256 
  2257             /* there doesn't seem to be a single flag in OpenGL for this! */
  2258             glGetIntegervFunc(GL_RED_BITS, &component);
  2259             bits += component;
  2260             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2261             bits += component;
  2262             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2263             bits += component;
  2264             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2265             bits += component;
  2266 
  2267             *value = bits;
  2268             return 0;
  2269         }
  2270     case SDL_GL_ACCELERATED_VISUAL:
  2271         {
  2272             /* FIXME: How do we get this information? */
  2273             *value = (_this->gl_config.accelerated != 0);
  2274             return 0;
  2275         }
  2276     default:
  2277         SDL_SetError("Unknown OpenGL attribute");
  2278         return -1;
  2279     }
  2280 
  2281     glGetIntegervFunc(attrib, (GLint *) value);
  2282     return 0;
  2283 #else
  2284     SDL_Unsupported();
  2285     return -1;
  2286 #endif /* SDL_VIDEO_OPENGL */
  2287 }
  2288 
  2289 SDL_GLContext
  2290 SDL_GL_CreateContext(SDL_WindowID windowID)
  2291 {
  2292     SDL_Window *window = SDL_GetWindowFromID(windowID);
  2293 
  2294     if (!window) {
  2295         return NULL;
  2296     }
  2297     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2298         SDL_SetError("The specified window isn't an OpenGL window");
  2299         return NULL;
  2300     }
  2301     return _this->GL_CreateContext(_this, window);
  2302 }
  2303 
  2304 int
  2305 SDL_GL_MakeCurrent(SDL_WindowID windowID, SDL_GLContext context)
  2306 {
  2307     SDL_Window *window = SDL_GetWindowFromID(windowID);
  2308 
  2309     if (window && !(window->flags & SDL_WINDOW_OPENGL)) {
  2310         SDL_SetError("The specified window isn't an OpenGL window");
  2311         return -1;
  2312     }
  2313     if (!context) {
  2314         window = NULL;
  2315     }
  2316     return _this->GL_MakeCurrent(_this, window, context);
  2317 }
  2318 
  2319 int
  2320 SDL_GL_SetSwapInterval(int interval)
  2321 {
  2322     if (!_this) {
  2323         SDL_UninitializedVideo();
  2324         return -1;
  2325     }
  2326 
  2327     if (_this->GL_SetSwapInterval) {
  2328         return _this->GL_SetSwapInterval(_this, interval);
  2329     } else {
  2330         SDL_SetError("Setting the swap interval is not supported");
  2331         return -1;
  2332     }
  2333 }
  2334 
  2335 int
  2336 SDL_GL_GetSwapInterval(void)
  2337 {
  2338     if (!_this) {
  2339         SDL_UninitializedVideo();
  2340         return -1;
  2341     }
  2342 
  2343     if (_this->GL_GetSwapInterval) {
  2344         return _this->GL_GetSwapInterval(_this);
  2345     } else {
  2346         SDL_SetError("Getting the swap interval is not supported");
  2347         return -1;
  2348     }
  2349 }
  2350 
  2351 void
  2352 SDL_GL_SwapWindow(SDL_WindowID windowID)
  2353 {
  2354     SDL_Window *window = SDL_GetWindowFromID(windowID);
  2355 
  2356     if (!window) {
  2357         return;
  2358     }
  2359     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2360         SDL_SetError("The specified window isn't an OpenGL window");
  2361         return;
  2362     }
  2363     _this->GL_SwapWindow(_this, window);
  2364 }
  2365 
  2366 void
  2367 SDL_GL_DeleteContext(SDL_GLContext context)
  2368 {
  2369     if (!_this || !context) {
  2370         return;
  2371     }
  2372     _this->GL_MakeCurrent(_this, NULL, NULL);
  2373     _this->GL_DeleteContext(_this, context);
  2374 }
  2375 
  2376 #if 0                           // FIXME
  2377 /* Utility function used by SDL_WM_SetIcon();
  2378  * flags & 1 for color key, flags & 2 for alpha channel. */
  2379 static void
  2380 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2381 {
  2382     int x, y;
  2383     Uint32 colorkey;
  2384 #define SET_MASKBIT(icon, x, y, mask) \
  2385 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2386 
  2387     colorkey = icon->format->colorkey;
  2388     switch (icon->format->BytesPerPixel) {
  2389     case 1:
  2390         {
  2391             Uint8 *pixels;
  2392             for (y = 0; y < icon->h; ++y) {
  2393                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2394                 for (x = 0; x < icon->w; ++x) {
  2395                     if (*pixels++ == colorkey) {
  2396                         SET_MASKBIT(icon, x, y, mask);
  2397                     }
  2398                 }
  2399             }
  2400         }
  2401         break;
  2402 
  2403     case 2:
  2404         {
  2405             Uint16 *pixels;
  2406             for (y = 0; y < icon->h; ++y) {
  2407                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2408                 for (x = 0; x < icon->w; ++x) {
  2409                     if ((flags & 1) && *pixels == colorkey) {
  2410                         SET_MASKBIT(icon, x, y, mask);
  2411                     } else if ((flags & 2)
  2412                                && (*pixels & icon->format->Amask) == 0) {
  2413                         SET_MASKBIT(icon, x, y, mask);
  2414                     }
  2415                     pixels++;
  2416                 }
  2417             }
  2418         }
  2419         break;
  2420 
  2421     case 4:
  2422         {
  2423             Uint32 *pixels;
  2424             for (y = 0; y < icon->h; ++y) {
  2425                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  2426                 for (x = 0; x < icon->w; ++x) {
  2427                     if ((flags & 1) && *pixels == colorkey) {
  2428                         SET_MASKBIT(icon, x, y, mask);
  2429                     } else if ((flags & 2)
  2430                                && (*pixels & icon->format->Amask) == 0) {
  2431                         SET_MASKBIT(icon, x, y, mask);
  2432                     }
  2433                     pixels++;
  2434                 }
  2435             }
  2436         }
  2437         break;
  2438     }
  2439 }
  2440 
  2441 /*
  2442  * Sets the window manager icon for the display window.
  2443  */
  2444 void
  2445 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  2446 {
  2447     if (icon && _this->SetIcon) {
  2448         /* Generate a mask if necessary, and create the icon! */
  2449         if (mask == NULL) {
  2450             int mask_len = icon->h * (icon->w + 7) / 8;
  2451             int flags = 0;
  2452             mask = (Uint8 *) SDL_malloc(mask_len);
  2453             if (mask == NULL) {
  2454                 return;
  2455             }
  2456             SDL_memset(mask, ~0, mask_len);
  2457             if (icon->flags & SDL_SRCCOLORKEY)
  2458                 flags |= 1;
  2459             if (icon->flags & SDL_SRCALPHA)
  2460                 flags |= 2;
  2461             if (flags) {
  2462                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  2463             }
  2464             _this->SetIcon(_this, icon, mask);
  2465             SDL_free(mask);
  2466         } else {
  2467             _this->SetIcon(_this, icon, mask);
  2468         }
  2469     }
  2470 }
  2471 #endif
  2472 
  2473 SDL_bool
  2474 SDL_GetWindowWMInfo(SDL_WindowID windowID, struct SDL_SysWMinfo *info)
  2475 {
  2476     SDL_Window *window = SDL_GetWindowFromID(windowID);
  2477 
  2478     if (!window || !_this->GetWindowWMInfo) {
  2479         return SDL_FALSE;
  2480     }
  2481     return (_this->GetWindowWMInfo(_this, window, info));
  2482 }
  2483 
  2484 /* vi: set ts=4 sw=4 expandtab: */