src/video/win32/SDL_gdirender.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Aug 2006 05:24:13 +0000
changeset 1975 ccef0d0c40c6
parent 1965 a788656ca29a
child 1985 8055185ae4ed
permissions -rw-r--r--
Added resize support for GDI and Direct3D renderers
     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 #if SDL_VIDEO_RENDER_GDI
    25 
    26 #include "SDL_win32video.h"
    27 #include "../SDL_rect_c.h"
    28 #include "../SDL_yuv_sw_c.h"
    29 
    30 /* GDI renderer implementation */
    31 
    32 static SDL_Renderer *GDI_CreateRenderer(SDL_Window * window, Uint32 flags);
    33 static int GDI_DisplayModeChanged(SDL_Renderer * renderer);
    34 static int GDI_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    35 static int GDI_QueryTexturePixels(SDL_Renderer * renderer,
    36                                   SDL_Texture * texture, void **pixels,
    37                                   int *pitch);
    38 static int GDI_SetTexturePalette(SDL_Renderer * renderer,
    39                                  SDL_Texture * texture,
    40                                  const SDL_Color * colors, int firstcolor,
    41                                  int ncolors);
    42 static int GDI_GetTexturePalette(SDL_Renderer * renderer,
    43                                  SDL_Texture * texture, SDL_Color * colors,
    44                                  int firstcolor, int ncolors);
    45 static int GDI_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    46                              const SDL_Rect * rect, const void *pixels,
    47                              int pitch);
    48 static int GDI_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    49                            const SDL_Rect * rect, int markDirty,
    50                            void **pixels, int *pitch);
    51 static void GDI_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    52 static void GDI_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    53                              int numrects, const SDL_Rect * rects);
    54 static int GDI_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
    55                           Uint32 color);
    56 static int GDI_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    57                           const SDL_Rect * srcrect, const SDL_Rect * dstrect,
    58                           int blendMode, int scaleMode);
    59 static void GDI_RenderPresent(SDL_Renderer * renderer);
    60 static void GDI_DestroyTexture(SDL_Renderer * renderer,
    61                                SDL_Texture * texture);
    62 static void GDI_DestroyRenderer(SDL_Renderer * renderer);
    63 
    64 
    65 SDL_RenderDriver GDI_RenderDriver = {
    66     GDI_CreateRenderer,
    67     {
    68      "gdi",
    69      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
    70       SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
    71       SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED),
    72      (SDL_TEXTUREBLENDMODE_NONE | SDL_TEXTUREBLENDMODE_MASK |
    73       SDL_TEXTUREBLENDMODE_BLEND),
    74      (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST),
    75      11,
    76      {
    77       SDL_PIXELFORMAT_INDEX8,
    78       SDL_PIXELFORMAT_RGB555,
    79       SDL_PIXELFORMAT_RGB565,
    80       SDL_PIXELFORMAT_RGB888,
    81       SDL_PIXELFORMAT_BGR888,
    82       SDL_PIXELFORMAT_ARGB8888,
    83       SDL_PIXELFORMAT_RGBA8888,
    84       SDL_PIXELFORMAT_ABGR8888,
    85       SDL_PIXELFORMAT_BGRA8888,
    86       SDL_PIXELFORMAT_YUY2,
    87       SDL_PIXELFORMAT_UYVY},
    88      0,
    89      0}
    90 };
    91 
    92 typedef struct
    93 {
    94     HWND hwnd;
    95     HDC window_hdc;
    96     HDC render_hdc;
    97     HDC memory_hdc;
    98     HDC current_hdc;
    99     LPBITMAPINFO bmi;
   100     HBITMAP hbm[3];
   101     int current_hbm;
   102     SDL_DirtyRectList dirty;
   103     SDL_bool makedirty;
   104 } GDI_RenderData;
   105 
   106 typedef struct
   107 {
   108     SDL_SW_YUVTexture *yuv;
   109     Uint32 format;
   110     HPALETTE hpal;
   111     HBITMAP hbm;
   112     void *pixels;
   113     int pitch;
   114 } GDI_TextureData;
   115 
   116 static void
   117 UpdateYUVTextureData(SDL_Texture * texture)
   118 {
   119     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   120     SDL_Rect rect;
   121 
   122     rect.x = 0;
   123     rect.y = 0;
   124     rect.w = texture->w;
   125     rect.h = texture->h;
   126     SDL_SW_CopyYUVToRGB(data->yuv, &rect, data->format, texture->w,
   127                         texture->h, data->pixels, data->pitch);
   128 }
   129 
   130 void
   131 GDI_AddRenderDriver(_THIS)
   132 {
   133     SDL_AddRenderDriver(0, &GDI_RenderDriver);
   134 }
   135 
   136 SDL_Renderer *
   137 GDI_CreateRenderer(SDL_Window * window, Uint32 flags)
   138 {
   139     SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
   140     SDL_Renderer *renderer;
   141     GDI_RenderData *data;
   142     int bmi_size;
   143     HBITMAP hbm;
   144     int i, n;
   145 
   146     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   147     if (!renderer) {
   148         SDL_OutOfMemory();
   149         return NULL;
   150     }
   151 
   152     data = (GDI_RenderData *) SDL_calloc(1, sizeof(*data));
   153     if (!data) {
   154         GDI_DestroyRenderer(renderer);
   155         SDL_OutOfMemory();
   156         return NULL;
   157     }
   158 
   159     renderer->DisplayModeChanged = GDI_DisplayModeChanged;
   160     renderer->CreateTexture = GDI_CreateTexture;
   161     renderer->QueryTexturePixels = GDI_QueryTexturePixels;
   162     renderer->SetTexturePalette = GDI_SetTexturePalette;
   163     renderer->GetTexturePalette = GDI_GetTexturePalette;
   164     renderer->UpdateTexture = GDI_UpdateTexture;
   165     renderer->LockTexture = GDI_LockTexture;
   166     renderer->UnlockTexture = GDI_UnlockTexture;
   167     renderer->DirtyTexture = GDI_DirtyTexture;
   168     renderer->RenderFill = GDI_RenderFill;
   169     renderer->RenderCopy = GDI_RenderCopy;
   170     renderer->RenderPresent = GDI_RenderPresent;
   171     renderer->DestroyTexture = GDI_DestroyTexture;
   172     renderer->DestroyRenderer = GDI_DestroyRenderer;
   173     renderer->info = GDI_RenderDriver.info;
   174     renderer->window = window->id;
   175     renderer->driverdata = data;
   176 
   177     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   178 
   179     data->hwnd = windowdata->hwnd;
   180     data->window_hdc = windowdata->hdc;
   181     data->render_hdc = CreateCompatibleDC(data->window_hdc);
   182     data->memory_hdc = CreateCompatibleDC(data->window_hdc);
   183 
   184     /* Fill in the compatible bitmap info */
   185     bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
   186     data->bmi = (LPBITMAPINFO) SDL_calloc(1, bmi_size);
   187     if (!data->bmi) {
   188         GDI_DestroyRenderer(renderer);
   189         SDL_OutOfMemory();
   190         return NULL;
   191     }
   192     data->bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   193 
   194     hbm = CreateCompatibleBitmap(data->window_hdc, 1, 1);
   195     GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
   196     GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
   197     DeleteObject(hbm);
   198 
   199     if (flags & SDL_RENDERER_SINGLEBUFFER) {
   200         renderer->info.flags |=
   201             (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY);
   202         n = 0;
   203     } else if (flags & SDL_RENDERER_PRESENTFLIP2) {
   204         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   205         n = 2;
   206     } else if (flags & SDL_RENDERER_PRESENTFLIP3) {
   207         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   208         n = 3;
   209     } else {
   210         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
   211         n = 1;
   212     }
   213     for (i = 0; i < n; ++i) {
   214         data->hbm[i] =
   215             CreateCompatibleBitmap(data->window_hdc, window->w, window->h);
   216         if (!data->hbm[i]) {
   217             GDI_DestroyRenderer(renderer);
   218             WIN_SetError("CreateCompatibleBitmap()");
   219             return NULL;
   220         }
   221     }
   222     if (n > 0) {
   223         SelectObject(data->render_hdc, data->hbm[0]);
   224         data->current_hdc = data->render_hdc;
   225         data->makedirty = SDL_TRUE;
   226     } else {
   227         data->current_hdc = data->window_hdc;
   228         data->makedirty = SDL_FALSE;
   229     }
   230     data->current_hbm = 0;
   231 
   232     return renderer;
   233 }
   234 
   235 static int
   236 GDI_DisplayModeChanged(SDL_Renderer * renderer)
   237 {
   238     GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
   239     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   240     int i, n;
   241 
   242     if (renderer->info.flags & SDL_RENDERER_SINGLEBUFFER) {
   243         n = 0;
   244     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   245         n = 2;
   246     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   247         n = 3;
   248     } else {
   249         n = 1;
   250     }
   251     for (i = 0; i < n; ++i) {
   252         if (data->hbm[i]) {
   253             DeleteObject(data->hbm[i]);
   254             data->hbm[i] = NULL;
   255         }
   256     }
   257     for (i = 0; i < n; ++i) {
   258         data->hbm[i] =
   259             CreateCompatibleBitmap(data->window_hdc, window->w, window->h);
   260         if (!data->hbm[i]) {
   261             WIN_SetError("CreateCompatibleBitmap()");
   262             return -1;
   263         }
   264     }
   265     if (n > 0) {
   266         SelectObject(data->render_hdc, data->hbm[0]);
   267     }
   268     return 0;
   269 }
   270 
   271 static int
   272 GDI_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   273 {
   274     GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
   275     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   276     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   277     GDI_TextureData *data;
   278 
   279     data = (GDI_TextureData *) SDL_calloc(1, sizeof(*data));
   280     if (!data) {
   281         SDL_OutOfMemory();
   282         return -1;
   283     }
   284 
   285     texture->driverdata = data;
   286 
   287     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   288         data->yuv = SDL_SW_CreateYUVTexture(texture);
   289         if (!data->yuv) {
   290             return -1;
   291         }
   292         data->format = display->current_mode.format;
   293     } else {
   294         data->format = texture->format;
   295     }
   296     data->pitch = (texture->w * SDL_BYTESPERPIXEL(data->format));
   297 
   298     if (data->yuv || texture->access == SDL_TEXTUREACCESS_LOCAL
   299         || texture->format != display->current_mode.format) {
   300         int bmi_size;
   301         LPBITMAPINFO bmi;
   302 
   303         bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
   304         bmi = (LPBITMAPINFO) SDL_calloc(1, bmi_size);
   305         if (!bmi) {
   306             SDL_OutOfMemory();
   307             return -1;
   308         }
   309         bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   310         bmi->bmiHeader.biWidth = texture->w;
   311         bmi->bmiHeader.biHeight = -texture->h;  /* topdown bitmap */
   312         bmi->bmiHeader.biPlanes = 1;
   313         bmi->bmiHeader.biSizeImage = texture->h * data->pitch;
   314         bmi->bmiHeader.biXPelsPerMeter = 0;
   315         bmi->bmiHeader.biYPelsPerMeter = 0;
   316         bmi->bmiHeader.biClrUsed = 0;
   317         bmi->bmiHeader.biClrImportant = 0;
   318         bmi->bmiHeader.biBitCount = SDL_BYTESPERPIXEL(data->format) * 8;
   319         if (SDL_ISPIXELFORMAT_INDEXED(data->format)) {
   320             int i, ncolors;
   321             LOGPALETTE *palette;
   322 
   323             bmi->bmiHeader.biCompression = BI_RGB;
   324             ncolors = (1 << SDL_BITSPERPIXEL(data->format));
   325             palette =
   326                 (LOGPALETTE *) SDL_malloc(sizeof(*palette) +
   327                                           ncolors * sizeof(PALETTEENTRY));
   328             if (!palette) {
   329                 SDL_free(bmi);
   330                 SDL_OutOfMemory();
   331                 return -1;
   332             }
   333             palette->palVersion = 0x300;
   334             palette->palNumEntries = ncolors;
   335             for (i = 0; i < ncolors; ++i) {
   336                 palette->palPalEntry[i].peRed = 0xFF;
   337                 palette->palPalEntry[i].peGreen = 0xFF;
   338                 palette->palPalEntry[i].peBlue = 0xFF;
   339                 palette->palPalEntry[i].peFlags = 0;
   340             }
   341             data->hpal = CreatePalette(palette);
   342             SDL_free(palette);
   343         } else {
   344             int bpp;
   345             Uint32 Rmask, Gmask, Bmask, Amask;
   346 
   347             bmi->bmiHeader.biCompression = BI_BITFIELDS;
   348             SDL_PixelFormatEnumToMasks(data->format, &bpp, &Rmask, &Gmask,
   349                                        &Bmask, &Amask);
   350             ((Uint32 *) bmi->bmiColors)[0] = Rmask;
   351             ((Uint32 *) bmi->bmiColors)[1] = Gmask;
   352             ((Uint32 *) bmi->bmiColors)[2] = Bmask;
   353             data->hpal = NULL;
   354         }
   355         data->hbm =
   356             CreateDIBSection(renderdata->memory_hdc, bmi, DIB_RGB_COLORS,
   357                              &data->pixels, NULL, 0);
   358     } else {
   359         data->hbm =
   360             CreateCompatibleBitmap(renderdata->window_hdc, texture->w,
   361                                    texture->h);
   362         data->pixels = NULL;
   363     }
   364     if (!data->hbm) {
   365         WIN_SetError("Couldn't create bitmap");
   366         return -1;
   367     }
   368     return 0;
   369 }
   370 
   371 static int
   372 GDI_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   373                        void **pixels, int *pitch)
   374 {
   375     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   376 
   377     if (data->yuv) {
   378         return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch);
   379     } else {
   380         *pixels = data->pixels;
   381         *pitch = data->pitch;
   382         return 0;
   383     }
   384 }
   385 
   386 static int
   387 GDI_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   388                       const SDL_Color * colors, int firstcolor, int ncolors)
   389 {
   390     GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
   391     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   392 
   393     if (data->yuv) {
   394         SDL_SetError("YUV textures don't have a palette");
   395         return -1;
   396     } else {
   397         PALETTEENTRY entries[256];
   398         int i;
   399 
   400         for (i = 0; i < ncolors; ++i) {
   401             entries[i].peRed = colors[i].r;
   402             entries[i].peGreen = colors[i].g;
   403             entries[i].peBlue = colors[i].b;
   404             entries[i].peFlags = 0;
   405         }
   406         if (!SetPaletteEntries(data->hpal, firstcolor, ncolors, entries)) {
   407             WIN_SetError("SetPaletteEntries()");
   408             return -1;
   409         }
   410         return 0;
   411     }
   412 }
   413 
   414 static int
   415 GDI_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   416                       SDL_Color * colors, int firstcolor, int ncolors)
   417 {
   418     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   419 
   420     if (data->yuv) {
   421         SDL_SetError("YUV textures don't have a palette");
   422         return -1;
   423     } else {
   424         PALETTEENTRY entries[256];
   425         int i;
   426 
   427         if (!GetPaletteEntries(data->hpal, firstcolor, ncolors, entries)) {
   428             WIN_SetError("GetPaletteEntries()");
   429             return -1;
   430         }
   431         for (i = 0; i < ncolors; ++i) {
   432             colors[i].r = entries[i].peRed;
   433             colors[i].g = entries[i].peGreen;
   434             colors[i].b = entries[i].peBlue;
   435         }
   436         return 0;
   437     }
   438 }
   439 
   440 static int
   441 GDI_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   442                   const SDL_Rect * rect, const void *pixels, int pitch)
   443 {
   444     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   445 
   446     if (data->yuv) {
   447         if (SDL_SW_UpdateYUVTexture(data->yuv, rect, pixels, pitch) < 0) {
   448             return -1;
   449         }
   450         UpdateYUVTextureData(texture);
   451         return 0;
   452     } else {
   453         GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
   454 
   455         if (data->pixels) {
   456             Uint8 *src, *dst;
   457             int row;
   458             size_t length;
   459 
   460             src = (Uint8 *) pixels;
   461             dst =
   462                 (Uint8 *) data->pixels + rect->y * data->pitch +
   463                 rect->x * SDL_BYTESPERPIXEL(texture->format);
   464             length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   465             for (row = 0; row < rect->h; ++row) {
   466                 SDL_memcpy(dst, src, length);
   467                 src += pitch;
   468                 dst += data->pitch;
   469             }
   470         } else if (rect->w == texture->w && pitch == data->pitch) {
   471             if (!SetDIBits
   472                 (renderdata->window_hdc, data->hbm, rect->y, rect->h, pixels,
   473                  renderdata->bmi, DIB_RGB_COLORS)) {
   474                 WIN_SetError("SetDIBits()");
   475                 return -1;
   476             }
   477         } else {
   478             SDL_SetError
   479                 ("FIXME: Need to allocate temporary memory and do GetDIBits() followed by SetDIBits(), since we can only set blocks of scanlines at a time");
   480             return -1;
   481         }
   482         return 0;
   483     }
   484 }
   485 
   486 static int
   487 GDI_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   488                 const SDL_Rect * rect, int markDirty, void **pixels,
   489                 int *pitch)
   490 {
   491     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   492 
   493     if (data->yuv) {
   494         return SDL_SW_LockYUVTexture(data->yuv, rect, markDirty, pixels,
   495                                      pitch);
   496     } else if (data->pixels) {
   497         GdiFlush();
   498         *pixels =
   499             (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   500                       rect->x * SDL_BYTESPERPIXEL(texture->format));
   501         *pitch = data->pitch;
   502         return 0;
   503     } else {
   504         SDL_SetError("No pixels available");
   505         return -1;
   506     }
   507 }
   508 
   509 static void
   510 GDI_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   511 {
   512     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   513 
   514     if (data->yuv) {
   515         SDL_SW_UnlockYUVTexture(data->yuv);
   516         UpdateYUVTextureData(texture);
   517     }
   518 }
   519 
   520 static void
   521 GDI_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
   522                  const SDL_Rect * rects)
   523 {
   524 }
   525 
   526 static int
   527 GDI_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 color)
   528 {
   529     GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
   530     Uint8 r, g, b;
   531     RECT rc;
   532     HBRUSH brush;
   533     int status;
   534 
   535     if (data->makedirty) {
   536         SDL_AddDirtyRect(&data->dirty, rect);
   537     }
   538 
   539     r = (Uint8) ((color >> 16) & 0xFF);
   540     g = (Uint8) ((color >> 8) & 0xFF);
   541     b = (Uint8) (color & 0xFF);
   542 
   543     rc.left = rect->x;
   544     rc.top = rect->y;
   545     rc.right = rect->x + rect->w + 1;
   546     rc.bottom = rect->y + rect->h + 1;
   547 
   548     /* Should we cache the brushes? .. it looks like GDI does for us. :) */
   549     brush = CreateSolidBrush(RGB(r, g, b));
   550     SelectObject(data->current_hdc, brush);
   551     status = FillRect(data->current_hdc, &rc, brush);
   552     DeleteObject(brush);
   553 
   554     if (!status) {
   555         WIN_SetError("FillRect()");
   556         return -1;
   557     }
   558     return 0;
   559 }
   560 
   561 static int
   562 GDI_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   563                const SDL_Rect * srcrect, const SDL_Rect * dstrect,
   564                int blendMode, int scaleMode)
   565 {
   566     GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
   567     GDI_TextureData *texturedata = (GDI_TextureData *) texture->driverdata;
   568 
   569     if (data->makedirty) {
   570         SDL_AddDirtyRect(&data->dirty, dstrect);
   571     }
   572 
   573     SelectObject(data->memory_hdc, texturedata->hbm);
   574     if (texturedata->hpal) {
   575         SelectPalette(data->memory_hdc, texturedata->hpal, TRUE);
   576         RealizePalette(data->memory_hdc);
   577     }
   578     if (blendMode & (SDL_TEXTUREBLENDMODE_MASK | SDL_TEXTUREBLENDMODE_BLEND)) {
   579         static BLENDFUNCTION blendFunc = {
   580             AC_SRC_OVER,
   581             0,
   582             255,
   583             AC_SRC_ALPHA
   584         };
   585         /* FIXME: GDI uses premultiplied alpha! */
   586         if (!AlphaBlend
   587             (data->current_hdc, dstrect->x, dstrect->y, dstrect->w,
   588              dstrect->h, data->memory_hdc, srcrect->x, srcrect->y, srcrect->w,
   589              srcrect->h, blendFunc)) {
   590             WIN_SetError("AlphaBlend()");
   591             return -1;
   592         }
   593     } else {
   594         if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) {
   595             if (!BitBlt
   596                 (data->current_hdc, dstrect->x, dstrect->y, dstrect->w,
   597                  srcrect->h, data->memory_hdc, srcrect->x, srcrect->y,
   598                  SRCCOPY)) {
   599                 WIN_SetError("BitBlt()");
   600                 return -1;
   601             }
   602         } else {
   603             if (!StretchBlt
   604                 (data->current_hdc, dstrect->x, dstrect->y, dstrect->w,
   605                  dstrect->h, data->memory_hdc, srcrect->x, srcrect->y,
   606                  srcrect->w, srcrect->h, SRCCOPY)) {
   607                 WIN_SetError("StretchBlt()");
   608                 return -1;
   609             }
   610         }
   611     }
   612     return 0;
   613 }
   614 
   615 static void
   616 GDI_RenderPresent(SDL_Renderer * renderer)
   617 {
   618     GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
   619     SDL_DirtyRect *dirty;
   620 
   621     /* Send the data to the display */
   622     if (!(renderer->info.flags & SDL_RENDERER_SINGLEBUFFER)) {
   623         for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
   624             const SDL_Rect *rect = &dirty->rect;
   625             BitBlt(data->window_hdc, rect->x, rect->y, rect->w, rect->h,
   626                    data->render_hdc, rect->x, rect->y, SRCCOPY);
   627         }
   628         SDL_ClearDirtyRects(&data->dirty);
   629     }
   630 
   631     /* Update the flipping chain, if any */
   632     if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   633         data->current_hbm = (data->current_hbm + 1) % 2;
   634         SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
   635     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   636         data->current_hbm = (data->current_hbm + 1) % 3;
   637         SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
   638     }
   639 }
   640 
   641 static void
   642 GDI_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   643 {
   644     GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
   645 
   646     if (!data) {
   647         return;
   648     }
   649     if (data->yuv) {
   650         SDL_SW_DestroyYUVTexture(data->yuv);
   651     }
   652     if (data->hpal) {
   653         DeleteObject(data->hpal);
   654     }
   655     if (data->hbm) {
   656         DeleteObject(data->hbm);
   657     }
   658     SDL_free(data);
   659     texture->driverdata = NULL;
   660 }
   661 
   662 static void
   663 GDI_DestroyRenderer(SDL_Renderer * renderer)
   664 {
   665     GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
   666     int i;
   667 
   668     if (data) {
   669         DeleteDC(data->render_hdc);
   670         DeleteDC(data->memory_hdc);
   671         if (data->bmi) {
   672             SDL_free(data->bmi);
   673         }
   674         for (i = 0; i < SDL_arraysize(data->hbm); ++i) {
   675             if (data->hbm[i]) {
   676                 DeleteObject(data->hbm[i]);
   677             }
   678         }
   679         SDL_FreeDirtyRects(&data->dirty);
   680         SDL_free(data);
   681     }
   682     SDL_free(renderer);
   683 }
   684 
   685 #endif /* SDL_VIDEO_RENDER_GDI */
   686 
   687 /* vi: set ts=4 sw=4 expandtab: */