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