src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 08 Dec 2008 00:52:12 +0000
changeset 2860 6ce28e5287e9
parent 2859 99210400e8b9
child 2869 2fe507a2ef7d
permissions -rw-r--r--
Date: Sun, 07 Dec 2008 13:35:23 +0100
From: Couriersud
Subject: SDL: Mouse last_x, last_y into SDL_Mouse

the attached diff moves the static vars last_x and last_y into
SDL_Mouse. These, as far as I understand it, should be tied to the
individual mouse.

The patch also makes the code check for out of window conditions of
mouse->x,y when relative movements are passed to MouseSendMotion.

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