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