src/video/win32/SDL_d3drender.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 19 Jul 2006 05:45:42 +0000
changeset 1917 3f54b3ec5a07
parent 1916 c773b0c0ac89
child 1918 092bd3a019c5
permissions -rw-r--r--
Implemented scaling in the D3D renderer
     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_D3D
    25 
    26 #include "SDL_win32video.h"
    27 
    28 /* Direct3D renderer implementation */
    29 
    30 static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
    31 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    32 static int D3D_SetTexturePalette(SDL_Renderer * renderer,
    33                                  SDL_Texture * texture,
    34                                  const SDL_Color * colors, int firstcolor,
    35                                  int ncolors);
    36 static int D3D_GetTexturePalette(SDL_Renderer * renderer,
    37                                  SDL_Texture * texture, SDL_Color * colors,
    38                                  int firstcolor, int ncolors);
    39 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    40                              const SDL_Rect * rect, const void *pixels,
    41                              int pitch);
    42 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    43                            const SDL_Rect * rect, int markDirty,
    44                            void **pixels, int *pitch);
    45 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    46 static void D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    47                              int numrects, const SDL_Rect * rects);
    48 static int D3D_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
    49                           Uint32 color);
    50 static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    51                           const SDL_Rect * srcrect, const SDL_Rect * dstrect,
    52                           int blendMode, int scaleMode);
    53 static void D3D_RenderPresent(SDL_Renderer * renderer);
    54 static void D3D_DestroyTexture(SDL_Renderer * renderer,
    55                                SDL_Texture * texture);
    56 static void D3D_DestroyRenderer(SDL_Renderer * renderer);
    57 
    58 
    59 SDL_RenderDriver D3D_RenderDriver = {
    60     D3D_CreateRenderer,
    61     {
    62      "d3d",
    63      (SDL_Renderer_SingleBuffer | SDL_Renderer_PresentCopy |
    64       SDL_Renderer_PresentFlip2 | SDL_Renderer_PresentFlip3 |
    65       SDL_Renderer_PresentDiscard | SDL_Renderer_PresentVSync),
    66      (SDL_TextureBlendMode_None | SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend),      /* FIXME */
    67      (SDL_TextureScaleMode_None | SDL_TextureScaleMode_Fast),   /* FIXME */
    68      12,
    69      {
    70       SDL_PixelFormat_Index8,
    71       SDL_PixelFormat_RGB332,
    72       SDL_PixelFormat_RGB444,
    73       SDL_PixelFormat_RGB555,
    74       SDL_PixelFormat_ARGB4444,
    75       SDL_PixelFormat_ARGB1555,
    76       SDL_PixelFormat_RGB565,
    77       SDL_PixelFormat_RGB888,
    78       SDL_PixelFormat_ARGB8888,
    79       SDL_PixelFormat_ARGB2101010,
    80       SDL_PixelFormat_UYVY,
    81       SDL_PixelFormat_YUY2},
    82      0,
    83      0}
    84 };
    85 
    86 typedef struct
    87 {
    88     IDirect3DDevice9 *device;
    89     SDL_bool beginScene;
    90 } D3D_RenderData;
    91 
    92 typedef struct
    93 {
    94     IDirect3DTexture9 *texture;
    95 } D3D_TextureData;
    96 
    97 typedef struct
    98 {
    99     float x, y, z;
   100     float rhw;
   101     float u, v;
   102 } Vertex;
   103 
   104 static void
   105 D3D_SetError(const char *prefix, HRESULT result)
   106 {
   107     const char *error;
   108 
   109     switch (result) {
   110     case D3DERR_WRONGTEXTUREFORMAT:
   111         error = "WRONGTEXTUREFORMAT";
   112         break;
   113     case D3DERR_UNSUPPORTEDCOLOROPERATION:
   114         error = "UNSUPPORTEDCOLOROPERATION";
   115         break;
   116     case D3DERR_UNSUPPORTEDCOLORARG:
   117         error = "UNSUPPORTEDCOLORARG";
   118         break;
   119     case D3DERR_UNSUPPORTEDALPHAOPERATION:
   120         error = "UNSUPPORTEDALPHAOPERATION";
   121         break;
   122     case D3DERR_UNSUPPORTEDALPHAARG:
   123         error = "UNSUPPORTEDALPHAARG";
   124         break;
   125     case D3DERR_TOOMANYOPERATIONS:
   126         error = "TOOMANYOPERATIONS";
   127         break;
   128     case D3DERR_CONFLICTINGTEXTUREFILTER:
   129         error = "CONFLICTINGTEXTUREFILTER";
   130         break;
   131     case D3DERR_UNSUPPORTEDFACTORVALUE:
   132         error = "UNSUPPORTEDFACTORVALUE";
   133         break;
   134     case D3DERR_CONFLICTINGRENDERSTATE:
   135         error = "CONFLICTINGRENDERSTATE";
   136         break;
   137     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
   138         error = "UNSUPPORTEDTEXTUREFILTER";
   139         break;
   140     case D3DERR_CONFLICTINGTEXTUREPALETTE:
   141         error = "CONFLICTINGTEXTUREPALETTE";
   142         break;
   143     case D3DERR_DRIVERINTERNALERROR:
   144         error = "DRIVERINTERNALERROR";
   145         break;
   146     case D3DERR_NOTFOUND:
   147         error = "NOTFOUND";
   148         break;
   149     case D3DERR_MOREDATA:
   150         error = "MOREDATA";
   151         break;
   152     case D3DERR_DEVICELOST:
   153         error = "DEVICELOST";
   154         break;
   155     case D3DERR_DEVICENOTRESET:
   156         error = "DEVICENOTRESET";
   157         break;
   158     case D3DERR_NOTAVAILABLE:
   159         error = "NOTAVAILABLE";
   160         break;
   161     case D3DERR_OUTOFVIDEOMEMORY:
   162         error = "OUTOFVIDEOMEMORY";
   163         break;
   164     case D3DERR_INVALIDDEVICE:
   165         error = "INVALIDDEVICE";
   166         break;
   167     case D3DERR_INVALIDCALL:
   168         error = "INVALIDCALL";
   169         break;
   170     case D3DERR_DRIVERINVALIDCALL:
   171         error = "DRIVERINVALIDCALL";
   172         break;
   173     case D3DERR_WASSTILLDRAWING:
   174         error = "WASSTILLDRAWING";
   175         break;
   176     default:
   177         error = "UNKNOWN";
   178         break;
   179     }
   180     SDL_SetError("%s: %s", prefix, error);
   181 }
   182 
   183 static D3DFORMAT
   184 PixelFormatToD3DFMT(Uint32 format)
   185 {
   186     switch (format) {
   187     case SDL_PixelFormat_Index8:
   188         return D3DFMT_P8;
   189     case SDL_PixelFormat_RGB332:
   190         return D3DFMT_R3G3B2;
   191     case SDL_PixelFormat_RGB444:
   192         return D3DFMT_X4R4G4B4;
   193     case SDL_PixelFormat_RGB555:
   194         return D3DFMT_X1R5G5B5;
   195     case SDL_PixelFormat_ARGB4444:
   196         return D3DFMT_A4R4G4B4;
   197     case SDL_PixelFormat_ARGB1555:
   198         return D3DFMT_A1R5G5B5;
   199     case SDL_PixelFormat_RGB565:
   200         return D3DFMT_R5G6B5;
   201     case SDL_PixelFormat_RGB888:
   202         return D3DFMT_X8R8G8B8;
   203     case SDL_PixelFormat_ARGB8888:
   204         return D3DFMT_A8R8G8B8;
   205     case SDL_PixelFormat_ARGB2101010:
   206         return D3DFMT_A2R10G10B10;
   207     case SDL_PixelFormat_UYVY:
   208         return D3DFMT_UYVY;
   209     case SDL_PixelFormat_YUY2:
   210         return D3DFMT_YUY2;
   211     default:
   212         return D3DFMT_UNKNOWN;
   213     }
   214 }
   215 
   216 void
   217 D3D_AddRenderDriver(_THIS)
   218 {
   219     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   220 
   221     if (data->d3d) {
   222         SDL_AddRenderDriver(0, &D3D_RenderDriver);
   223     }
   224 }
   225 
   226 SDL_Renderer *
   227 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
   228 {
   229     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   230     SDL_VideoData *videodata = (SDL_VideoData *) display->device->driverdata;
   231     SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
   232     SDL_Renderer *renderer;
   233     D3D_RenderData *data;
   234     HRESULT result;
   235     D3DPRESENT_PARAMETERS pparams;
   236     IDirect3DSwapChain9 *chain;
   237 
   238     renderer = (SDL_Renderer *) SDL_malloc(sizeof(*renderer));
   239     if (!renderer) {
   240         SDL_OutOfMemory();
   241         return NULL;
   242     }
   243     SDL_zerop(renderer);
   244 
   245     data = (D3D_RenderData *) SDL_malloc(sizeof(*data));
   246     if (!data) {
   247         D3D_DestroyRenderer(renderer);
   248         SDL_OutOfMemory();
   249         return NULL;
   250     }
   251     SDL_zerop(data);
   252 
   253     renderer->CreateTexture = D3D_CreateTexture;
   254     renderer->SetTexturePalette = D3D_SetTexturePalette;
   255     renderer->GetTexturePalette = D3D_GetTexturePalette;
   256     renderer->UpdateTexture = D3D_UpdateTexture;
   257     renderer->LockTexture = D3D_LockTexture;
   258     renderer->UnlockTexture = D3D_UnlockTexture;
   259     renderer->DirtyTexture = D3D_DirtyTexture;
   260     renderer->RenderFill = D3D_RenderFill;
   261     renderer->RenderCopy = D3D_RenderCopy;
   262     renderer->RenderPresent = D3D_RenderPresent;
   263     renderer->DestroyTexture = D3D_DestroyTexture;
   264     renderer->DestroyRenderer = D3D_DestroyRenderer;
   265     renderer->info = D3D_RenderDriver.info;
   266     renderer->window = window->id;
   267     renderer->driverdata = data;
   268 
   269     renderer->info.flags = SDL_Renderer_Accelerated;
   270 
   271     SDL_zero(pparams);
   272     pparams.BackBufferWidth = window->w;
   273     pparams.BackBufferHeight = window->h;
   274     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   275         pparams.BackBufferFormat =
   276             PixelFormatToD3DFMT(display->fullscreen_mode->format);
   277     } else {
   278         pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   279     }
   280     if (flags & SDL_Renderer_PresentFlip2) {
   281         pparams.BackBufferCount = 2;
   282         pparams.SwapEffect = D3DSWAPEFFECT_FLIP;
   283     } else if (flags & SDL_Renderer_PresentFlip3) {
   284         pparams.BackBufferCount = 3;
   285         pparams.SwapEffect = D3DSWAPEFFECT_FLIP;
   286     } else if (flags & SDL_Renderer_PresentCopy) {
   287         pparams.BackBufferCount = 1;
   288         pparams.SwapEffect = D3DSWAPEFFECT_COPY;
   289     } else {
   290         pparams.BackBufferCount = 1;
   291         pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
   292     }
   293     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   294         pparams.Windowed = FALSE;
   295         pparams.FullScreen_RefreshRateInHz =
   296             display->fullscreen_mode->refresh_rate;
   297     } else {
   298         pparams.Windowed = TRUE;
   299         pparams.FullScreen_RefreshRateInHz = 0;
   300     }
   301     if (flags & SDL_Renderer_PresentVSync) {
   302         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
   303     } else {
   304         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   305     }
   306 
   307     result = IDirect3D9_CreateDevice(videodata->d3d, D3DADAPTER_DEFAULT,        /* FIXME */
   308                                      D3DDEVTYPE_HAL,
   309                                      windowdata->hwnd,
   310                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
   311                                      &pparams, &data->device);
   312     if (FAILED(result)) {
   313         D3D_DestroyRenderer(renderer);
   314         D3D_SetError("CreateDevice()", result);
   315         return NULL;
   316     }
   317     data->beginScene = SDL_TRUE;
   318 
   319     /* Get presentation parameters to fill info */
   320     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
   321     if (FAILED(result)) {
   322         D3D_DestroyRenderer(renderer);
   323         D3D_SetError("GetSwapChain()", result);
   324         return NULL;
   325     }
   326     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
   327     if (FAILED(result)) {
   328         IDirect3DSwapChain9_Release(chain);
   329         D3D_DestroyRenderer(renderer);
   330         D3D_SetError("GetPresentParameters()", result);
   331         return NULL;
   332     }
   333     IDirect3DSwapChain9_Release(chain);
   334     switch (pparams.SwapEffect) {
   335     case D3DSWAPEFFECT_COPY:
   336         renderer->info.flags |= SDL_Renderer_PresentCopy;
   337         break;
   338     case D3DSWAPEFFECT_FLIP:
   339         switch (pparams.BackBufferCount) {
   340         case 2:
   341             renderer->info.flags |= SDL_Renderer_PresentFlip2;
   342             break;
   343         case 3:
   344             renderer->info.flags |= SDL_Renderer_PresentFlip3;
   345             break;
   346         }
   347         break;
   348     case D3DSWAPEFFECT_DISCARD:
   349         renderer->info.flags |= SDL_Renderer_PresentDiscard;
   350         break;
   351     }
   352     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
   353         renderer->info.flags |= SDL_Renderer_PresentVSync;
   354     }
   355 
   356     /* Set up parameters for rendering */
   357     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   358     IDirect3DDevice9_SetFVF(data->device, D3DFVF_XYZRHW | D3DFVF_TEX1);
   359     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   360                                     D3DCULL_NONE);
   361     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   362 
   363     return renderer;
   364 }
   365 
   366 static int
   367 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   368 {
   369     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   370     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   371     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   372     D3D_TextureData *data;
   373     D3DPOOL pool;
   374     HRESULT result;
   375 
   376     data = (D3D_TextureData *) SDL_malloc(sizeof(*data));
   377     if (!data) {
   378         SDL_OutOfMemory();
   379         return -1;
   380     }
   381     SDL_zerop(data);
   382 
   383     texture->driverdata = data;
   384 
   385     if (texture->access == SDL_TextureAccess_Local) {
   386         pool = D3DPOOL_MANAGED;
   387     } else {
   388         pool = D3DPOOL_DEFAULT;
   389     }
   390     result =
   391         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   392                                        texture->h, 1, 0,
   393                                        PixelFormatToD3DFMT(texture->format),
   394                                        pool, &data->texture, NULL);
   395     if (FAILED(result)) {
   396         SDL_free(data);
   397         D3D_SetError("CreateTexture()", result);
   398         return -1;
   399     }
   400 
   401     return 0;
   402 }
   403 
   404 static int
   405 D3D_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   406                       const SDL_Color * colors, int firstcolor, int ncolors)
   407 {
   408     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   409     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   410 
   411     return 0;
   412 }
   413 
   414 static int
   415 D3D_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   416                       SDL_Color * colors, int firstcolor, int ncolors)
   417 {
   418     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   419 
   420     return 0;
   421 }
   422 
   423 static int
   424 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   425                   const SDL_Rect * rect, const void *pixels, int pitch)
   426 {
   427     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   428     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   429     IDirect3DTexture9 *temp;
   430     RECT d3drect;
   431     D3DLOCKED_RECT locked;
   432     const Uint8 *src;
   433     Uint8 *dst;
   434     int row, length;
   435     HRESULT result;
   436 
   437     result =
   438         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   439                                        texture->h, 1, 0,
   440                                        PixelFormatToD3DFMT(texture->format),
   441                                        D3DPOOL_SYSTEMMEM, &temp, NULL);
   442     if (FAILED(result)) {
   443         D3D_SetError("CreateTexture()", result);
   444         return -1;
   445     }
   446 
   447     d3drect.left = rect->x;
   448     d3drect.right = rect->x + rect->w;
   449     d3drect.top = rect->y;
   450     d3drect.bottom = rect->y + rect->h;
   451 
   452     result = IDirect3DTexture9_LockRect(temp, 0, &locked, &d3drect, 0);
   453     if (FAILED(result)) {
   454         IDirect3DTexture9_Release(temp);
   455         D3D_SetError("LockRect()", result);
   456         return -1;
   457     }
   458 
   459     src = pixels;
   460     dst = locked.pBits;
   461     length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   462     for (row = 0; row < rect->h; ++row) {
   463         SDL_memcpy(dst, src, length);
   464         src += pitch;
   465         dst += locked.Pitch;
   466     }
   467     IDirect3DTexture9_UnlockRect(temp, 0);
   468 
   469     result =
   470         IDirect3DDevice9_UpdateTexture(renderdata->device,
   471                                        (IDirect3DBaseTexture9 *) temp,
   472                                        (IDirect3DBaseTexture9 *) data->
   473                                        texture);
   474     IDirect3DTexture9_Release(temp);
   475     if (FAILED(result)) {
   476         D3D_SetError("UpdateTexture()", result);
   477         return -1;
   478     }
   479     return 0;
   480 }
   481 
   482 static int
   483 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   484                 const SDL_Rect * rect, int markDirty, void **pixels,
   485                 int *pitch)
   486 {
   487     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   488     RECT d3drect;
   489     D3DLOCKED_RECT locked;
   490     HRESULT result;
   491 
   492     if (texture->access != SDL_TextureAccess_Local) {
   493         SDL_SetError("Can't lock remote video memory");
   494         return -1;
   495     }
   496 
   497     d3drect.left = rect->x;
   498     d3drect.right = rect->x + rect->w;
   499     d3drect.top = rect->y;
   500     d3drect.bottom = rect->y + rect->h;
   501 
   502     result =
   503         IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect,
   504                                    markDirty ? 0 : D3DLOCK_NO_DIRTY_UPDATE);
   505     if (FAILED(result)) {
   506         D3D_SetError("LockRect()", result);
   507         return -1;
   508     }
   509     *pixels = locked.pBits;
   510     *pitch = locked.Pitch;
   511     return 0;
   512 }
   513 
   514 static void
   515 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   516 {
   517     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   518 
   519     IDirect3DTexture9_UnlockRect(data->texture, 0);
   520 }
   521 
   522 static void
   523 D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
   524                  const SDL_Rect * rects)
   525 {
   526     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   527     RECT d3drect;
   528     int i;
   529 
   530     for (i = 0; i < numrects; ++i) {
   531         const SDL_Rect *rect = &rects[i];
   532 
   533         d3drect.left = rect->x;
   534         d3drect.right = rect->x + rect->w;
   535         d3drect.top = rect->y;
   536         d3drect.bottom = rect->y + rect->h;
   537 
   538         IDirect3DTexture9_AddDirtyRect(data->texture, &d3drect);
   539     }
   540 }
   541 
   542 static int
   543 D3D_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 color)
   544 {
   545     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   546     D3DRECT d3drect;
   547     HRESULT result;
   548 
   549     if (data->beginScene) {
   550         IDirect3DDevice9_BeginScene(data->device);
   551         data->beginScene = SDL_FALSE;
   552     }
   553 
   554     d3drect.x1 = rect->x;
   555     d3drect.x2 = rect->x + rect->w;
   556     d3drect.y1 = rect->y;
   557     d3drect.y2 = rect->y + rect->h;
   558 
   559     result =
   560         IDirect3DDevice9_Clear(data->device, 1, &d3drect, D3DCLEAR_TARGET,
   561                                (D3DCOLOR) color, 1.0f, 0);
   562     if (FAILED(result)) {
   563         D3D_SetError("Clear()", result);
   564         return -1;
   565     }
   566     return 0;
   567 }
   568 
   569 static int
   570 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   571                const SDL_Rect * srcrect, const SDL_Rect * dstrect,
   572                int blendMode, int scaleMode)
   573 {
   574     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   575     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
   576     float minx, miny, maxx, maxy;
   577     float minu, maxu, minv, maxv;
   578     Vertex vertices[4];
   579     HRESULT result;
   580 
   581     if (data->beginScene) {
   582         IDirect3DDevice9_BeginScene(data->device);
   583         data->beginScene = SDL_FALSE;
   584     }
   585 
   586     minx = (float) dstrect->x - 0.5f;
   587     miny = (float) dstrect->y - 0.5f;
   588     maxx = (float) dstrect->x + dstrect->w - 0.5f;
   589     maxy = (float) dstrect->y + dstrect->h - 0.5f;
   590 
   591     minu = (float) srcrect->x / texture->w;
   592     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
   593     minv = (float) srcrect->y / texture->h;
   594     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
   595 
   596     vertices[0].x = minx;
   597     vertices[0].y = miny;
   598     vertices[0].z = 0.0f;
   599     vertices[0].rhw = 1.0f;
   600     vertices[0].u = minu;
   601     vertices[0].v = minv;
   602 
   603     vertices[1].x = maxx;
   604     vertices[1].y = miny;
   605     vertices[1].z = 0.0f;
   606     vertices[1].rhw = 1.0f;
   607     vertices[1].u = maxu;
   608     vertices[1].v = minv;
   609 
   610     vertices[2].x = maxx;
   611     vertices[2].y = maxy;
   612     vertices[2].z = 0.0f;
   613     vertices[2].rhw = 1.0f;
   614     vertices[2].u = maxu;
   615     vertices[2].v = maxv;
   616 
   617     vertices[3].x = minx;
   618     vertices[3].y = maxy;
   619     vertices[3].z = 0.0f;
   620     vertices[3].rhw = 1.0f;
   621     vertices[3].u = minu;
   622     vertices[3].v = maxv;
   623 
   624     switch (blendMode) {
   625     case SDL_TextureBlendMode_None:
   626         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   627                                         FALSE);
   628         break;
   629     case SDL_TextureBlendMode_Mask:
   630     case SDL_TextureBlendMode_Blend:
   631         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   632                                         TRUE);
   633         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   634                                         D3DBLEND_SRCALPHA);
   635         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   636                                         D3DBLEND_INVSRCALPHA);
   637         break;
   638     case SDL_TextureBlendMode_Add:
   639         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   640                                         TRUE);
   641         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   642                                         D3DBLEND_SRCALPHA);
   643         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   644                                         D3DBLEND_ONE);
   645         break;
   646     case SDL_TextureBlendMode_Mod:
   647         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   648                                         TRUE);
   649         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   650                                         D3DBLEND_ZERO);
   651         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   652                                         D3DBLEND_SRCCOLOR);
   653         break;
   654     }
   655 
   656     switch (scaleMode) {
   657     case SDL_TextureScaleMode_None:
   658     case SDL_TextureScaleMode_Fast:
   659         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
   660                                          D3DTEXF_POINT);
   661         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
   662                                          D3DTEXF_POINT);
   663         break;
   664     case SDL_TextureScaleMode_Slow:
   665         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
   666                                          D3DTEXF_LINEAR);
   667         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
   668                                          D3DTEXF_LINEAR);
   669         break;
   670     case SDL_TextureScaleMode_Best:
   671         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
   672                                          D3DTEXF_GAUSSIANQUAD);
   673         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
   674                                          D3DTEXF_GAUSSIANQUAD);
   675         break;
   676     }
   677 
   678     result =
   679         IDirect3DDevice9_SetTexture(data->device, 0,
   680                                     (IDirect3DBaseTexture9 *) texturedata->
   681                                     texture);
   682     if (FAILED(result)) {
   683         D3D_SetError("SetTexture()", result);
   684         return -1;
   685     }
   686     result =
   687         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
   688                                          vertices, sizeof(*vertices));
   689     if (FAILED(result)) {
   690         D3D_SetError("DrawPrimitiveUP()", result);
   691         return -1;
   692     }
   693     return 0;
   694 }
   695 
   696 static void
   697 D3D_RenderPresent(SDL_Renderer * renderer)
   698 {
   699     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   700     HRESULT result;
   701 
   702     if (!data->beginScene) {
   703         IDirect3DDevice9_EndScene(data->device);
   704         data->beginScene = SDL_TRUE;
   705     }
   706 
   707     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
   708     if (FAILED(result)) {
   709         D3D_SetError("Present()", result);
   710     }
   711 }
   712 
   713 static void
   714 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   715 {
   716     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   717 
   718     if (!data) {
   719         return;
   720     }
   721     if (data->texture) {
   722         IDirect3DTexture9_Release(data->texture);
   723     }
   724     SDL_free(data);
   725     texture->driverdata = NULL;
   726 }
   727 
   728 void
   729 D3D_DestroyRenderer(SDL_Renderer * renderer)
   730 {
   731     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   732 
   733     if (data) {
   734         if (data->device) {
   735             IDirect3DDevice9_Release(data->device);
   736         }
   737         SDL_free(data);
   738     }
   739     SDL_free(renderer);
   740 }
   741 
   742 #endif /* SDL_VIDEO_RENDER_D3D */
   743 
   744 /* vi: set ts=4 sw=4 expandtab: */