src/video/SDL_renderer_sw.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 14 Jun 2006 06:14:26 +0000
branchSDL-1.3
changeset 1678 90bf530ced8e
parent 1676 e136f3ffdc1b
child 1680 9488fca10677
permissions -rw-r--r--
SDL_SetVideoMode() compiles now...
     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_video.h"
    25 #include "SDL_sysvideo.h"
    26 
    27 
    28 /* SDL surface based renderer implementation */
    29 
    30 static SDL_Renderer *SDL_SW_CreateRenderer(SDL_Window * window, Uint32 flags);
    31 static int SDL_SW_CreateTexture(SDL_Renderer * renderer,
    32                                 SDL_Texture * texture);
    33 static int SDL_SW_QueryTexturePixels(SDL_Renderer * renderer,
    34                                      SDL_Texture * texture, void **pixels,
    35                                      int *pitch);
    36 static int SDL_SW_UpdateTexture(SDL_Renderer * renderer,
    37                                 SDL_Texture * texture, SDL_Rect * rect,
    38                                 const void *pixels, int pitch);
    39 static int SDL_SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    40                               SDL_Rect * rect, int markDirty, void **pixels,
    41                               int *pitch);
    42 static void SDL_SW_UnlockTexture(SDL_Renderer * renderer,
    43                                  SDL_Texture * texture);
    44 static void SDL_SW_DirtyTexture(SDL_Renderer * renderer,
    45                                 SDL_Texture * texture, int numrects,
    46                                 SDL_Rect * rects);
    47 static void SDL_SW_SelectRenderTexture(SDL_Renderer * renderer,
    48                                        SDL_Texture * texture);
    49 static void SDL_SW_RenderFill(SDL_Renderer * renderer, SDL_Rect * rect,
    50                               Uint32 color);
    51 static int SDL_SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    52                              SDL_Rect * srcrect, SDL_Rect * dstrect,
    53                              int blendMode, int scaleMode);
    54 static int SDL_SW_RenderReadPixels(SDL_Renderer * renderer, SDL_Rect * rect,
    55                                    void *pixels, int pitch);
    56 static int SDL_SW_RenderWritePixels(SDL_Renderer * renderer, SDL_Rect * rect,
    57                                     const void *pixels, int pitch);
    58 static void SDL_SW_RenderPresent(SDL_Renderer * renderer);
    59 static void SDL_SW_DestroyTexture(SDL_Renderer * renderer,
    60                                   SDL_Texture * texture);
    61 static void SDL_SW_DestroyRenderer(SDL_Renderer * renderer);
    62 
    63 
    64 SDL_RenderDriver SDL_SW_RenderDriver = {
    65     SDL_SW_CreateRenderer,
    66     {
    67      "software",
    68      (SDL_Renderer_PresentDiscard |
    69       SDL_Renderer_PresentCopy |
    70       SDL_Renderer_PresentFlip2 |
    71       SDL_Renderer_PresentFlip3 | SDL_Renderer_RenderTarget),
    72      (SDL_TextureBlendMode_None |
    73       SDL_TextureBlendMode_Mask | 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      32768,
    89      32768}
    90 };
    91 
    92 typedef struct
    93 {
    94     int current_screen;
    95     SDL_Surface *screens[3];
    96     SDL_Surface *target;
    97     SDL_Renderer *renderer;
    98 } SDL_SW_RenderData;
    99 
   100 SDL_Renderer *
   101 SDL_SW_CreateRenderer(SDL_Window * window, Uint32 flags)
   102 {
   103     SDL_DisplayMode *displayMode = &window->display->current_mode;
   104     SDL_Renderer *renderer;
   105     SDL_SW_RenderData *data;
   106     int i, n;
   107     int bpp;
   108     Uint32 Rmask, Gmask, Bmask, Amask;
   109 
   110     if (!SDL_PixelFormatEnumToMasks
   111         (displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   112         SDL_SetError("Unknown display format");
   113         return NULL;
   114     }
   115 
   116     renderer = (SDL_Renderer *) SDL_malloc(sizeof(*renderer));
   117     if (!renderer) {
   118         SDL_OutOfMemory();
   119         return NULL;
   120     }
   121     SDL_zerop(renderer);
   122 
   123     data = (SDL_SW_RenderData *) SDL_malloc(sizeof(*data));
   124     if (!data) {
   125         SDL_SW_DestroyRenderer(renderer);
   126         SDL_OutOfMemory();
   127         return NULL;
   128     }
   129     SDL_zerop(data);
   130 
   131     renderer->CreateTexture = SDL_SW_CreateTexture;
   132     renderer->QueryTexturePixels = SDL_SW_QueryTexturePixels;
   133     renderer->UpdateTexture = SDL_SW_UpdateTexture;
   134     renderer->LockTexture = SDL_SW_LockTexture;
   135     renderer->UnlockTexture = SDL_SW_UnlockTexture;
   136     renderer->DirtyTexture = SDL_SW_DirtyTexture;
   137     renderer->SelectRenderTexture = SDL_SW_SelectRenderTexture;
   138     renderer->RenderFill = SDL_SW_RenderFill;
   139     renderer->RenderCopy = SDL_SW_RenderCopy;
   140     renderer->RenderReadPixels = SDL_SW_RenderReadPixels;
   141     renderer->RenderWritePixels = SDL_SW_RenderWritePixels;
   142     renderer->RenderPresent = SDL_SW_RenderPresent;
   143     renderer->DestroyTexture = SDL_SW_DestroyTexture;
   144     renderer->DestroyRenderer = SDL_SW_DestroyRenderer;
   145     renderer->info = SDL_SW_RenderDriver.info;
   146     renderer->window = window;
   147     renderer->driverdata = data;
   148 
   149     renderer->info.flags = SDL_Renderer_RenderTarget;
   150 
   151     if (flags & SDL_Renderer_PresentFlip2) {
   152         renderer->info.flags |= SDL_Renderer_PresentFlip2;
   153         n = 2;
   154     } else if (flags & SDL_Renderer_PresentFlip3) {
   155         renderer->info.flags |= SDL_Renderer_PresentFlip3;
   156         n = 3;
   157     } else {
   158         renderer->info.flags |= SDL_Renderer_PresentCopy;
   159         n = 1;
   160     }
   161     for (i = 0; i < n; ++i) {
   162         data->screens[i] =
   163             SDL_CreateRGBSurface(0, window->w, window->h, bpp, Rmask, Gmask,
   164                                  Bmask, Amask);
   165         if (!data->screens[i]) {
   166             SDL_SW_DestroyRenderer(renderer);
   167             return NULL;
   168         }
   169     }
   170     data->current_screen = 0;
   171     data->target = data->screens[0];
   172 
   173     /* Find a render driver that we can use to display data */
   174     for (i = 0; i < window->display->num_render_drivers; ++i) {
   175         SDL_RenderDriver *driver = &window->display->render_drivers[i];
   176         if (driver->info.name != SDL_SW_RenderDriver.info.name) {
   177             data->renderer =
   178                 driver->CreateRenderer(window, SDL_Renderer_PresentDiscard);
   179             if (data->renderer) {
   180                 break;
   181             }
   182         }
   183     }
   184     if (i == window->display->num_render_drivers) {
   185         SDL_SW_DestroyRenderer(renderer);
   186         SDL_SetError("Couldn't find display render driver");
   187         return NULL;
   188     }
   189     return renderer;
   190 }
   191 
   192 int
   193 SDL_SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   194 {
   195     SDL_Surface *surface;
   196     int bpp;
   197     Uint32 Rmask, Gmask, Bmask, Amask;
   198 
   199     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   200         /* FIXME: implement this */
   201         return -1;
   202     }
   203 
   204     if (!SDL_PixelFormatEnumToMasks
   205         (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   206         SDL_SetError("Unknown texture format");
   207         return -1;
   208     }
   209 
   210     surface =
   211         SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
   212                              Bmask, Amask);
   213     if (!surface) {
   214         return -1;
   215     }
   216 
   217     texture->driverdata = surface;
   218     return 0;
   219 }
   220 
   221 int
   222 SDL_SW_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   223                           void **pixels, int *pitch)
   224 {
   225     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   226 
   227     *pixels = surface->pixels;
   228     *pitch = surface->pitch;
   229     return 0;
   230 }
   231 
   232 int
   233 SDL_SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   234                      SDL_Rect * rect, const void *pixels, int pitch)
   235 {
   236     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   237     Uint8 *src, *dst;
   238     int row;
   239     size_t length;
   240 
   241     src = (Uint8 *) pixels;
   242     dst =
   243         (Uint8 *) surface->pixels + rect->y * surface->pitch +
   244         rect->x * surface->format->BytesPerPixel;
   245     length = rect->w * surface->format->BytesPerPixel;
   246     for (row = 0; row < rect->h; ++row) {
   247         SDL_memcpy(dst, src, length);
   248         src += pitch;
   249         dst += surface->pitch;
   250     }
   251     return 0;
   252 }
   253 
   254 int
   255 SDL_SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   256                    SDL_Rect * rect, int markDirty, void **pixels, int *pitch)
   257 {
   258     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   259 
   260     *pixels =
   261         (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
   262                   rect->x * surface->format->BytesPerPixel);
   263     *pitch = surface->pitch;
   264     return 0;
   265 }
   266 
   267 void
   268 SDL_SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   269 {
   270 }
   271 
   272 void
   273 SDL_SW_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   274                     int numrects, SDL_Rect * rects)
   275 {
   276 }
   277 
   278 void
   279 SDL_SW_SelectRenderTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   280 {
   281     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
   282     data->target = (SDL_Surface *) texture->driverdata;
   283 }
   284 
   285 void
   286 SDL_SW_RenderFill(SDL_Renderer * renderer, SDL_Rect * rect, Uint32 color)
   287 {
   288     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
   289     Uint8 r, g, b, a;
   290 
   291     a = (Uint8) ((color >> 24) & 0xFF);
   292     r = (Uint8) ((color >> 16) & 0xFF);
   293     g = (Uint8) ((color >> 8) & 0xFF);
   294     b = (Uint8) (color & 0xFF);
   295     color = SDL_MapRGBA(data->target->format, r, g, b, a);
   296 
   297     SDL_FillRect(data->target, rect, color);
   298 }
   299 
   300 int
   301 SDL_SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   302                   SDL_Rect * srcrect, SDL_Rect * dstrect, int blendMode,
   303                   int scaleMode)
   304 {
   305     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
   306     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   307 
   308     if (blendMode & (SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend)) {
   309         SDL_SetAlpha(surface, SDL_SRCALPHA, 0);
   310     } else {
   311         SDL_SetAlpha(surface, 0, 0);
   312     }
   313     if (scaleMode != SDL_TextureScaleMode_None &&
   314         (srcrect->w != dstrect->w || srcrect->h != dstrect->h)) {
   315         return SDL_SoftStretch(surface, srcrect, data->target, dstrect);
   316     } else {
   317         return SDL_LowerBlit(surface, srcrect, data->target, dstrect);
   318     }
   319 }
   320 
   321 int
   322 SDL_SW_RenderReadPixels(SDL_Renderer * renderer, SDL_Rect * rect,
   323                         void *pixels, int pitch)
   324 {
   325     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
   326     SDL_Surface *surface = data->target;
   327     Uint8 *src, *dst;
   328     int row;
   329     size_t length;
   330 
   331     src =
   332         (Uint8 *) surface->pixels + rect->y * surface->pitch +
   333         rect->x * surface->format->BytesPerPixel;
   334     dst = (Uint8 *) pixels;
   335     length = rect->w * surface->format->BytesPerPixel;
   336     for (row = 0; row < rect->h; ++row) {
   337         SDL_memcpy(dst, src, length);
   338         src += surface->pitch;
   339         dst += pitch;
   340     }
   341     return 0;
   342 }
   343 
   344 int
   345 SDL_SW_RenderWritePixels(SDL_Renderer * renderer, SDL_Rect * rect,
   346                          const void *pixels, int pitch)
   347 {
   348     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
   349     SDL_Surface *surface = data->target;
   350     Uint8 *src, *dst;
   351     int row;
   352     size_t length;
   353 
   354     src = (Uint8 *) pixels;
   355     dst =
   356         (Uint8 *) surface->pixels + rect->y * surface->pitch +
   357         rect->x * surface->format->BytesPerPixel;
   358     length = rect->w * surface->format->BytesPerPixel;
   359     for (row = 0; row < rect->h; ++row) {
   360         SDL_memcpy(dst, src, length);
   361         src += pitch;
   362         dst += surface->pitch;
   363     }
   364     return 0;
   365 }
   366 
   367 void
   368 SDL_SW_RenderPresent(SDL_Renderer * renderer)
   369 {
   370     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
   371     SDL_Surface *surface = data->screens[data->current_screen];
   372     SDL_Rect rect;
   373     int new_screen;
   374 
   375     /* Send the data to the display */
   376     /* FIXME: implement dirty rect updates */
   377     rect.x = 0;
   378     rect.y = 0;
   379     rect.w = surface->w;
   380     rect.h = surface->h;
   381     data->renderer->RenderWritePixels(data->renderer, &rect, surface->pixels,
   382                                       surface->pitch);
   383     data->renderer->RenderPresent(data->renderer);
   384 
   385     /* Update the flipping chain, if any */
   386     if (renderer->info.flags & SDL_Renderer_PresentFlip2) {
   387         new_screen = (data->current_screen + 1) % 2;
   388     } else if (renderer->info.flags & SDL_Renderer_PresentFlip3) {
   389         new_screen = (data->current_screen + 1) % 3;
   390     } else {
   391         new_screen = 0;
   392     }
   393     if (data->target == data->screens[data->current_screen]) {
   394         data->target = data->screens[new_screen];
   395     }
   396     data->current_screen = new_screen;
   397 }
   398 
   399 void
   400 SDL_SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   401 {
   402     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   403 
   404     SDL_FreeSurface(surface);
   405 }
   406 
   407 void
   408 SDL_SW_DestroyRenderer(SDL_Renderer * renderer)
   409 {
   410     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
   411     int i;
   412 
   413     if (data) {
   414         for (i = 0; i < SDL_arraysize(data->screens); ++i) {
   415             if (data->screens[i]) {
   416                 SDL_FreeSurface(data->screens[i]);
   417             }
   418         }
   419         SDL_free(data);
   420     }
   421     SDL_free(renderer);
   422 }
   423 
   424 /* vi: set ts=4 sw=4 expandtab: */