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