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