src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 24 Mar 2009 10:43:53 +0000
changeset 3100 7dc982143c06
parent 3099 82e60908fab1
child 3130 fef1a835af43
child 3139 7f684f249ec9
permissions -rw-r--r--
Date: Sun, 22 Mar 2009 12:52:29 +0000
From: Luke Benstead
Subject: OpenGL 3.0 Context Creation

I've attached a patch which implements OpenGL 3.x context creation on
the latest SVN. I've added two options to SDL_GL_SetAttribute, these
are SDL_GL_CONTEXT_MAJOR_VERSION and SDL_GL_CONTEXT_MINOR_VERSION.
These default to 2 and 1 respectively. If the major version is less
than 3 then the current context creation method is used, otherwise the
appropriate new context creation function is called (depending on the
platform).

Sample code:

if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("Unable to initialize SDL: %s\n", SDL_GetError());
return 1;
}

SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); //Without these 2 lines, SDL will create a GL 2.x context
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

SDL_Surface* screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL | SDL_FULLSCREEN );


I've implemented context creation on both Win32 and X and run basic
tests on both. This patch doesn't provide access to all the options
allowed by the new context creation (e.g. shared contexts, forward
compatible contexts) but they can be added pretty easily.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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_video.h"
    28 #include "SDL_sysvideo.h"
    29 #include "SDL_blit.h"
    30 #include "SDL_pixels_c.h"
    31 #include "SDL_renderer_gl.h"
    32 #include "SDL_renderer_gles.h"
    33 #include "SDL_renderer_sw.h"
    34 #include "../events/SDL_sysevents.h"
    35 #include "../events/SDL_events_c.h"
    36 
    37 #if SDL_VIDEO_OPENGL_ES
    38 #include "SDL_opengles.h"
    39 #endif /* SDL_VIDEO_OPENGL_ES */
    40 
    41 #if SDL_VIDEO_OPENGL
    42 #include "SDL_opengl.h"
    43 
    44 /* On Windows, windows.h defines CreateWindow */
    45 #ifdef CreateWindow
    46 #undef CreateWindow
    47 #endif
    48 #endif /* SDL_VIDEO_OPENGL */
    49 
    50 /* Available video drivers */
    51 static VideoBootStrap *bootstrap[] = {
    52 #if SDL_VIDEO_DRIVER_COCOA
    53     &COCOA_bootstrap,
    54 #endif
    55 #if SDL_VIDEO_DRIVER_X11
    56     &X11_bootstrap,
    57 #endif
    58 #if SDL_VIDEO_DRIVER_NANOX
    59     &NX_bootstrap,
    60 #endif
    61 #if SDL_VIDEO_DRIVER_IPOD
    62     &iPod_bootstrap,
    63 #endif
    64 #if SDL_VIDEO_DRIVER_WSCONS
    65     &WSCONS_bootstrap,
    66 #endif
    67 #if SDL_VIDEO_DRIVER_FBCON
    68     &FBCON_bootstrap,
    69 #endif
    70 #if SDL_VIDEO_DRIVER_DIRECTFB
    71     &DirectFB_bootstrap,
    72 #endif
    73 #if SDL_VIDEO_DRIVER_PS2GS
    74     &PS2GS_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_PHOTON
    92     &photon_bootstrap,
    93 #endif
    94 #if SDL_VIDEO_DRIVER_QNXGF
    95     &qnxgf_bootstrap,
    96 #endif
    97 #if SDL_VIDEO_DRIVER_EPOC
    98     &EPOC_bootstrap,
    99 #endif
   100 #if SDL_VIDEO_DRIVER_XBIOS
   101     &XBIOS_bootstrap,
   102 #endif
   103 #if SDL_VIDEO_DRIVER_GEM
   104     &GEM_bootstrap,
   105 #endif
   106 #if SDL_VIDEO_DRIVER_DC
   107     &DC_bootstrap,
   108 #endif
   109 #if SDL_VIDEO_DRIVER_RISCOS
   110     &RISCOS_bootstrap,
   111 #endif
   112 #if SDL_VIDEO_DRIVER_OS2FS
   113     &OS2FSLib_bootstrap,
   114 #endif
   115 #if SDL_VIDEO_DRIVER_NDS
   116     &NDS_bootstrap,
   117 #endif
   118 #if SDL_VIDEO_DRIVER_UIKIT
   119     &UIKIT_bootstrap,
   120 #endif
   121 #if SDL_VIDEO_DRIVER_DUMMY
   122     &DUMMY_bootstrap,
   123 #endif
   124     NULL
   125 };
   126 
   127 static SDL_VideoDevice *_this = NULL;
   128 
   129 /* Various local functions */
   130 static void SDL_UpdateWindowGrab(SDL_Window * window);
   131 
   132 static int
   133 cmpmodes(const void *A, const void *B)
   134 {
   135     SDL_DisplayMode a = *(const SDL_DisplayMode *) A;
   136     SDL_DisplayMode b = *(const SDL_DisplayMode *) B;
   137 
   138     if (a.w != b.w) {
   139         return b.w - a.w;
   140     }
   141     if (a.h != b.h) {
   142         return b.h - a.h;
   143     }
   144     if (SDL_BITSPERPIXEL(a.format) != SDL_BITSPERPIXEL(b.format)) {
   145         return SDL_BITSPERPIXEL(b.format) - SDL_BITSPERPIXEL(a.format);
   146     }
   147     if (a.refresh_rate != b.refresh_rate) {
   148         return b.refresh_rate - a.refresh_rate;
   149     }
   150     return 0;
   151 }
   152 
   153 static void
   154 SDL_UninitializedVideo()
   155 {
   156     SDL_SetError("Video subsystem has not been initialized");
   157 }
   158 
   159 int
   160 SDL_GetNumVideoDrivers(void)
   161 {
   162     return SDL_arraysize(bootstrap) - 1;
   163 }
   164 
   165 const char *
   166 SDL_GetVideoDriver(int index)
   167 {
   168     if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
   169         return bootstrap[index]->name;
   170     }
   171     return NULL;
   172 }
   173 
   174 /*
   175  * Initialize the video and event subsystems -- determine native pixel format
   176  */
   177 int
   178 SDL_VideoInit(const char *driver_name, Uint32 flags)
   179 {
   180     SDL_VideoDevice *video;
   181     int index;
   182     int i;
   183 
   184     /* Toggle the event thread flags, based on OS requirements */
   185 #if defined(MUST_THREAD_EVENTS)
   186     flags |= SDL_INIT_EVENTTHREAD;
   187 #elif defined(CANT_THREAD_EVENTS)
   188     if ((flags & SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD) {
   189         SDL_SetError("OS doesn't support threaded events");
   190         return -1;
   191     }
   192 #endif
   193 
   194     /* Start the event loop */
   195     if (SDL_StartEventLoop(flags) < 0) {
   196         return -1;
   197     }
   198     /* Check to make sure we don't overwrite '_this' */
   199     if (_this != NULL) {
   200         SDL_VideoQuit();
   201     }
   202     /* Select the proper video driver */
   203     index = 0;
   204     video = NULL;
   205     if (driver_name == NULL) {
   206         driver_name = SDL_getenv("SDL_VIDEODRIVER");
   207     }
   208     if (driver_name != NULL) {
   209         for (i = 0; bootstrap[i]; ++i) {
   210             if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) {
   211                 if (bootstrap[i]->available()) {
   212                     video = bootstrap[i]->create(index);
   213                 }
   214                 break;
   215             }
   216         }
   217     } else {
   218         for (i = 0; bootstrap[i]; ++i) {
   219             if (bootstrap[i]->available()) {
   220                 video = bootstrap[i]->create(index);
   221                 if (video != NULL) {
   222                     break;
   223                 }
   224             }
   225         }
   226     }
   227     if (video == NULL) {
   228         if (driver_name) {
   229             SDL_SetError("%s not available", driver_name);
   230         } else {
   231             SDL_SetError("No available video device");
   232         }
   233         return -1;
   234     }
   235     _this = video;
   236     _this->name = bootstrap[i]->name;
   237     _this->next_object_id = 1;
   238 
   239 
   240     /* Set some very sane GL defaults */
   241     _this->gl_config.driver_loaded = 0;
   242     _this->gl_config.dll_handle = NULL;
   243     _this->gl_config.red_size = 3;
   244     _this->gl_config.green_size = 3;
   245     _this->gl_config.blue_size = 2;
   246     _this->gl_config.alpha_size = 0;
   247     _this->gl_config.buffer_size = 0;
   248     _this->gl_config.depth_size = 16;
   249     _this->gl_config.stencil_size = 0;
   250     _this->gl_config.double_buffer = 1;
   251     _this->gl_config.accum_red_size = 0;
   252     _this->gl_config.accum_green_size = 0;
   253     _this->gl_config.accum_blue_size = 0;
   254     _this->gl_config.accum_alpha_size = 0;
   255     _this->gl_config.stereo = 0;
   256     _this->gl_config.multisamplebuffers = 0;
   257     _this->gl_config.multisamplesamples = 0;
   258     _this->gl_config.retained_backing = 1;
   259     _this->gl_config.accelerated = -1;  /* not known, don't set */
   260     _this->gl_config.major_version = 2;
   261     _this->gl_config.minor_version = 1;
   262 
   263     /* Initialize the video subsystem */
   264     if (_this->VideoInit(_this) < 0) {
   265         SDL_VideoQuit();
   266         return -1;
   267     }
   268     /* Make sure some displays were added */
   269     if (_this->num_displays == 0) {
   270         SDL_SetError("The video driver did not add any displays");
   271         SDL_VideoQuit();
   272         return (-1);
   273     }
   274     /* The software renderer is always available */
   275     for (i = 0; i < _this->num_displays; ++i) {
   276 #if SDL_VIDEO_RENDER_OGL
   277         SDL_AddRenderDriver(i, &GL_RenderDriver);
   278 #endif
   279 
   280 #if SDL_VIDEO_RENDER_OGL_ES
   281         SDL_AddRenderDriver(i, &GL_ES_RenderDriver);
   282 #endif
   283         if (_this->displays[i].num_render_drivers > 0) {
   284             SDL_AddRenderDriver(i, &SW_RenderDriver);
   285         }
   286     }
   287 
   288     /* We're ready to go! */
   289     return 0;
   290 }
   291 
   292 const char *
   293 SDL_GetCurrentVideoDriver()
   294 {
   295     if (!_this) {
   296         SDL_UninitializedVideo();
   297         return NULL;
   298     }
   299     return _this->name;
   300 }
   301 
   302 SDL_VideoDevice *
   303 SDL_GetVideoDevice()
   304 {
   305     return _this;
   306 }
   307 
   308 int
   309 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
   310 {
   311     SDL_VideoDisplay display;
   312 
   313     SDL_zero(display);
   314     if (desktop_mode) {
   315         display.desktop_mode = *desktop_mode;
   316     }
   317     display.current_mode = display.desktop_mode;
   318 
   319     return SDL_AddVideoDisplay(&display);
   320 }
   321 
   322 int
   323 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
   324 {
   325     SDL_VideoDisplay *displays;
   326     int index = -1;
   327 
   328     displays =
   329         SDL_realloc(_this->displays,
   330                     (_this->num_displays + 1) * sizeof(*displays));
   331     if (displays) {
   332         index = _this->num_displays++;
   333         displays[index] = *display;
   334         displays[index].device = _this;
   335         _this->displays = displays;
   336     } else {
   337         SDL_OutOfMemory();
   338     }
   339     return index;
   340 }
   341 
   342 int
   343 SDL_GetNumVideoDisplays(void)
   344 {
   345     if (!_this) {
   346         SDL_UninitializedVideo();
   347         return 0;
   348     }
   349     return _this->num_displays;
   350 }
   351 
   352 int
   353 SDL_SelectVideoDisplay(int index)
   354 {
   355     if (!_this) {
   356         SDL_UninitializedVideo();
   357         return (-1);
   358     }
   359     if (index < 0 || index >= _this->num_displays) {
   360         SDL_SetError("index must be in the range 0 - %d",
   361                      _this->num_displays - 1);
   362         return -1;
   363     }
   364     _this->current_display = index;
   365     return 0;
   366 }
   367 
   368 int
   369 SDL_GetCurrentVideoDisplay(void)
   370 {
   371     if (!_this) {
   372         SDL_UninitializedVideo();
   373         return (-1);
   374     }
   375     return _this->current_display;
   376 }
   377 
   378 SDL_bool
   379 SDL_AddDisplayMode(int displayIndex, const SDL_DisplayMode * mode)
   380 {
   381     SDL_VideoDisplay *display = &_this->displays[displayIndex];
   382     SDL_DisplayMode *modes;
   383     int i, nmodes;
   384 
   385     /* Make sure we don't already have the mode in the list */
   386     modes = display->display_modes;
   387     nmodes = display->num_display_modes;
   388     for (i = nmodes; i--;) {
   389         if (SDL_memcmp(mode, &modes[i], sizeof(*mode)) == 0) {
   390             return SDL_FALSE;
   391         }
   392     }
   393 
   394     /* Go ahead and add the new mode */
   395     if (nmodes == display->max_display_modes) {
   396         modes =
   397             SDL_realloc(modes,
   398                         (display->max_display_modes + 32) * sizeof(*modes));
   399         if (!modes) {
   400             return SDL_FALSE;
   401         }
   402         display->display_modes = modes;
   403         display->max_display_modes += 32;
   404     }
   405     modes[nmodes] = *mode;
   406     display->num_display_modes++;
   407 
   408     return SDL_TRUE;
   409 }
   410 
   411 int
   412 SDL_GetNumDisplayModes()
   413 {
   414     if (_this) {
   415         SDL_VideoDisplay *display = &SDL_CurrentDisplay;
   416         if (!display->num_display_modes && _this->GetDisplayModes) {
   417             _this->GetDisplayModes(_this);
   418             SDL_qsort(display->display_modes, display->num_display_modes,
   419                       sizeof(SDL_DisplayMode), cmpmodes);
   420         }
   421         return display->num_display_modes;
   422     }
   423     return 0;
   424 }
   425 
   426 int
   427 SDL_GetDisplayMode(int index, SDL_DisplayMode * mode)
   428 {
   429     if (index < 0 || index >= SDL_GetNumDisplayModes()) {
   430         SDL_SetError("index must be in the range of 0 - %d",
   431                      SDL_GetNumDisplayModes() - 1);
   432         return -1;
   433     }
   434     if (mode) {
   435         *mode = SDL_CurrentDisplay.display_modes[index];
   436     }
   437     return 0;
   438 }
   439 
   440 int
   441 SDL_GetDesktopDisplayMode(SDL_DisplayMode * mode)
   442 {
   443     if (!_this) {
   444         SDL_UninitializedVideo();
   445         return -1;
   446     }
   447     if (mode) {
   448         *mode = SDL_CurrentDisplay.desktop_mode;
   449     }
   450     return 0;
   451 }
   452 
   453 int
   454 SDL_GetCurrentDisplayMode(SDL_DisplayMode * mode)
   455 {
   456     if (!_this) {
   457         SDL_UninitializedVideo();
   458         return -1;
   459     }
   460     if (mode) {
   461         *mode = SDL_CurrentDisplay.current_mode;
   462     }
   463     return 0;
   464 }
   465 
   466 SDL_DisplayMode *
   467 SDL_GetClosestDisplayMode(const SDL_DisplayMode * mode,
   468                           SDL_DisplayMode * closest)
   469 {
   470     Uint32 target_format;
   471     int target_refresh_rate;
   472     int i;
   473     SDL_DisplayMode *current, *match;
   474 
   475     if (!_this || !mode || !closest) {
   476         return NULL;
   477     }
   478     /* Default to the desktop format */
   479     if (mode->format) {
   480         target_format = mode->format;
   481     } else {
   482         target_format = SDL_CurrentDisplay.desktop_mode.format;
   483     }
   484 
   485     /* Default to the desktop refresh rate */
   486     if (mode->refresh_rate) {
   487         target_refresh_rate = mode->refresh_rate;
   488     } else {
   489         target_refresh_rate = SDL_CurrentDisplay.desktop_mode.refresh_rate;
   490     }
   491 
   492     match = NULL;
   493     for (i = 0; i < SDL_GetNumDisplayModes(); ++i) {
   494         current = &SDL_CurrentDisplay.display_modes[i];
   495 
   496         if (current->w && (current->w < mode->w)) {
   497             /* Out of sorted modes large enough here */
   498             break;
   499         }
   500         if (current->h && (current->h < mode->h)) {
   501             if (current->w && (current->w == mode->w)) {
   502                 /* Out of sorted modes large enough here */
   503                 break;
   504             }
   505             /* Wider, but not tall enough, due to a different
   506                aspect ratio. This mode must be skipped, but closer
   507                modes may still follow. */
   508             continue;
   509         }
   510         if (!match || current->w < match->w || current->h < match->h) {
   511             match = current;
   512             continue;
   513         }
   514         if (current->format != match->format) {
   515             /* Sorted highest depth to lowest */
   516             if (current->format == target_format ||
   517                 (SDL_BITSPERPIXEL(current->format) >=
   518                  SDL_BITSPERPIXEL(target_format)
   519                  && SDL_PIXELTYPE(current->format) ==
   520                  SDL_PIXELTYPE(target_format))) {
   521                 match = current;
   522             }
   523             continue;
   524         }
   525         if (current->refresh_rate != match->refresh_rate) {
   526             /* Sorted highest refresh to lowest */
   527             if (current->refresh_rate >= target_refresh_rate) {
   528                 match = current;
   529             }
   530         }
   531     }
   532     if (match) {
   533         if (match->format) {
   534             closest->format = match->format;
   535         } else {
   536             closest->format = mode->format;
   537         }
   538         if (match->w && match->h) {
   539             closest->w = match->w;
   540             closest->h = match->h;
   541         } else {
   542             closest->w = mode->w;
   543             closest->h = mode->h;
   544         }
   545         if (match->refresh_rate) {
   546             closest->refresh_rate = match->refresh_rate;
   547         } else {
   548             closest->refresh_rate = mode->refresh_rate;
   549         }
   550         closest->driverdata = match->driverdata;
   551 
   552         /*
   553          * Pick some reasonable defaults if the app and driver don't
   554          * care
   555          */
   556         if (!closest->format) {
   557             closest->format = SDL_PIXELFORMAT_RGB888;
   558         }
   559         if (!closest->w) {
   560             closest->w = 640;
   561         }
   562         if (!closest->h) {
   563             closest->h = 480;
   564         }
   565         return closest;
   566     }
   567     return NULL;
   568 }
   569 
   570 int
   571 SDL_SetDisplayMode(const SDL_DisplayMode * mode)
   572 {
   573     SDL_VideoDisplay *display;
   574     SDL_DisplayMode display_mode;
   575     SDL_DisplayMode current_mode;
   576     int i, ncolors;
   577 
   578     if (!_this) {
   579         SDL_UninitializedVideo();
   580         return -1;
   581     }
   582     display = &SDL_CurrentDisplay;
   583     if (!mode) {
   584         mode = &display->desktop_mode;
   585     }
   586     display_mode = *mode;
   587 
   588     /* Default to the current mode */
   589     if (!display_mode.format) {
   590         display_mode.format = display->current_mode.format;
   591     }
   592     if (!display_mode.w) {
   593         display_mode.w = display->current_mode.w;
   594     }
   595     if (!display_mode.h) {
   596         display_mode.h = display->current_mode.h;
   597     }
   598     if (!display_mode.refresh_rate) {
   599         display_mode.refresh_rate = display->current_mode.refresh_rate;
   600     }
   601     /* Get a good video mode, the closest one possible */
   602     if (!SDL_GetClosestDisplayMode(&display_mode, &display_mode)) {
   603         SDL_SetError("No video mode large enough for %dx%d",
   604                      display_mode.w, display_mode.h);
   605         return -1;
   606     }
   607     /* See if there's anything left to do */
   608     SDL_GetCurrentDisplayMode(&current_mode);
   609     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
   610         return 0;
   611     }
   612     /* Actually change the display mode */
   613     if (_this->SetDisplayMode(_this, &display_mode) < 0) {
   614         return -1;
   615     }
   616     display->current_mode = display_mode;
   617 
   618     /* Set up a palette, if necessary */
   619     if (SDL_ISPIXELFORMAT_INDEXED(display_mode.format)) {
   620         ncolors = (1 << SDL_BITSPERPIXEL(display_mode.format));
   621     } else {
   622         ncolors = 0;
   623     }
   624     if ((!ncolors && display->palette) || (ncolors && !display->palette)
   625         || (ncolors && ncolors != display->palette->ncolors)) {
   626         if (display->palette) {
   627             SDL_FreePalette(display->palette);
   628             display->palette = NULL;
   629         }
   630         if (ncolors) {
   631             display->palette = SDL_AllocPalette(ncolors);
   632             if (!display->palette) {
   633                 return -1;
   634             }
   635             SDL_DitherColors(display->palette->colors,
   636                              SDL_BITSPERPIXEL(display_mode.format));
   637         }
   638     }
   639     /* Move any fullscreen windows into position */
   640     for (i = 0; i < display->num_windows; ++i) {
   641         SDL_Window *window = &display->windows[i];
   642         if (FULLSCREEN_VISIBLE(window)) {
   643             SDL_SetWindowPosition(window->id, window->x, window->y);
   644         }
   645     }
   646 
   647     return 0;
   648 }
   649 
   650 int
   651 SDL_SetFullscreenDisplayMode(const SDL_DisplayMode * mode)
   652 {
   653     SDL_VideoDisplay *display;
   654     SDL_DisplayMode fullscreen_mode;
   655     int i;
   656 
   657     if (!_this) {
   658         SDL_UninitializedVideo();
   659         return -1;
   660     }
   661     display = &SDL_CurrentDisplay;
   662     if (!mode) {
   663         mode = &display->desktop_mode;
   664     }
   665     if (!SDL_GetClosestDisplayMode(mode, &fullscreen_mode)) {
   666         SDL_SetError("Couldn't find display mode match");
   667         return -1;
   668     }
   669 
   670     if (SDL_memcmp
   671         (&fullscreen_mode, &display->fullscreen_mode,
   672          sizeof(fullscreen_mode)) == 0) {
   673         /* Nothing to do... */
   674         return 0;
   675     }
   676     display->fullscreen_mode = fullscreen_mode;
   677 
   678     /* Actually set the mode if we have a fullscreen window visible */
   679     for (i = 0; i < display->num_windows; ++i) {
   680         SDL_Window *window = &display->windows[i];
   681         if (FULLSCREEN_VISIBLE(window)) {
   682             if (SDL_SetDisplayMode(&display->fullscreen_mode) < 0) {
   683                 return -1;
   684             }
   685         }
   686         if (window->flags & SDL_WINDOW_FULLSCREEN) {
   687             SDL_OnWindowResized(window);
   688         }
   689     }
   690     return 0;
   691 }
   692 
   693 int
   694 SDL_GetFullscreenDisplayMode(SDL_DisplayMode * mode)
   695 {
   696     if (!_this) {
   697         SDL_UninitializedVideo();
   698         return -1;
   699     }
   700     if (mode) {
   701         *mode = SDL_CurrentDisplay.fullscreen_mode;
   702     }
   703     return 0;
   704 }
   705 
   706 int
   707 SDL_SetDisplayPalette(const SDL_Color * colors, int firstcolor, int ncolors)
   708 {
   709     SDL_Palette *palette;
   710     int status = 0;
   711 
   712     if (!_this) {
   713         SDL_UninitializedVideo();
   714         return -1;
   715     }
   716     palette = SDL_CurrentDisplay.palette;
   717     if (!palette) {
   718         SDL_SetError("Display mode does not have a palette");
   719         return -1;
   720     }
   721     status = SDL_SetPaletteColors(palette, colors, firstcolor, ncolors);
   722 
   723     if (_this->SetDisplayPalette) {
   724         if (_this->SetDisplayPalette(_this, palette) < 0) {
   725             status = -1;
   726         }
   727     }
   728     return status;
   729 }
   730 
   731 int
   732 SDL_GetDisplayPalette(SDL_Color * colors, int firstcolor, int ncolors)
   733 {
   734     SDL_Palette *palette;
   735 
   736     if (!_this) {
   737         SDL_UninitializedVideo();
   738         return -1;
   739     }
   740     palette = SDL_CurrentDisplay.palette;
   741     if (!palette->ncolors) {
   742         SDL_SetError("Display mode does not have a palette");
   743         return -1;
   744     }
   745     if (firstcolor < 0 || (firstcolor + ncolors) > palette->ncolors) {
   746         SDL_SetError("Palette indices are out of range");
   747         return -1;
   748     }
   749     SDL_memcpy(colors, &palette->colors[firstcolor],
   750                ncolors * sizeof(*colors));
   751     return 0;
   752 }
   753 
   754 SDL_WindowID
   755 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
   756 {
   757     const Uint32 allowed_flags = (SDL_WINDOW_FULLSCREEN |
   758                                   SDL_WINDOW_OPENGL |
   759                                   SDL_WINDOW_BORDERLESS |
   760                                   SDL_WINDOW_RESIZABLE |
   761                                   SDL_WINDOW_INPUT_GRABBED);
   762     SDL_VideoDisplay *display;
   763     SDL_Window window;
   764     int num_windows;
   765     SDL_Window *windows;
   766 
   767     if (!_this) {
   768         SDL_UninitializedVideo();
   769         return 0;
   770     }
   771     if (flags & SDL_WINDOW_OPENGL) {
   772         if (!_this->GL_CreateContext) {
   773             SDL_SetError("No OpenGL support in video driver");
   774             return 0;
   775         }
   776         SDL_GL_LoadLibrary(NULL);
   777     }
   778     SDL_zero(window);
   779     window.id = _this->next_object_id++;
   780     window.x = x;
   781     window.y = y;
   782     window.w = w;
   783     window.h = h;
   784     window.flags = (flags & allowed_flags);
   785     window.display = _this->current_display;
   786 
   787     if (_this->CreateWindow && _this->CreateWindow(_this, &window) < 0) {
   788         if (flags & SDL_WINDOW_OPENGL) {
   789             SDL_GL_UnloadLibrary();
   790         }
   791         return 0;
   792     }
   793     display = &SDL_CurrentDisplay;
   794     num_windows = display->num_windows;
   795     windows =
   796         SDL_realloc(display->windows, (num_windows + 1) * sizeof(*windows));
   797     if (!windows) {
   798         if (_this->DestroyWindow) {
   799             _this->DestroyWindow(_this, &window);
   800         }
   801         if (flags & SDL_WINDOW_OPENGL) {
   802             SDL_GL_UnloadLibrary();
   803         }
   804         return 0;
   805     }
   806     windows[num_windows] = window;
   807     display->windows = windows;
   808     display->num_windows++;
   809 
   810     if (title) {
   811         SDL_SetWindowTitle(window.id, title);
   812     }
   813     if (flags & SDL_WINDOW_MAXIMIZED) {
   814         SDL_MaximizeWindow(window.id);
   815     }
   816     if (flags & SDL_WINDOW_MINIMIZED) {
   817         SDL_MinimizeWindow(window.id);
   818     }
   819     if (flags & SDL_WINDOW_SHOWN) {
   820         SDL_ShowWindow(window.id);
   821     }
   822     SDL_UpdateWindowGrab(&window);
   823 
   824     return window.id;
   825 }
   826 
   827 SDL_WindowID
   828 SDL_CreateWindowFrom(const void *data)
   829 {
   830     SDL_VideoDisplay *display;
   831     SDL_Window window;
   832     int num_windows;
   833     SDL_Window *windows;
   834 
   835     if (!_this) {
   836         SDL_UninitializedVideo();
   837         return (0);
   838     }
   839     SDL_zero(window);
   840     window.id = _this->next_object_id++;
   841     window.display = _this->current_display;
   842     window.flags = SDL_WINDOW_FOREIGN;
   843 
   844     if (!_this->CreateWindowFrom ||
   845         _this->CreateWindowFrom(_this, &window, data) < 0) {
   846         return 0;
   847     }
   848     display = &SDL_CurrentDisplay;
   849     num_windows = display->num_windows;
   850     windows =
   851         SDL_realloc(display->windows, (num_windows + 1) * sizeof(*windows));
   852     if (!windows) {
   853         if (_this->DestroyWindow) {
   854             _this->DestroyWindow(_this, &window);
   855         }
   856         if (window.title) {
   857             SDL_free(window.title);
   858         }
   859         return 0;
   860     }
   861     windows[num_windows] = window;
   862     display->windows = windows;
   863     display->num_windows++;
   864 
   865     return window.id;
   866 }
   867 
   868 int
   869 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
   870 {
   871     const Uint32 allowed_flags = (SDL_WINDOW_FULLSCREEN |
   872                                   SDL_WINDOW_OPENGL |
   873                                   SDL_WINDOW_BORDERLESS |
   874                                   SDL_WINDOW_RESIZABLE |
   875                                   SDL_WINDOW_INPUT_GRABBED);
   876     char *title = window->title;
   877 
   878     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
   879         SDL_SetError("No OpenGL support in video driver");
   880         return -1;
   881     }
   882     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
   883         if (flags & SDL_WINDOW_OPENGL) {
   884             SDL_GL_LoadLibrary(NULL);
   885         } else {
   886             SDL_GL_UnloadLibrary();
   887         }
   888     }
   889 
   890     if (window->flags & SDL_WINDOW_FOREIGN) {
   891         /* Can't destroy and re-create foreign windows, hrm */
   892         flags |= SDL_WINDOW_FOREIGN;
   893     } else {
   894         flags &= ~SDL_WINDOW_FOREIGN;
   895     }
   896 
   897     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
   898         _this->DestroyWindow(_this, window);
   899     }
   900 
   901     window->title = NULL;
   902     window->flags = (flags & allowed_flags);
   903 
   904     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
   905         if (_this->CreateWindow(_this, window) < 0) {
   906             if (flags & SDL_WINDOW_OPENGL) {
   907                 SDL_GL_UnloadLibrary();
   908             }
   909             return -1;
   910         }
   911     }
   912 
   913     if (title) {
   914         SDL_SetWindowTitle(window->id, title);
   915         SDL_free(title);
   916     }
   917     if (flags & SDL_WINDOW_MAXIMIZED) {
   918         SDL_MaximizeWindow(window->id);
   919     }
   920     if (flags & SDL_WINDOW_MINIMIZED) {
   921         SDL_MinimizeWindow(window->id);
   922     }
   923     if (flags & SDL_WINDOW_SHOWN) {
   924         SDL_ShowWindow(window->id);
   925     }
   926     SDL_UpdateWindowGrab(window);
   927 
   928     return 0;
   929 }
   930 
   931 SDL_Window *
   932 SDL_GetWindowFromID(SDL_WindowID windowID)
   933 {
   934     int i, j;
   935 
   936     if (!_this) {
   937         SDL_UninitializedVideo();
   938         return NULL;
   939     }
   940     for (i = 0; i < _this->num_displays; ++i) {
   941         SDL_VideoDisplay *display = &_this->displays[i];
   942         for (j = 0; j < display->num_windows; ++j) {
   943             SDL_Window *window = &display->windows[j];
   944             if (window->id == windowID) {
   945                 return window;
   946             }
   947         }
   948     }
   949     return NULL;
   950 }
   951 
   952 SDL_VideoDisplay *
   953 SDL_GetDisplayFromWindow(SDL_Window * window)
   954 {
   955     if (!_this) {
   956         SDL_UninitializedVideo();
   957         return NULL;
   958     }
   959     if (!window) {
   960         return NULL;
   961     }
   962     return &_this->displays[window->display];
   963 }
   964 
   965 Uint32
   966 SDL_GetWindowFlags(SDL_WindowID windowID)
   967 {
   968     SDL_Window *window = SDL_GetWindowFromID(windowID);
   969 
   970     if (!window) {
   971         return 0;
   972     }
   973     return window->flags;
   974 }
   975 
   976 void
   977 SDL_SetWindowTitle(SDL_WindowID windowID, const char *title)
   978 {
   979     SDL_Window *window = SDL_GetWindowFromID(windowID);
   980 
   981     if (!window || title == window->title) {
   982         return;
   983     }
   984     if (window->title) {
   985         SDL_free(window->title);
   986     }
   987     if (title) {
   988         window->title = SDL_strdup(title);
   989     } else {
   990         window->title = NULL;
   991     }
   992 
   993     if (_this->SetWindowTitle) {
   994         _this->SetWindowTitle(_this, window);
   995     }
   996 }
   997 
   998 const char *
   999 SDL_GetWindowTitle(SDL_WindowID windowID)
  1000 {
  1001     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1002 
  1003     if (!window) {
  1004         return NULL;
  1005     }
  1006     return window->title;
  1007 }
  1008 
  1009 void
  1010 SDL_SetWindowIcon(SDL_WindowID windowID, SDL_Surface * icon)
  1011 {
  1012     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1013 
  1014     if (!window) {
  1015         return;
  1016     }
  1017     if (_this->SetWindowIcon) {
  1018         _this->SetWindowIcon(_this, window, icon);
  1019     }
  1020 }
  1021 
  1022 void
  1023 SDL_SetWindowData(SDL_WindowID windowID, void *userdata)
  1024 {
  1025     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1026 
  1027     if (!window) {
  1028         return;
  1029     }
  1030     window->userdata = userdata;
  1031 }
  1032 
  1033 void *
  1034 SDL_GetWindowData(SDL_WindowID windowID)
  1035 {
  1036     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1037 
  1038     if (!window) {
  1039         return NULL;
  1040     }
  1041     return window->userdata;
  1042 }
  1043 
  1044 void
  1045 SDL_SetWindowPosition(SDL_WindowID windowID, int x, int y)
  1046 {
  1047     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1048     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
  1049 
  1050     if (!window) {
  1051         return;
  1052     }
  1053     if (x != SDL_WINDOWPOS_UNDEFINED) {
  1054         window->x = x;
  1055     }
  1056     if (y != SDL_WINDOWPOS_UNDEFINED) {
  1057         window->y = y;
  1058     }
  1059     if (_this->SetWindowPosition) {
  1060         _this->SetWindowPosition(_this, window);
  1061     }
  1062     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MOVED, x, y);
  1063 }
  1064 
  1065 void
  1066 SDL_GetWindowPosition(SDL_WindowID windowID, int *x, int *y)
  1067 {
  1068     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1069 
  1070     if (!window) {
  1071         return;
  1072     }
  1073     if (x) {
  1074         *x = window->x;
  1075     }
  1076     if (y) {
  1077         *y = window->y;
  1078     }
  1079 }
  1080 
  1081 void
  1082 SDL_SetWindowSize(SDL_WindowID windowID, int w, int h)
  1083 {
  1084     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1085 
  1086     if (!window) {
  1087         return;
  1088     }
  1089     window->w = w;
  1090     window->h = h;
  1091 
  1092     if (_this->SetWindowSize) {
  1093         _this->SetWindowSize(_this, window);
  1094     }
  1095     SDL_OnWindowResized(window);
  1096 }
  1097 
  1098 void
  1099 SDL_GetWindowSize(SDL_WindowID windowID, int *w, int *h)
  1100 {
  1101     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1102 
  1103     if (window) {
  1104         if (w) {
  1105             *w = window->w;
  1106         }
  1107         if (h) {
  1108             *h = window->h;
  1109         }
  1110     } else {
  1111         if (w) {
  1112             *w = 0;
  1113         }
  1114         if (h) {
  1115             *h = 0;
  1116         }
  1117     }
  1118 }
  1119 
  1120 void
  1121 SDL_ShowWindow(SDL_WindowID windowID)
  1122 {
  1123     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1124 
  1125     if (!window || (window->flags & SDL_WINDOW_SHOWN)) {
  1126         return;
  1127     }
  1128 
  1129     if (_this->ShowWindow) {
  1130         _this->ShowWindow(_this, window);
  1131     }
  1132     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1133 }
  1134 
  1135 void
  1136 SDL_HideWindow(SDL_WindowID windowID)
  1137 {
  1138     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1139 
  1140     if (!window || !(window->flags & SDL_WINDOW_SHOWN)) {
  1141         return;
  1142     }
  1143 
  1144     if (_this->HideWindow) {
  1145         _this->HideWindow(_this, window);
  1146     }
  1147     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1148 }
  1149 
  1150 void
  1151 SDL_RaiseWindow(SDL_WindowID windowID)
  1152 {
  1153     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1154 
  1155     if (!window || !(window->flags & SDL_WINDOW_SHOWN)) {
  1156         return;
  1157     }
  1158     if (_this->RaiseWindow) {
  1159         _this->RaiseWindow(_this, window);
  1160     }
  1161 }
  1162 
  1163 void
  1164 SDL_MaximizeWindow(SDL_WindowID windowID)
  1165 {
  1166     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1167 
  1168     if (!window || (window->flags & SDL_WINDOW_MAXIMIZED)) {
  1169         return;
  1170     }
  1171 
  1172     if (_this->MaximizeWindow) {
  1173         _this->MaximizeWindow(_this, window);
  1174     }
  1175     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
  1176 }
  1177 
  1178 void
  1179 SDL_MinimizeWindow(SDL_WindowID windowID)
  1180 {
  1181     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1182 
  1183     if (!window || (window->flags & SDL_WINDOW_MINIMIZED)) {
  1184         return;
  1185     }
  1186 
  1187     if (_this->MinimizeWindow) {
  1188         _this->MinimizeWindow(_this, window);
  1189     }
  1190     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
  1191 }
  1192 
  1193 void
  1194 SDL_RestoreWindow(SDL_WindowID windowID)
  1195 {
  1196     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1197 
  1198     if (!window
  1199         || !(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1200         return;
  1201     }
  1202 
  1203     if (_this->RestoreWindow) {
  1204         _this->RestoreWindow(_this, window);
  1205     }
  1206     SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_RESTORED, 0, 0);
  1207 }
  1208 
  1209 int
  1210 SDL_SetWindowFullscreen(SDL_WindowID windowID, int fullscreen)
  1211 {
  1212     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1213 
  1214     if (!window) {
  1215         return -1;
  1216     }
  1217     if (fullscreen) {
  1218         fullscreen = SDL_WINDOW_FULLSCREEN;
  1219     }
  1220     if ((window->flags & SDL_WINDOW_FULLSCREEN) == fullscreen) {
  1221         return 0;
  1222     }
  1223     if (fullscreen) {
  1224         window->flags |= SDL_WINDOW_FULLSCREEN;
  1225 
  1226         if (FULLSCREEN_VISIBLE(window)) {
  1227             SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
  1228 
  1229             /* Hide any other fullscreen windows */
  1230             int i;
  1231             for (i = 0; i < display->num_windows; ++i) {
  1232                 SDL_Window *other = &display->windows[i];
  1233                 if (other->id != windowID && FULLSCREEN_VISIBLE(other)) {
  1234                     SDL_MinimizeWindow(other->id);
  1235                 }
  1236             }
  1237 
  1238             SDL_SetDisplayMode(&display->fullscreen_mode);
  1239         }
  1240     } else {
  1241         window->flags &= ~SDL_WINDOW_FULLSCREEN;
  1242 
  1243         if (FULLSCREEN_VISIBLE(window)) {
  1244             SDL_SetDisplayMode(NULL);
  1245         }
  1246     }
  1247     return 0;
  1248 }
  1249 
  1250 void
  1251 SDL_SetWindowGrab(SDL_WindowID windowID, int mode)
  1252 {
  1253     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1254 
  1255     if (!window || (!!mode == !!(window->flags & SDL_WINDOW_INPUT_GRABBED))) {
  1256         return;
  1257     }
  1258     if (mode) {
  1259         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1260     } else {
  1261         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  1262     }
  1263     SDL_UpdateWindowGrab(window);
  1264 }
  1265 
  1266 static void
  1267 SDL_UpdateWindowGrab(SDL_Window * window)
  1268 {
  1269     if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) {
  1270         _this->SetWindowGrab(_this, window);
  1271     }
  1272 }
  1273 
  1274 int
  1275 SDL_GetWindowGrab(SDL_WindowID windowID)
  1276 {
  1277     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1278 
  1279     if (!window) {
  1280         return 0;
  1281     }
  1282     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  1283 }
  1284 
  1285 void
  1286 SDL_OnWindowShown(SDL_Window * window)
  1287 {
  1288     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1289         SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
  1290     }
  1291 }
  1292 
  1293 void
  1294 SDL_OnWindowHidden(SDL_Window * window)
  1295 {
  1296     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1297         SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
  1298     }
  1299 }
  1300 
  1301 void
  1302 SDL_OnWindowResized(SDL_Window * window)
  1303 {
  1304     SDL_Renderer *renderer = window->renderer;
  1305 
  1306     if (renderer && renderer->DisplayModeChanged) {
  1307         renderer->DisplayModeChanged(renderer);
  1308     }
  1309 }
  1310 
  1311 void
  1312 SDL_OnWindowFocusGained(SDL_Window * window)
  1313 {
  1314     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
  1315 
  1316     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1317         SDL_SetDisplayMode(&display->fullscreen_mode);
  1318     }
  1319     if (display->gamma && _this->SetDisplayGammaRamp) {
  1320         _this->SetDisplayGammaRamp(_this, display->gamma);
  1321     }
  1322     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
  1323         && _this->SetWindowGrab) {
  1324         _this->SetWindowGrab(_this, window);
  1325     }
  1326 }
  1327 
  1328 void
  1329 SDL_OnWindowFocusLost(SDL_Window * window)
  1330 {
  1331     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
  1332 
  1333     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1334         SDL_MinimizeWindow(window->id);
  1335         SDL_SetDisplayMode(NULL);
  1336     }
  1337     if (display->gamma && _this->SetDisplayGammaRamp) {
  1338         _this->SetDisplayGammaRamp(_this, display->saved_gamma);
  1339     }
  1340     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
  1341         && _this->SetWindowGrab) {
  1342         _this->SetWindowGrab(_this, window);
  1343     }
  1344 }
  1345 
  1346 SDL_WindowID
  1347 SDL_GetFocusWindow(void)
  1348 {
  1349     SDL_VideoDisplay *display;
  1350     int i;
  1351 
  1352     if (!_this) {
  1353         return 0;
  1354     }
  1355     display = &SDL_CurrentDisplay;
  1356     for (i = 0; i < display->num_windows; ++i) {
  1357         SDL_Window *window = &display->windows[i];
  1358 
  1359         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1360             return window->id;
  1361         }
  1362     }
  1363     return 0;
  1364 }
  1365 
  1366 void
  1367 SDL_DestroyWindow(SDL_WindowID windowID)
  1368 {
  1369     int i, j;
  1370 
  1371     if (!_this) {
  1372         return;
  1373     }
  1374     /* Restore video mode, etc. */
  1375     SDL_SendWindowEvent(windowID, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
  1376 
  1377     for (i = 0; i < _this->num_displays; ++i) {
  1378         SDL_VideoDisplay *display = &_this->displays[i];
  1379         for (j = 0; j < display->num_windows; ++j) {
  1380             SDL_Window *window = &display->windows[j];
  1381             if (window->id != windowID) {
  1382                 continue;
  1383             }
  1384             if (window->title) {
  1385                 SDL_free(window->title);
  1386                 window->title = NULL;
  1387             }
  1388             if (window->renderer) {
  1389                 SDL_DestroyRenderer(window->id);
  1390                 window->renderer = NULL;
  1391             }
  1392             if (_this->DestroyWindow) {
  1393                 _this->DestroyWindow(_this, window);
  1394             }
  1395             if (window->flags & SDL_WINDOW_OPENGL) {
  1396                 SDL_GL_UnloadLibrary();
  1397             }
  1398             if (j != display->num_windows - 1) {
  1399                 SDL_memcpy(&display->windows[i],
  1400                            &display->windows[i + 1],
  1401                            (display->num_windows - i - 1) * sizeof(*window));
  1402             }
  1403             --display->num_windows;
  1404             return;
  1405         }
  1406     }
  1407 }
  1408 
  1409 void
  1410 SDL_AddRenderDriver(int displayIndex, const SDL_RenderDriver * driver)
  1411 {
  1412     SDL_VideoDisplay *display;
  1413     SDL_RenderDriver *render_drivers;
  1414 
  1415     if (displayIndex >= _this->num_displays) {
  1416         return;
  1417     }
  1418     display = &_this->displays[displayIndex];
  1419 
  1420     render_drivers =
  1421         SDL_realloc(display->render_drivers,
  1422                     (display->num_render_drivers +
  1423                      1) * sizeof(*render_drivers));
  1424     if (render_drivers) {
  1425         render_drivers[display->num_render_drivers] = *driver;
  1426         display->render_drivers = render_drivers;
  1427         display->num_render_drivers++;
  1428     }
  1429 }
  1430 
  1431 int
  1432 SDL_GetNumRenderDrivers(void)
  1433 {
  1434     if (_this) {
  1435         return SDL_CurrentDisplay.num_render_drivers;
  1436     }
  1437     return 0;
  1438 }
  1439 
  1440 int
  1441 SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info)
  1442 {
  1443     if (!_this) {
  1444         SDL_UninitializedVideo();
  1445         return -1;
  1446     }
  1447     if (index < 0 || index >= SDL_GetNumRenderDrivers()) {
  1448         SDL_SetError("index must be in the range of 0 - %d",
  1449                      SDL_GetNumRenderDrivers() - 1);
  1450         return -1;
  1451     }
  1452     *info = SDL_CurrentDisplay.render_drivers[index].info;
  1453     return 0;
  1454 }
  1455 
  1456 int
  1457 SDL_CreateRenderer(SDL_WindowID windowID, int index, Uint32 flags)
  1458 {
  1459     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1460 
  1461     if (!window) {
  1462         SDL_SetError("Invalid window ID");
  1463         return -1;
  1464     }
  1465     if (index < 0) {
  1466         const char *override = SDL_getenv("SDL_VIDEO_RENDERER");
  1467         int n = SDL_GetNumRenderDrivers();
  1468         for (index = 0; index < n; ++index) {
  1469             SDL_RenderDriver *driver =
  1470                 &SDL_CurrentDisplay.render_drivers[index];
  1471 
  1472             if (override) {
  1473                 if (SDL_strcasecmp(override, driver->info.name) == 0) {
  1474                     break;
  1475                 }
  1476             } else {
  1477                 if ((driver->info.flags & flags) == flags) {
  1478                     break;
  1479                 }
  1480             }
  1481         }
  1482         if (index == n) {
  1483             SDL_SetError("Couldn't find matching render driver");
  1484             return -1;
  1485         }
  1486     }
  1487     if (index >= SDL_GetNumRenderDrivers()) {
  1488         SDL_SetError("index must be -1 or in the range of 0 - %d",
  1489                      SDL_GetNumRenderDrivers() - 1);
  1490         return -1;
  1491     }
  1492     /* Free any existing renderer */
  1493     SDL_DestroyRenderer(windowID);
  1494 
  1495     /* Create a new renderer instance */
  1496     window->renderer = SDL_CurrentDisplay.render_drivers[index]
  1497         .CreateRenderer(window, flags);
  1498 
  1499     if (window->renderer==NULL)
  1500     {
  1501        /* Assuming renderer set its error */
  1502        return -1;
  1503     }
  1504 
  1505     SDL_SelectRenderer(window->id);
  1506 
  1507     return 0;
  1508 }
  1509 
  1510 int
  1511 SDL_SelectRenderer(SDL_WindowID windowID)
  1512 {
  1513     SDL_Window *window = SDL_GetWindowFromID(windowID);
  1514     SDL_Renderer *renderer;
  1515 
  1516     if (!window || !window->renderer) {
  1517         return -1;
  1518     }
  1519     renderer = window->renderer;
  1520     if (renderer && renderer->ActivateRenderer) {
  1521         if (renderer->ActivateRenderer(renderer) < 0) {
  1522             return -1;
  1523         }
  1524     }
  1525     SDL_CurrentDisplay.current_renderer = renderer;
  1526     return 0;
  1527 }
  1528 
  1529 int
  1530 SDL_GetRendererInfo(SDL_RendererInfo * info)
  1531 {
  1532     if (!_this) {
  1533         SDL_UninitializedVideo();
  1534         return -1;
  1535     }
  1536     if (!SDL_CurrentDisplay.current_renderer) {
  1537         SDL_SetError("There is no current renderer");
  1538         return -1;
  1539     }
  1540     *info = SDL_CurrentDisplay.current_renderer->info;
  1541     return 0;
  1542 }
  1543 
  1544 SDL_TextureID
  1545 SDL_CreateTexture(Uint32 format, int access, int w, int h)
  1546 {
  1547     int hash;
  1548     SDL_Renderer *renderer;
  1549     SDL_Texture *texture;
  1550 
  1551     if (!_this) {
  1552         SDL_UninitializedVideo();
  1553         return 0;
  1554     }
  1555     renderer = SDL_CurrentDisplay.current_renderer;
  1556     if (!renderer) {
  1557         return 0;
  1558     }
  1559     if (!renderer->CreateTexture) {
  1560         SDL_Unsupported();
  1561         return 0;
  1562     }
  1563     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
  1564     if (!texture) {
  1565         SDL_OutOfMemory();
  1566         return 0;
  1567     }
  1568     texture->id = _this->next_object_id++;
  1569     texture->format = format;
  1570     texture->access = access;
  1571     texture->w = w;
  1572     texture->h = h;
  1573     texture->r = 255;
  1574     texture->g = 255;
  1575     texture->b = 255;
  1576     texture->a = 255;
  1577     texture->renderer = renderer;
  1578 
  1579     if (renderer->CreateTexture(renderer, texture) < 0) {
  1580         if (renderer->DestroyTexture) {
  1581             renderer->DestroyTexture(renderer, texture);
  1582         }
  1583         SDL_free(texture);
  1584         return 0;
  1585     }
  1586     hash = (texture->id % SDL_arraysize(SDL_CurrentDisplay.textures));
  1587     texture->next = SDL_CurrentDisplay.textures[hash];
  1588     SDL_CurrentDisplay.textures[hash] = texture;
  1589 
  1590     return texture->id;
  1591 }
  1592 
  1593 SDL_TextureID
  1594 SDL_CreateTextureFromSurface(Uint32 format, SDL_Surface * surface)
  1595 {
  1596     SDL_TextureID textureID;
  1597     Uint32 requested_format = format;
  1598     SDL_PixelFormat *fmt;
  1599     int bpp;
  1600     Uint32 Rmask, Gmask, Bmask, Amask;
  1601 
  1602     if (!surface) {
  1603         SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
  1604         return 0;
  1605     }
  1606     fmt = surface->format;
  1607 
  1608     if (format) {
  1609         if (!SDL_PixelFormatEnumToMasks
  1610             (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1611             SDL_SetError("Unknown pixel format");
  1612             return 0;
  1613         }
  1614     } else {
  1615         /* FIXME: Get the best supported texture format */
  1616         if (surface->format->Amask
  1617             || !(surface->map->info.flags &
  1618                  (SDL_COPY_COLORKEY | SDL_COPY_MASK | SDL_COPY_BLEND))) {
  1619             bpp = fmt->BitsPerPixel;
  1620             Rmask = fmt->Rmask;
  1621             Gmask = fmt->Gmask;
  1622             Bmask = fmt->Bmask;
  1623             Amask = fmt->Amask;
  1624         } else {
  1625             /* Need a format with alpha */
  1626             bpp = 32;
  1627             Rmask = 0x00FF0000;
  1628             Gmask = 0x0000FF00;
  1629             Bmask = 0x000000FF;
  1630             Amask = 0xFF000000;
  1631         }
  1632         format = SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
  1633         if (!format) {
  1634             SDL_SetError("Unknown pixel format");
  1635             return 0;
  1636         }
  1637     }
  1638 
  1639     textureID =
  1640         SDL_CreateTexture(format, SDL_TEXTUREACCESS_STATIC, surface->w,
  1641                           surface->h);
  1642     if (!textureID && !requested_format) {
  1643         SDL_DisplayMode desktop_mode;
  1644         SDL_GetDesktopDisplayMode(&desktop_mode);
  1645         format = desktop_mode.format;
  1646         textureID =
  1647             SDL_CreateTexture(format, SDL_TEXTUREACCESS_STATIC, surface->w,
  1648                               surface->h);
  1649     }
  1650     if (!textureID) {
  1651         return 0;
  1652     }
  1653     if (bpp == fmt->BitsPerPixel && Rmask == fmt->Rmask && Gmask == fmt->Gmask
  1654         && Bmask == fmt->Bmask && Amask == fmt->Amask) {
  1655         if (SDL_MUSTLOCK(surface)) {
  1656             if (SDL_LockSurface(surface) < 0) {
  1657                 SDL_DestroyTexture(textureID);
  1658                 return 0;
  1659             }
  1660             SDL_UpdateTexture(textureID, NULL, surface->pixels,
  1661                               surface->pitch);
  1662             SDL_UnlockSurface(surface);
  1663         } else {
  1664             SDL_UpdateTexture(textureID, NULL, surface->pixels,
  1665                               surface->pitch);
  1666         }
  1667     } else {
  1668         SDL_PixelFormat dst_fmt;
  1669         SDL_Surface *dst = NULL;
  1670 
  1671         /* Set up a destination surface for the texture update */
  1672         SDL_InitFormat(&dst_fmt, bpp, Rmask, Gmask, Bmask, Amask);
  1673         if (SDL_ISPIXELFORMAT_INDEXED(format)) {
  1674             dst_fmt.palette =
  1675                 SDL_AllocPalette((1 << SDL_BITSPERPIXEL(format)));
  1676             if (dst_fmt.palette) {
  1677                 /*
  1678                  * FIXME: Should we try to copy
  1679                  * fmt->palette?
  1680                  */
  1681                 SDL_DitherColors(dst_fmt.palette->colors,
  1682                                  SDL_BITSPERPIXEL(format));
  1683             }
  1684         }
  1685         dst = SDL_ConvertSurface(surface, &dst_fmt, 0);
  1686         if (dst) {
  1687             SDL_UpdateTexture(textureID, NULL, dst->pixels, dst->pitch);
  1688             SDL_FreeSurface(dst);
  1689         }
  1690         if (dst_fmt.palette) {
  1691             SDL_FreePalette(dst_fmt.palette);
  1692         }
  1693         if (!dst) {
  1694             SDL_DestroyTexture(textureID);
  1695             return 0;
  1696         }
  1697     }
  1698 
  1699     {
  1700         Uint8 r, g, b, a;
  1701         int blendMode;
  1702         int scaleMode;
  1703 
  1704         SDL_GetSurfaceColorMod(surface, &r, &g, &b);
  1705         SDL_SetTextureColorMod(textureID, r, g, b);
  1706 
  1707         SDL_GetSurfaceAlphaMod(surface, &a);
  1708         SDL_SetTextureAlphaMod(textureID, a);
  1709 
  1710         SDL_GetSurfaceBlendMode(surface, &blendMode);
  1711         SDL_SetTextureBlendMode(textureID, blendMode);
  1712 
  1713         SDL_GetSurfaceScaleMode(surface, &scaleMode);
  1714         SDL_SetTextureScaleMode(textureID, scaleMode);
  1715     }
  1716 
  1717     if (SDL_ISPIXELFORMAT_INDEXED(format) && fmt->palette) {
  1718         SDL_SetTexturePalette(textureID, fmt->palette->colors, 0,
  1719                               fmt->palette->ncolors);
  1720     }
  1721     return textureID;
  1722 }
  1723 
  1724 static __inline__ SDL_Texture *
  1725 SDL_GetTextureFromID(SDL_TextureID textureID)
  1726 {
  1727     int hash;
  1728     SDL_Texture *texture;
  1729 
  1730     if (!_this) {
  1731         return NULL;
  1732     }
  1733     hash = (textureID % SDL_arraysize(SDL_CurrentDisplay.textures));
  1734     for (texture = SDL_CurrentDisplay.textures[hash]; texture;
  1735          texture = texture->next) {
  1736         if (texture->id == textureID) {
  1737             return texture;
  1738         }
  1739     }
  1740     return NULL;
  1741 }
  1742 
  1743 int
  1744 SDL_QueryTexture(SDL_TextureID textureID, Uint32 * format, int *access,
  1745                  int *w, int *h)
  1746 {
  1747     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1748 
  1749     if (!texture) {
  1750         return -1;
  1751     }
  1752     if (format) {
  1753         *format = texture->format;
  1754     }
  1755     if (access) {
  1756         *access = texture->access;
  1757     }
  1758     if (w) {
  1759         *w = texture->w;
  1760     }
  1761     if (h) {
  1762         *h = texture->h;
  1763     }
  1764     return 0;
  1765 }
  1766 
  1767 int
  1768 SDL_QueryTexturePixels(SDL_TextureID textureID, void **pixels, int *pitch)
  1769 {
  1770     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1771     SDL_Renderer *renderer;
  1772 
  1773     if (!texture) {
  1774         return -1;
  1775     }
  1776     renderer = texture->renderer;
  1777     if (!renderer->QueryTexturePixels) {
  1778         SDL_Unsupported();
  1779         return -1;
  1780     }
  1781     return renderer->QueryTexturePixels(renderer, texture, pixels, pitch);
  1782 }
  1783 
  1784 int
  1785 SDL_SetTexturePalette(SDL_TextureID textureID, const SDL_Color * colors,
  1786                       int firstcolor, int ncolors)
  1787 {
  1788     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1789     SDL_Renderer *renderer;
  1790 
  1791     if (!texture) {
  1792         return -1;
  1793     }
  1794     renderer = texture->renderer;
  1795     if (!renderer->SetTexturePalette) {
  1796         SDL_Unsupported();
  1797         return -1;
  1798     }
  1799     return renderer->SetTexturePalette(renderer, texture, colors, firstcolor,
  1800                                        ncolors);
  1801 }
  1802 
  1803 int
  1804 SDL_GetTexturePalette(SDL_TextureID textureID, SDL_Color * colors,
  1805                       int firstcolor, int ncolors)
  1806 {
  1807     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1808     SDL_Renderer *renderer;
  1809 
  1810     if (!texture) {
  1811         return -1;
  1812     }
  1813     renderer = texture->renderer;
  1814     if (!renderer->GetTexturePalette) {
  1815         SDL_Unsupported();
  1816         return -1;
  1817     }
  1818     return renderer->GetTexturePalette(renderer, texture, colors, firstcolor,
  1819                                        ncolors);
  1820 }
  1821 
  1822 int
  1823 SDL_SetTextureColorMod(SDL_TextureID textureID, Uint8 r, Uint8 g, Uint8 b)
  1824 {
  1825     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1826     SDL_Renderer *renderer;
  1827 
  1828     if (!texture) {
  1829         return -1;
  1830     }
  1831     renderer = texture->renderer;
  1832     if (!renderer->SetTextureColorMod) {
  1833         SDL_Unsupported();
  1834         return -1;
  1835     }
  1836     if (r < 255 || g < 255 || b < 255) {
  1837         texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
  1838     } else {
  1839         texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
  1840     }
  1841     texture->r = r;
  1842     texture->g = g;
  1843     texture->b = b;
  1844     return renderer->SetTextureColorMod(renderer, texture);
  1845 }
  1846 
  1847 int
  1848 SDL_GetTextureColorMod(SDL_TextureID textureID, Uint8 * r, Uint8 * g,
  1849                        Uint8 * b)
  1850 {
  1851     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1852     SDL_Renderer *renderer;
  1853 
  1854     if (!texture) {
  1855         return -1;
  1856     }
  1857     renderer = texture->renderer;
  1858     if (r) {
  1859         *r = texture->r;
  1860     }
  1861     if (g) {
  1862         *g = texture->g;
  1863     }
  1864     if (b) {
  1865         *b = texture->b;
  1866     }
  1867     return 0;
  1868 }
  1869 
  1870 int
  1871 SDL_SetTextureAlphaMod(SDL_TextureID textureID, Uint8 alpha)
  1872 {
  1873     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1874     SDL_Renderer *renderer;
  1875 
  1876     if (!texture) {
  1877         return -1;
  1878     }
  1879     renderer = texture->renderer;
  1880     if (!renderer->SetTextureAlphaMod) {
  1881         SDL_Unsupported();
  1882         return -1;
  1883     }
  1884     if (alpha < 255) {
  1885         texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
  1886     } else {
  1887         texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA;
  1888     }
  1889     texture->a = alpha;
  1890     return renderer->SetTextureAlphaMod(renderer, texture);
  1891 }
  1892 
  1893 int
  1894 SDL_GetTextureAlphaMod(SDL_TextureID textureID, Uint8 * alpha)
  1895 {
  1896     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1897 
  1898     if (!texture) {
  1899         return -1;
  1900     }
  1901     if (alpha) {
  1902         *alpha = texture->a;
  1903     }
  1904     return 0;
  1905 }
  1906 
  1907 int
  1908 SDL_SetTextureBlendMode(SDL_TextureID textureID, int blendMode)
  1909 {
  1910     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1911     SDL_Renderer *renderer;
  1912 
  1913     if (!texture) {
  1914         return -1;
  1915     }
  1916     renderer = texture->renderer;
  1917     if (!renderer->SetTextureBlendMode) {
  1918         SDL_Unsupported();
  1919         return -1;
  1920     }
  1921     texture->blendMode = blendMode;
  1922     return renderer->SetTextureBlendMode(renderer, texture);
  1923 }
  1924 
  1925 int
  1926 SDL_GetTextureBlendMode(SDL_TextureID textureID, int *blendMode)
  1927 {
  1928     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1929 
  1930     if (!texture) {
  1931         return -1;
  1932     }
  1933     if (blendMode) {
  1934         *blendMode = texture->blendMode;
  1935     }
  1936     return 0;
  1937 }
  1938 
  1939 int
  1940 SDL_SetTextureScaleMode(SDL_TextureID textureID, int scaleMode)
  1941 {
  1942     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1943     SDL_Renderer *renderer;
  1944 
  1945     if (!texture) {
  1946         return -1;
  1947     }
  1948     renderer = texture->renderer;
  1949     if (!renderer->SetTextureScaleMode) {
  1950         SDL_Unsupported();
  1951         return -1;
  1952     }
  1953     texture->scaleMode = scaleMode;
  1954     return renderer->SetTextureScaleMode(renderer, texture);
  1955 }
  1956 
  1957 int
  1958 SDL_GetTextureScaleMode(SDL_TextureID textureID, int *scaleMode)
  1959 {
  1960     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1961 
  1962     if (!texture) {
  1963         return -1;
  1964     }
  1965     if (scaleMode) {
  1966         *scaleMode = texture->scaleMode;
  1967     }
  1968     return 0;
  1969 }
  1970 
  1971 int
  1972 SDL_UpdateTexture(SDL_TextureID textureID, const SDL_Rect * rect,
  1973                   const void *pixels, int pitch)
  1974 {
  1975     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  1976     SDL_Renderer *renderer;
  1977     SDL_Rect full_rect;
  1978 
  1979     if (!texture) {
  1980         return -1;
  1981     }
  1982     renderer = texture->renderer;
  1983     if (!renderer->UpdateTexture) {
  1984         SDL_Unsupported();
  1985         return -1;
  1986     }
  1987     if (!rect) {
  1988         full_rect.x = 0;
  1989         full_rect.y = 0;
  1990         full_rect.w = texture->w;
  1991         full_rect.h = texture->h;
  1992         rect = &full_rect;
  1993     }
  1994     return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
  1995 }
  1996 
  1997 int
  1998 SDL_LockTexture(SDL_TextureID textureID, const SDL_Rect * rect, int markDirty,
  1999                 void **pixels, int *pitch)
  2000 {
  2001     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  2002     SDL_Renderer *renderer;
  2003     SDL_Rect full_rect;
  2004 
  2005     if (!texture) {
  2006         return -1;
  2007     }
  2008     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
  2009         SDL_SetError("SDL_LockTexture(): texture must be streaming");
  2010         return -1;
  2011     }
  2012     renderer = texture->renderer;
  2013     if (!renderer->LockTexture) {
  2014         SDL_Unsupported();
  2015         return -1;
  2016     }
  2017     if (!rect) {
  2018         full_rect.x = 0;
  2019         full_rect.y = 0;
  2020         full_rect.w = texture->w;
  2021         full_rect.h = texture->h;
  2022         rect = &full_rect;
  2023     }
  2024     return renderer->LockTexture(renderer, texture, rect, markDirty, pixels,
  2025                                  pitch);
  2026 }
  2027 
  2028 void
  2029 SDL_UnlockTexture(SDL_TextureID textureID)
  2030 {
  2031     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  2032     SDL_Renderer *renderer;
  2033 
  2034     if (!texture) {
  2035         return;
  2036     }
  2037     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
  2038         return;
  2039     }
  2040     renderer = texture->renderer;
  2041     if (!renderer->UnlockTexture) {
  2042         return;
  2043     }
  2044     renderer->UnlockTexture(renderer, texture);
  2045 }
  2046 
  2047 void
  2048 SDL_DirtyTexture(SDL_TextureID textureID, int numrects,
  2049                  const SDL_Rect * rects)
  2050 {
  2051     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  2052     SDL_Renderer *renderer;
  2053 
  2054     if (!texture) {
  2055         return;
  2056     }
  2057     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
  2058         return;
  2059     }
  2060     renderer = texture->renderer;
  2061     if (!renderer->DirtyTexture) {
  2062         return;
  2063     }
  2064     renderer->DirtyTexture(renderer, texture, numrects, rects);
  2065 }
  2066 
  2067 int
  2068 SDL_SetRenderDrawColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  2069 {
  2070     SDL_Renderer *renderer;
  2071 
  2072     if (!_this) {
  2073         SDL_UninitializedVideo();
  2074         return -1;
  2075     }
  2076     renderer = SDL_CurrentDisplay.current_renderer;
  2077     if (!renderer) {
  2078         return -1;
  2079     }
  2080     renderer->r = r;
  2081     renderer->g = g;
  2082     renderer->b = b;
  2083     renderer->a = a;
  2084     if (renderer->SetDrawColor) {
  2085         return renderer->SetDrawColor(renderer);
  2086     } else {
  2087         return 0;
  2088     }
  2089 }
  2090 
  2091 int
  2092 SDL_GetRenderDrawColor(Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
  2093 {
  2094     SDL_Renderer *renderer;
  2095 
  2096     if (!_this) {
  2097         SDL_UninitializedVideo();
  2098         return -1;
  2099     }
  2100     renderer = SDL_CurrentDisplay.current_renderer;
  2101     if (!renderer) {
  2102         return -1;
  2103     }
  2104     if (r) {
  2105         *r = renderer->r;
  2106     }
  2107     if (g) {
  2108         *g = renderer->g;
  2109     }
  2110     if (b) {
  2111         *b = renderer->b;
  2112     }
  2113     if (a) {
  2114         *a = renderer->a;
  2115     }
  2116     return 0;
  2117 }
  2118 
  2119 int
  2120 SDL_SetRenderDrawBlendMode(int blendMode)
  2121 {
  2122     SDL_Renderer *renderer;
  2123 
  2124     if (!_this) {
  2125         SDL_UninitializedVideo();
  2126         return -1;
  2127     }
  2128     renderer = SDL_CurrentDisplay.current_renderer;
  2129     if (!renderer) {
  2130         return -1;
  2131     }
  2132     renderer->blendMode = blendMode;
  2133     if (renderer->SetDrawBlendMode) {
  2134         return renderer->SetDrawBlendMode(renderer);
  2135     } else {
  2136         return 0;
  2137     }
  2138 }
  2139 
  2140 int
  2141 SDL_GetRenderDrawBlendMode(int *blendMode)
  2142 {
  2143     SDL_Renderer *renderer;
  2144 
  2145     if (!_this) {
  2146         SDL_UninitializedVideo();
  2147         return -1;
  2148     }
  2149     renderer = SDL_CurrentDisplay.current_renderer;
  2150     if (!renderer) {
  2151         return -1;
  2152     }
  2153     *blendMode = renderer->blendMode;
  2154     return 0;
  2155 }
  2156 
  2157 int
  2158 SDL_RenderPoint(int x, int y)
  2159 {
  2160     SDL_Renderer *renderer;
  2161     SDL_Window *window;
  2162 
  2163     if (!_this) {
  2164         SDL_UninitializedVideo();
  2165         return -1;
  2166     }
  2167     renderer = SDL_CurrentDisplay.current_renderer;
  2168     if (!renderer) {
  2169         return -1;
  2170     }
  2171     if (!renderer->RenderPoint) {
  2172         SDL_Unsupported();
  2173         return -1;
  2174     }
  2175     window = SDL_GetWindowFromID(renderer->window);
  2176     if (x < 0 || y < 0 || x >= window->w || y >= window->h) {
  2177         return 0;
  2178     }
  2179     return renderer->RenderPoint(renderer, x, y);
  2180 }
  2181 
  2182 int
  2183 SDL_RenderLine(int x1, int y1, int x2, int y2)
  2184 {
  2185     SDL_Renderer *renderer;
  2186     SDL_Window *window;
  2187     SDL_Rect real_rect;
  2188 
  2189     if (x1 == x2 && y1 == y2) {
  2190         return SDL_RenderPoint(x1, y1);
  2191     }
  2192 
  2193     if (!_this) {
  2194         SDL_UninitializedVideo();
  2195         return -1;
  2196     }
  2197     renderer = SDL_CurrentDisplay.current_renderer;
  2198     if (!renderer) {
  2199         return -1;
  2200     }
  2201     if (!renderer->RenderLine) {
  2202         SDL_Unsupported();
  2203         return -1;
  2204     }
  2205     window = SDL_GetWindowFromID(renderer->window);
  2206 
  2207     real_rect.x = 0;
  2208     real_rect.y = 0;
  2209     real_rect.w = window->w;
  2210     real_rect.h = window->h;
  2211     if (!SDL_IntersectRectAndLine(&real_rect, &x1, &y1, &x2, &y2)) {
  2212         return (0);
  2213     }
  2214     return renderer->RenderLine(renderer, x1, y1, x2, y2);
  2215 }
  2216 
  2217 int
  2218 SDL_RenderFill(const SDL_Rect * rect)
  2219 {
  2220     SDL_Renderer *renderer;
  2221     SDL_Window *window;
  2222     SDL_Rect real_rect;
  2223 
  2224     if (!_this) {
  2225         SDL_UninitializedVideo();
  2226         return -1;
  2227     }
  2228     renderer = SDL_CurrentDisplay.current_renderer;
  2229     if (!renderer) {
  2230         return -1;
  2231     }
  2232     if (!renderer->RenderFill) {
  2233         SDL_Unsupported();
  2234         return -1;
  2235     }
  2236     window = SDL_GetWindowFromID(renderer->window);
  2237 
  2238     real_rect.x = 0;
  2239     real_rect.y = 0;
  2240     real_rect.w = window->w;
  2241     real_rect.h = window->h;
  2242     if (rect) {
  2243         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  2244             return 0;
  2245         }
  2246     }
  2247     return renderer->RenderFill(renderer, &real_rect);
  2248 }
  2249 
  2250 int
  2251 SDL_RenderCopy(SDL_TextureID textureID, const SDL_Rect * srcrect,
  2252                const SDL_Rect * dstrect)
  2253 {
  2254     SDL_Texture *texture = SDL_GetTextureFromID(textureID);
  2255     SDL_Renderer *renderer;
  2256     SDL_Window *window;
  2257     SDL_Rect real_srcrect;
  2258     SDL_Rect real_dstrect;
  2259 
  2260     if (!texture || texture->renderer != SDL_CurrentDisplay.current_renderer) {
  2261         return -1;
  2262     }
  2263     renderer = SDL_CurrentDisplay.current_renderer;
  2264     if (!renderer) {
  2265         return -1;
  2266     }
  2267     if (!renderer->RenderCopy) {
  2268         SDL_Unsupported();
  2269         return -1;
  2270     }
  2271     window = SDL_GetWindowFromID(renderer->window);
  2272 
  2273     real_srcrect.x = 0;
  2274     real_srcrect.y = 0;
  2275     real_srcrect.w = texture->w;
  2276     real_srcrect.h = texture->h;
  2277     if (srcrect) {
  2278         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  2279             return 0;
  2280         }
  2281     }
  2282 
  2283     real_dstrect.x = 0;
  2284     real_dstrect.y = 0;
  2285     real_dstrect.w = window->w;
  2286     real_dstrect.h = window->h;
  2287     if (dstrect) {
  2288         if (!SDL_IntersectRect(dstrect, &real_dstrect, &real_dstrect)) {
  2289             return 0;
  2290         }
  2291         /* Clip srcrect by the same amount as dstrect was clipped */
  2292         if (dstrect->w != real_dstrect.w) {
  2293             int deltax = (real_dstrect.x - dstrect->x);
  2294             int deltaw = (real_dstrect.w - dstrect->w);
  2295             real_srcrect.x += (deltax * dstrect->w) / real_srcrect.w;
  2296             real_srcrect.w += (deltaw * dstrect->w) / real_srcrect.w;
  2297         }
  2298         if (dstrect->h != real_dstrect.h) {
  2299             int deltay = (real_dstrect.y - dstrect->y);
  2300             int deltah = (real_dstrect.h - dstrect->h);
  2301             real_srcrect.y += (deltay * dstrect->h) / real_srcrect.h;
  2302             real_srcrect.h += (deltah * dstrect->h) / real_srcrect.h;
  2303         }
  2304     }
  2305 
  2306     return renderer->RenderCopy(renderer, texture, &real_srcrect,
  2307                                 &real_dstrect);
  2308 }
  2309 
  2310 void
  2311 SDL_RenderPresent(void)
  2312 {
  2313     SDL_Renderer *renderer;
  2314 
  2315     if (!_this) {
  2316         SDL_UninitializedVideo();
  2317         return;
  2318     }
  2319     renderer = SDL_CurrentDisplay.current_renderer;
  2320     if (!renderer || !renderer->RenderPresent) {
  2321         return;
  2322     }
  2323     renderer->RenderPresent(renderer);
  2324 }
  2325 
  2326 void
  2327 SDL_DestroyTexture(SDL_TextureID textureID)
  2328 {
  2329     int hash;
  2330     SDL_Texture *prev, *texture;
  2331     SDL_Renderer *renderer;
  2332 
  2333     if (!_this) {
  2334         SDL_UninitializedVideo();
  2335         return;
  2336     }
  2337     /* Look up the texture in the hash table */
  2338     hash = (textureID % SDL_arraysize(SDL_CurrentDisplay.textures));
  2339     prev = NULL;
  2340     for (texture = SDL_CurrentDisplay.textures[hash]; texture;
  2341          prev = texture, texture = texture->next) {
  2342         if (texture->id == textureID) {
  2343             break;
  2344         }
  2345     }
  2346     if (!texture) {
  2347         return;
  2348     }
  2349     /* Unlink the texture from the list */
  2350     if (prev) {
  2351         prev->next = texture->next;
  2352     } else {
  2353         SDL_CurrentDisplay.textures[hash] = texture->next;
  2354     }
  2355 
  2356     /* Free the texture */
  2357     renderer = texture->renderer;
  2358     renderer->DestroyTexture(renderer, texture);
  2359     SDL_free(texture);
  2360 }
  2361 
  2362 void
  2363 SDL_DestroyRenderer(SDL_WindowID windowID)
  2364 {
  2365     SDL_Window *window = SDL_GetWindowFromID(windowID);
  2366     SDL_Renderer *renderer;
  2367     int i;
  2368 
  2369     if (!window) {
  2370         return;
  2371     }
  2372     renderer = window->renderer;
  2373     if (!renderer) {
  2374         return;
  2375     }
  2376     /* Free existing textures for this renderer */
  2377     for (i = 0; i < SDL_arraysize(SDL_CurrentDisplay.textures); ++i) {
  2378         SDL_Texture *texture;
  2379         SDL_Texture *prev = NULL;
  2380         SDL_Texture *next;
  2381         for (texture = SDL_CurrentDisplay.textures[i]; texture;
  2382              texture = next) {
  2383             next = texture->next;
  2384             if (texture->renderer == renderer) {
  2385                 if (prev) {
  2386                     prev->next = next;
  2387                 } else {
  2388                     SDL_CurrentDisplay.textures[i] = next;
  2389                 }
  2390                 renderer->DestroyTexture(renderer, texture);
  2391                 SDL_free(texture);
  2392             } else {
  2393                 prev = texture;
  2394             }
  2395         }
  2396     }
  2397 
  2398     /* Free the renderer instance */
  2399     renderer->DestroyRenderer(renderer);
  2400 
  2401     /* Clear references */
  2402     window->renderer = NULL;
  2403     if (SDL_CurrentDisplay.current_renderer == renderer) {
  2404         SDL_CurrentDisplay.current_renderer = NULL;
  2405     }
  2406 }
  2407 
  2408 SDL_bool
  2409 SDL_IsScreenSaverEnabled()
  2410 {
  2411     if (!_this) {
  2412         return SDL_TRUE;
  2413     }
  2414     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2415 }
  2416 
  2417 void
  2418 SDL_EnableScreenSaver()
  2419 {
  2420     if (!_this) {
  2421         return;
  2422     }
  2423     if (!_this->suspend_screensaver) {
  2424         return;
  2425     }
  2426     _this->suspend_screensaver = SDL_FALSE;
  2427     if (_this->SuspendScreenSaver) {
  2428         _this->SuspendScreenSaver(_this);
  2429     }
  2430 }
  2431 
  2432 void
  2433 SDL_DisableScreenSaver()
  2434 {
  2435     if (!_this) {
  2436         return;
  2437     }
  2438     if (_this->suspend_screensaver) {
  2439         return;
  2440     }
  2441     _this->suspend_screensaver = SDL_TRUE;
  2442     if (_this->SuspendScreenSaver) {
  2443         _this->SuspendScreenSaver(_this);
  2444     }
  2445 }
  2446 
  2447 void
  2448 SDL_VideoQuit(void)
  2449 {
  2450     int i, j;
  2451 
  2452     if (!_this) {
  2453         return;
  2454     }
  2455     /* Halt event processing before doing anything else */
  2456     SDL_StopEventLoop();
  2457     SDL_EnableScreenSaver();
  2458 
  2459     /* Clean up the system video */
  2460     for (i = _this->num_displays; i--;) {
  2461         SDL_VideoDisplay *display = &_this->displays[i];
  2462         for (j = display->num_windows; j--;) {
  2463             SDL_DestroyWindow(display->windows[i].id);
  2464         }
  2465         if (display->windows) {
  2466             SDL_free(display->windows);
  2467             display->windows = NULL;
  2468         }
  2469         display->num_windows = 0;
  2470         if (display->render_drivers) {
  2471             SDL_free(display->render_drivers);
  2472             display->render_drivers = NULL;
  2473         }
  2474         display->num_render_drivers = 0;
  2475     }
  2476     _this->VideoQuit(_this);
  2477 
  2478     for (i = _this->num_displays; i--;) {
  2479         SDL_VideoDisplay *display = &_this->displays[i];
  2480         for (j = display->num_display_modes; j--;) {
  2481             if (display->display_modes[j].driverdata) {
  2482                 SDL_free(display->display_modes[j].driverdata);
  2483                 display->display_modes[j].driverdata = NULL;
  2484             }
  2485         }
  2486         if (display->display_modes) {
  2487             SDL_free(display->display_modes);
  2488             display->display_modes = NULL;
  2489         }
  2490         if (display->desktop_mode.driverdata) {
  2491             SDL_free(display->desktop_mode.driverdata);
  2492             display->desktop_mode.driverdata = NULL;
  2493         }
  2494         if (display->palette) {
  2495             SDL_FreePalette(display->palette);
  2496             display->palette = NULL;
  2497         }
  2498         if (display->gamma) {
  2499             SDL_free(display->gamma);
  2500             display->gamma = NULL;
  2501         }
  2502         if (display->driverdata) {
  2503             SDL_free(display->driverdata);
  2504             display->driverdata = NULL;
  2505         }
  2506     }
  2507     if (_this->displays) {
  2508         SDL_free(_this->displays);
  2509         _this->displays = NULL;
  2510     }
  2511     _this->free(_this);
  2512     _this = NULL;
  2513 }
  2514 
  2515 int
  2516 SDL_GL_LoadLibrary(const char *path)
  2517 {
  2518     int retval;
  2519 
  2520     if (!_this) {
  2521         SDL_UninitializedVideo();
  2522         return -1;
  2523     }
  2524     if (_this->gl_config.driver_loaded) {
  2525         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2526             SDL_SetError("OpenGL library already loaded");
  2527             return -1;
  2528         }
  2529         retval = 0;
  2530     } else {
  2531         if (!_this->GL_LoadLibrary) {
  2532             SDL_SetError("No dynamic GL support in video driver");
  2533             return -1;
  2534         }
  2535         retval = _this->GL_LoadLibrary(_this, path);
  2536     }
  2537     if (retval == 0) {
  2538         ++_this->gl_config.driver_loaded;
  2539     }
  2540     return (retval);
  2541 }
  2542 
  2543 void *
  2544 SDL_GL_GetProcAddress(const char *proc)
  2545 {
  2546     void *func;
  2547 
  2548     if (!_this) {
  2549         SDL_UninitializedVideo();
  2550         return NULL;
  2551     }
  2552     func = NULL;
  2553     if (_this->GL_GetProcAddress) {
  2554         if (_this->gl_config.driver_loaded) {
  2555             func = _this->GL_GetProcAddress(_this, proc);
  2556         } else {
  2557             SDL_SetError("No GL driver has been loaded");
  2558         }
  2559     } else {
  2560         SDL_SetError("No dynamic GL support in video driver");
  2561     }
  2562     return func;
  2563 }
  2564 
  2565 void
  2566 SDL_GL_UnloadLibrary(void)
  2567 {
  2568     if (!_this) {
  2569         SDL_UninitializedVideo();
  2570         return;
  2571     }
  2572     if (_this->gl_config.driver_loaded > 0) {
  2573         if (--_this->gl_config.driver_loaded > 0) {
  2574             return;
  2575         }
  2576         if (_this->GL_UnloadLibrary) {
  2577             _this->GL_UnloadLibrary(_this);
  2578         }
  2579     }
  2580 }
  2581 
  2582 SDL_bool
  2583 SDL_GL_ExtensionSupported(const char *extension)
  2584 {
  2585 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES
  2586     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2587     const char *extensions;
  2588     const char *start;
  2589     const char *where, *terminator;
  2590 
  2591     /* Extension names should not have spaces. */
  2592     where = SDL_strchr(extension, ' ');
  2593     if (where || *extension == '\0') {
  2594         return SDL_FALSE;
  2595     }
  2596     /* See if there's an environment variable override */
  2597     start = SDL_getenv(extension);
  2598     if (start && *start == '0') {
  2599         return SDL_FALSE;
  2600     }
  2601     /* Lookup the available extensions */
  2602     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2603     if (glGetStringFunc) {
  2604         extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2605     } else {
  2606         extensions = NULL;
  2607     }
  2608     if (!extensions) {
  2609         return SDL_FALSE;
  2610     }
  2611     /*
  2612      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2613      * extensions string. Don't be fooled by sub-strings, etc.
  2614      */
  2615 
  2616     start = extensions;
  2617 
  2618     for (;;) {
  2619         where = SDL_strstr(start, extension);
  2620         if (!where)
  2621             break;
  2622 
  2623         terminator = where + SDL_strlen(extension);
  2624         if (where == start || *(where - 1) == ' ')
  2625             if (*terminator == ' ' || *terminator == '\0')
  2626                 return SDL_TRUE;
  2627 
  2628         start = terminator;
  2629     }
  2630     return SDL_FALSE;
  2631 #else
  2632     return SDL_FALSE;
  2633 #endif
  2634 }
  2635 
  2636 int
  2637 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2638 {
  2639 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES
  2640     int retval;
  2641 
  2642     if (!_this) {
  2643         SDL_UninitializedVideo();
  2644         return -1;
  2645     }
  2646     retval = 0;
  2647     switch (attr) {
  2648     case SDL_GL_RED_SIZE:
  2649         _this->gl_config.red_size = value;
  2650         break;
  2651     case SDL_GL_GREEN_SIZE:
  2652         _this->gl_config.green_size = value;
  2653         break;
  2654     case SDL_GL_BLUE_SIZE:
  2655         _this->gl_config.blue_size = value;
  2656         break;
  2657     case SDL_GL_ALPHA_SIZE:
  2658         _this->gl_config.alpha_size = value;
  2659         break;
  2660     case SDL_GL_DOUBLEBUFFER:
  2661         _this->gl_config.double_buffer = value;
  2662         break;
  2663     case SDL_GL_BUFFER_SIZE:
  2664         _this->gl_config.buffer_size = value;
  2665         break;
  2666     case SDL_GL_DEPTH_SIZE:
  2667         _this->gl_config.depth_size = value;
  2668         break;
  2669     case SDL_GL_STENCIL_SIZE:
  2670         _this->gl_config.stencil_size = value;
  2671         break;
  2672     case SDL_GL_ACCUM_RED_SIZE:
  2673         _this->gl_config.accum_red_size = value;
  2674         break;
  2675     case SDL_GL_ACCUM_GREEN_SIZE:
  2676         _this->gl_config.accum_green_size = value;
  2677         break;
  2678     case SDL_GL_ACCUM_BLUE_SIZE:
  2679         _this->gl_config.accum_blue_size = value;
  2680         break;
  2681     case SDL_GL_ACCUM_ALPHA_SIZE:
  2682         _this->gl_config.accum_alpha_size = value;
  2683         break;
  2684     case SDL_GL_STEREO:
  2685         _this->gl_config.stereo = value;
  2686         break;
  2687     case SDL_GL_MULTISAMPLEBUFFERS:
  2688         _this->gl_config.multisamplebuffers = value;
  2689         break;
  2690     case SDL_GL_MULTISAMPLESAMPLES:
  2691         _this->gl_config.multisamplesamples = value;
  2692         break;
  2693     case SDL_GL_ACCELERATED_VISUAL:
  2694         _this->gl_config.accelerated = value;
  2695         break;
  2696     case SDL_GL_RETAINED_BACKING:
  2697         _this->gl_config.retained_backing = value;
  2698         break;
  2699     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2700         _this->gl_config.major_version = value;
  2701         break;
  2702     case SDL_GL_CONTEXT_MINOR_VERSION:
  2703         _this->gl_config.minor_version = value;
  2704         break;
  2705     default:
  2706         SDL_SetError("Unknown OpenGL attribute");
  2707         retval = -1;
  2708         break;
  2709     }
  2710     return retval;
  2711 #else
  2712     SDL_Unsupported();
  2713     return -1;
  2714 #endif /* SDL_VIDEO_OPENGL */
  2715 }
  2716 
  2717 int
  2718 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2719 {
  2720 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES
  2721     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2722     GLenum (APIENTRY * glGetErrorFunc) (void);
  2723     GLenum attrib = 0;
  2724     GLenum error = 0;
  2725 
  2726     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2727     if (!glGetIntegervFunc) {
  2728         return -1;
  2729     }
  2730 
  2731     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2732     if (!glGetErrorFunc) {
  2733         return -1;
  2734     }
  2735 
  2736     /* Clear value in any case */
  2737     *value=0;
  2738 
  2739     switch (attr) {
  2740     case SDL_GL_RETAINED_BACKING:
  2741         *value = _this->gl_config.retained_backing;
  2742         return 0;
  2743     case SDL_GL_RED_SIZE:
  2744         attrib = GL_RED_BITS;
  2745         break;
  2746     case SDL_GL_BLUE_SIZE:
  2747         attrib = GL_BLUE_BITS;
  2748         break;
  2749     case SDL_GL_GREEN_SIZE:
  2750         attrib = GL_GREEN_BITS;
  2751         break;
  2752     case SDL_GL_ALPHA_SIZE:
  2753         attrib = GL_ALPHA_BITS;
  2754         break;
  2755     case SDL_GL_DOUBLEBUFFER:
  2756 #ifndef SDL_VIDEO_OPENGL_ES
  2757         attrib = GL_DOUBLEBUFFER;
  2758         break;
  2759 #else
  2760         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2761         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2762         /* SDL driver must set proper value after initialization              */
  2763         *value = _this->gl_config.double_buffer;
  2764         return 0;
  2765 #endif
  2766     case SDL_GL_DEPTH_SIZE:
  2767         attrib = GL_DEPTH_BITS;
  2768         break;
  2769     case SDL_GL_STENCIL_SIZE:
  2770         attrib = GL_STENCIL_BITS;
  2771         break;
  2772 #ifndef SDL_VIDEO_OPENGL_ES
  2773     case SDL_GL_ACCUM_RED_SIZE:
  2774         attrib = GL_ACCUM_RED_BITS;
  2775         break;
  2776     case SDL_GL_ACCUM_GREEN_SIZE:
  2777         attrib = GL_ACCUM_GREEN_BITS;
  2778         break;
  2779     case SDL_GL_ACCUM_BLUE_SIZE:
  2780         attrib = GL_ACCUM_BLUE_BITS;
  2781         break;
  2782     case SDL_GL_ACCUM_ALPHA_SIZE:
  2783         attrib = GL_ACCUM_ALPHA_BITS;
  2784         break;
  2785     case SDL_GL_STEREO:
  2786         attrib = GL_STEREO;
  2787         break;
  2788 #else
  2789     case SDL_GL_ACCUM_RED_SIZE:
  2790     case SDL_GL_ACCUM_GREEN_SIZE:
  2791     case SDL_GL_ACCUM_BLUE_SIZE:
  2792     case SDL_GL_ACCUM_ALPHA_SIZE:
  2793     case SDL_GL_STEREO:
  2794         /* none of these are supported in OpenGL ES */
  2795         *value = 0;
  2796         return 0;
  2797 #endif
  2798     case SDL_GL_MULTISAMPLEBUFFERS:
  2799 #ifndef SDL_VIDEO_OPENGL_ES
  2800         attrib = GL_SAMPLE_BUFFERS_ARB;
  2801 #else
  2802         attrib = GL_SAMPLE_BUFFERS;
  2803 #endif
  2804         break;
  2805     case SDL_GL_MULTISAMPLESAMPLES:
  2806 #ifndef SDL_VIDEO_OPENGL_ES
  2807         attrib = GL_SAMPLES_ARB;
  2808 #else
  2809         attrib = GL_SAMPLES;
  2810 #endif
  2811         break;
  2812     case SDL_GL_BUFFER_SIZE:
  2813         {
  2814             GLint bits = 0;
  2815             GLint component;
  2816 
  2817             /*
  2818              * there doesn't seem to be a single flag in OpenGL
  2819              * for this!
  2820              */
  2821             glGetIntegervFunc(GL_RED_BITS, &component);
  2822             bits += component;
  2823             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2824             bits += component;
  2825             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2826             bits += component;
  2827             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2828             bits += component;
  2829 
  2830             *value = bits;
  2831             return 0;
  2832         }
  2833     case SDL_GL_ACCELERATED_VISUAL:
  2834         {
  2835             /* FIXME: How do we get this information? */
  2836             *value = (_this->gl_config.accelerated != 0);
  2837             return 0;
  2838         }
  2839     default:
  2840         SDL_SetError("Unknown OpenGL attribute");
  2841         return -1;
  2842     }
  2843 
  2844     glGetIntegervFunc(attrib, (GLint *) value);
  2845     error=glGetErrorFunc();
  2846     if (error!=GL_NO_ERROR)
  2847     {
  2848        switch (error)
  2849        {
  2850           case GL_INVALID_ENUM:
  2851                {
  2852                   SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2853                }
  2854                break;
  2855           case GL_INVALID_VALUE:
  2856                {
  2857                   SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2858                }
  2859                break;
  2860           default:
  2861                {
  2862                   SDL_SetError("OpenGL error: %08X", error);
  2863                }
  2864                break;
  2865        }
  2866        return -1;
  2867     }
  2868     return 0;
  2869 #else
  2870     SDL_Unsupported();
  2871     return -1;
  2872 #endif /* SDL_VIDEO_OPENGL */
  2873 }
  2874 
  2875 SDL_GLContext
  2876 SDL_GL_CreateContext(SDL_WindowID windowID)
  2877 {
  2878     SDL_Window *window = SDL_GetWindowFromID(windowID);
  2879 
  2880     if (!window) {
  2881         return NULL;
  2882     }
  2883     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2884         SDL_SetError("The specified window isn't an OpenGL window");
  2885         return NULL;
  2886     }
  2887     return _this->GL_CreateContext(_this, window);
  2888 }
  2889 
  2890 int
  2891 SDL_GL_MakeCurrent(SDL_WindowID windowID, SDL_GLContext context)
  2892 {
  2893     SDL_Window *window = SDL_GetWindowFromID(windowID);
  2894 
  2895     if (window && !(window->flags & SDL_WINDOW_OPENGL)) {
  2896         SDL_SetError("The specified window isn't an OpenGL window");
  2897         return -1;
  2898     }
  2899     if (!context) {
  2900         window = NULL;
  2901     }
  2902     return _this->GL_MakeCurrent(_this, window, context);
  2903 }
  2904 
  2905 int
  2906 SDL_GL_SetSwapInterval(int interval)
  2907 {
  2908     if (!_this) {
  2909         SDL_UninitializedVideo();
  2910         return -1;
  2911     }
  2912     if (_this->GL_SetSwapInterval) {
  2913         return _this->GL_SetSwapInterval(_this, interval);
  2914     } else {
  2915         SDL_SetError("Setting the swap interval is not supported");
  2916         return -1;
  2917     }
  2918 }
  2919 
  2920 int
  2921 SDL_GL_GetSwapInterval(void)
  2922 {
  2923     if (!_this) {
  2924         SDL_UninitializedVideo();
  2925         return -1;
  2926     }
  2927     if (_this->GL_GetSwapInterval) {
  2928         return _this->GL_GetSwapInterval(_this);
  2929     } else {
  2930         SDL_SetError("Getting the swap interval is not supported");
  2931         return -1;
  2932     }
  2933 }
  2934 
  2935 void
  2936 SDL_GL_SwapWindow(SDL_WindowID windowID)
  2937 {
  2938     SDL_Window *window = SDL_GetWindowFromID(windowID);
  2939 
  2940     if (!window) {
  2941         return;
  2942     }
  2943     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2944         SDL_SetError("The specified window isn't an OpenGL window");
  2945         return;
  2946     }
  2947     _this->GL_SwapWindow(_this, window);
  2948 }
  2949 
  2950 void
  2951 SDL_GL_DeleteContext(SDL_GLContext context)
  2952 {
  2953     if (!_this || !context) {
  2954         return;
  2955     }
  2956     _this->GL_MakeCurrent(_this, NULL, NULL);
  2957     _this->GL_DeleteContext(_this, context);
  2958 }
  2959 
  2960 #if 0                           // FIXME
  2961 /*
  2962  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2963  * & 2 for alpha channel.
  2964  */
  2965 static void
  2966 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2967 {
  2968     int x, y;
  2969     Uint32 colorkey;
  2970 #define SET_MASKBIT(icon, x, y, mask) \
  2971 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2972 
  2973     colorkey = icon->format->colorkey;
  2974     switch (icon->format->BytesPerPixel) {
  2975     case 1:
  2976         {
  2977             Uint8 *pixels;
  2978             for (y = 0; y < icon->h; ++y) {
  2979                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2980                 for (x = 0; x < icon->w; ++x) {
  2981                     if (*pixels++ == colorkey) {
  2982                         SET_MASKBIT(icon, x, y, mask);
  2983                     }
  2984                 }
  2985             }
  2986         }
  2987         break;
  2988 
  2989     case 2:
  2990         {
  2991             Uint16 *pixels;
  2992             for (y = 0; y < icon->h; ++y) {
  2993                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2994                 for (x = 0; x < icon->w; ++x) {
  2995                     if ((flags & 1) && *pixels == colorkey) {
  2996                         SET_MASKBIT(icon, x, y, mask);
  2997                     } else if ((flags & 2)
  2998                                && (*pixels & icon->format->Amask) == 0) {
  2999                         SET_MASKBIT(icon, x, y, mask);
  3000                     }
  3001                     pixels++;
  3002                 }
  3003             }
  3004         }
  3005         break;
  3006 
  3007     case 4:
  3008         {
  3009             Uint32 *pixels;
  3010             for (y = 0; y < icon->h; ++y) {
  3011                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  3012                 for (x = 0; x < icon->w; ++x) {
  3013                     if ((flags & 1) && *pixels == colorkey) {
  3014                         SET_MASKBIT(icon, x, y, mask);
  3015                     } else if ((flags & 2)
  3016                                && (*pixels & icon->format->Amask) == 0) {
  3017                         SET_MASKBIT(icon, x, y, mask);
  3018                     }
  3019                     pixels++;
  3020                 }
  3021             }
  3022         }
  3023         break;
  3024     }
  3025 }
  3026 
  3027 /*
  3028  * Sets the window manager icon for the display window.
  3029  */
  3030 void
  3031 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  3032 {
  3033     if (icon && _this->SetIcon) {
  3034         /* Generate a mask if necessary, and create the icon! */
  3035         if (mask == NULL) {
  3036             int mask_len = icon->h * (icon->w + 7) / 8;
  3037             int flags = 0;
  3038             mask = (Uint8 *) SDL_malloc(mask_len);
  3039             if (mask == NULL) {
  3040                 return;
  3041             }
  3042             SDL_memset(mask, ~0, mask_len);
  3043             if (icon->flags & SDL_SRCCOLORKEY)
  3044                 flags |= 1;
  3045             if (icon->flags & SDL_SRCALPHA)
  3046                 flags |= 2;
  3047             if (flags) {
  3048                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  3049             }
  3050             _this->SetIcon(_this, icon, mask);
  3051             SDL_free(mask);
  3052         } else {
  3053             _this->SetIcon(_this, icon, mask);
  3054         }
  3055     }
  3056 }
  3057 #endif
  3058 
  3059 SDL_bool
  3060 SDL_GetWindowWMInfo(SDL_WindowID windowID, struct SDL_SysWMinfo *info)
  3061 {
  3062     SDL_Window *window = SDL_GetWindowFromID(windowID);
  3063 
  3064     if (!window || !_this->GetWindowWMInfo) {
  3065         return SDL_FALSE;
  3066     }
  3067     return (_this->GetWindowWMInfo(_this, window, info));
  3068 }
  3069 
  3070 /* vi: set ts=4 sw=4 expandtab: */