src/render/software/SDL_render_sw.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 31 Dec 2011 09:28:07 -0500
changeset 6138 4c64952a58fb
parent 6044 35448a5ea044
child 6246 c70ec935a4bb
permissions -rwxr-xr-x
Happy New Year!
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if !SDL_RENDER_DISABLED
    24 
    25 #include "../SDL_sysrender.h"
    26 #include "SDL_render_sw_c.h"
    27 
    28 #include "SDL_draw.h"
    29 #include "SDL_blendfillrect.h"
    30 #include "SDL_blendline.h"
    31 #include "SDL_blendpoint.h"
    32 #include "SDL_drawline.h"
    33 #include "SDL_drawpoint.h"
    34 
    35 
    36 /* SDL surface based renderer implementation */
    37 
    38 static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags);
    39 static void SW_WindowEvent(SDL_Renderer * renderer,
    40                            const SDL_WindowEvent *event);
    41 static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    42 static int SW_SetTextureColorMod(SDL_Renderer * renderer,
    43                                  SDL_Texture * texture);
    44 static int SW_SetTextureAlphaMod(SDL_Renderer * renderer,
    45                                  SDL_Texture * texture);
    46 static int SW_SetTextureBlendMode(SDL_Renderer * renderer,
    47                                   SDL_Texture * texture);
    48 static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    49                             const SDL_Rect * rect, const void *pixels,
    50                             int pitch);
    51 static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    52                           const SDL_Rect * rect, void **pixels, int *pitch);
    53 static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    54 static int SW_UpdateViewport(SDL_Renderer * renderer);
    55 static int SW_RenderClear(SDL_Renderer * renderer);
    56 static int SW_RenderDrawPoints(SDL_Renderer * renderer,
    57                                const SDL_Point * points, int count);
    58 static int SW_RenderDrawLines(SDL_Renderer * renderer,
    59                               const SDL_Point * points, int count);
    60 static int SW_RenderFillRects(SDL_Renderer * renderer,
    61                               const SDL_Rect * rects, int count);
    62 static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    63                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    64 static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    65                                Uint32 format, void * pixels, int pitch);
    66 static void SW_RenderPresent(SDL_Renderer * renderer);
    67 static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    68 static void SW_DestroyRenderer(SDL_Renderer * renderer);
    69 
    70 
    71 SDL_RenderDriver SW_RenderDriver = {
    72     SW_CreateRenderer,
    73     {
    74      "software",
    75      SDL_RENDERER_SOFTWARE,
    76      8,
    77      {
    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      },
    87      0,
    88      0}
    89 };
    90 
    91 typedef struct
    92 {
    93     SDL_Surface *surface;
    94 } SW_RenderData;
    95 
    96 
    97 static SDL_Surface *
    98 SW_ActivateRenderer(SDL_Renderer * renderer)
    99 {
   100     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   101 
   102     if (!data->surface) {
   103         data->surface = SDL_GetWindowSurface(renderer->window);
   104 
   105         SW_UpdateViewport(renderer);
   106     }
   107     return data->surface;
   108 }
   109 
   110 SDL_Renderer *
   111 SW_CreateRendererForSurface(SDL_Surface * surface)
   112 {
   113     SDL_Renderer *renderer;
   114     SW_RenderData *data;
   115 
   116     if (!surface) {
   117         SDL_SetError("Can't create renderer for NULL surface");
   118         return NULL;
   119     }
   120 
   121     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   122     if (!renderer) {
   123         SDL_OutOfMemory();
   124         return NULL;
   125     }
   126 
   127     data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
   128     if (!data) {
   129         SW_DestroyRenderer(renderer);
   130         SDL_OutOfMemory();
   131         return NULL;
   132     }
   133     data->surface = surface;
   134 
   135     renderer->WindowEvent = SW_WindowEvent;
   136     renderer->CreateTexture = SW_CreateTexture;
   137     renderer->SetTextureColorMod = SW_SetTextureColorMod;
   138     renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
   139     renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
   140     renderer->UpdateTexture = SW_UpdateTexture;
   141     renderer->LockTexture = SW_LockTexture;
   142     renderer->UnlockTexture = SW_UnlockTexture;
   143     renderer->UpdateViewport = SW_UpdateViewport;
   144     renderer->DestroyTexture = SW_DestroyTexture;
   145     renderer->RenderClear = SW_RenderClear;
   146     renderer->RenderDrawPoints = SW_RenderDrawPoints;
   147     renderer->RenderDrawLines = SW_RenderDrawLines;
   148     renderer->RenderFillRects = SW_RenderFillRects;
   149     renderer->RenderCopy = SW_RenderCopy;
   150     renderer->RenderReadPixels = SW_RenderReadPixels;
   151     renderer->RenderPresent = SW_RenderPresent;
   152     renderer->DestroyRenderer = SW_DestroyRenderer;
   153     renderer->info = SW_RenderDriver.info;
   154     renderer->driverdata = data;
   155 
   156     SW_ActivateRenderer(renderer);
   157 
   158     return renderer;
   159 }
   160 
   161 SDL_Renderer *
   162 SW_CreateRenderer(SDL_Window * window, Uint32 flags)
   163 {
   164     SDL_Surface *surface;
   165 
   166     surface = SDL_GetWindowSurface(window);
   167     if (!surface) {
   168         return NULL;
   169     }
   170     return SW_CreateRendererForSurface(surface);
   171 }
   172 
   173 static void
   174 SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   175 {
   176     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   177 
   178     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   179         data->surface = NULL;
   180     }
   181 }
   182 
   183 static int
   184 SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   185 {
   186     int bpp;
   187     Uint32 Rmask, Gmask, Bmask, Amask;
   188 
   189     if (!SDL_PixelFormatEnumToMasks
   190         (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   191         SDL_SetError("Unknown texture format");
   192         return -1;
   193     }
   194 
   195     texture->driverdata =
   196         SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
   197                              Bmask, Amask);
   198     SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
   199                            texture->b);
   200     SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
   201     SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
   202 
   203     if (texture->access == SDL_TEXTUREACCESS_STATIC) {
   204         SDL_SetSurfaceRLE(texture->driverdata, 1);
   205     }
   206 
   207     if (!texture->driverdata) {
   208         return -1;
   209     }
   210     return 0;
   211 }
   212 
   213 static int
   214 SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   215 {
   216     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   217     return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
   218                                   texture->b);
   219 }
   220 
   221 static int
   222 SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   223 {
   224     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   225     return SDL_SetSurfaceAlphaMod(surface, texture->a);
   226 }
   227 
   228 static int
   229 SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   230 {
   231     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   232     return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
   233 }
   234 
   235 static int
   236 SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   237                  const SDL_Rect * rect, const void *pixels, int pitch)
   238 {
   239     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   240     Uint8 *src, *dst;
   241     int row;
   242     size_t length;
   243 
   244     if(SDL_MUSTLOCK(surface))
   245         SDL_LockSurface(surface);
   246     src = (Uint8 *) pixels;
   247     dst = (Uint8 *) surface->pixels +
   248                         rect->y * surface->pitch +
   249                         rect->x * surface->format->BytesPerPixel;
   250     length = rect->w * surface->format->BytesPerPixel;
   251     for (row = 0; row < rect->h; ++row) {
   252         SDL_memcpy(dst, src, length);
   253         src += pitch;
   254         dst += surface->pitch;
   255     }
   256     if(SDL_MUSTLOCK(surface))
   257         SDL_UnlockSurface(surface);
   258     return 0;
   259 }
   260 
   261 static int
   262 SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   263                const SDL_Rect * rect, void **pixels, int *pitch)
   264 {
   265     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   266 
   267     *pixels =
   268         (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
   269                   rect->x * surface->format->BytesPerPixel);
   270     *pitch = surface->pitch;
   271     return 0;
   272 }
   273 
   274 static void
   275 SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   276 {
   277 }
   278 
   279 static int
   280 SW_UpdateViewport(SDL_Renderer * renderer)
   281 {
   282     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   283     SDL_Surface *surface = data->surface;
   284 
   285     if (!surface) {
   286         /* We'll update the viewport after we recreate the surface */
   287         return 0;
   288     }
   289 
   290     if (!renderer->viewport.w && !renderer->viewport.h) {
   291         /* There may be no window, so update the viewport directly */
   292         renderer->viewport.w = surface->w;
   293         renderer->viewport.h = surface->h;
   294     }
   295     SDL_SetClipRect(data->surface, &renderer->viewport);
   296     return 0;
   297 }
   298 
   299 static int
   300 SW_RenderClear(SDL_Renderer * renderer)
   301 {
   302     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   303     Uint32 color;
   304     SDL_Rect clip_rect;
   305 
   306     if (!surface) {
   307         return -1;
   308     }
   309 
   310     color = SDL_MapRGBA(surface->format,
   311                         renderer->r, renderer->g, renderer->b, renderer->a);
   312 
   313     /* By definition the clear ignores the clip rect */
   314     clip_rect = surface->clip_rect;
   315     SDL_SetClipRect(surface, NULL);
   316     SDL_FillRect(surface, NULL, color);
   317     SDL_SetClipRect(surface, &clip_rect);
   318     return 0;
   319 }
   320 
   321 static int
   322 SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   323                     int count)
   324 {
   325     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   326     SDL_Point *temp = NULL;
   327     int status;
   328 
   329     if (!surface) {
   330         return -1;
   331     }
   332 
   333     if (renderer->viewport.x || renderer->viewport.y) {
   334         int i;
   335         int x = renderer->viewport.x;
   336         int y = renderer->viewport.y;
   337 
   338         temp = SDL_stack_alloc(SDL_Point, count);
   339         for (i = 0; i < count; ++i) {
   340             temp[i].x = x + points[i].x;
   341             temp[i].y = y + points[i].x;
   342         }
   343         points = temp;
   344     }
   345 
   346     /* Draw the points! */
   347     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   348         Uint32 color = SDL_MapRGBA(surface->format,
   349                                    renderer->r, renderer->g, renderer->b,
   350                                    renderer->a);
   351 
   352         status = SDL_DrawPoints(surface, points, count, color);
   353     } else {
   354         status = SDL_BlendPoints(surface, points, count,
   355                                 renderer->blendMode,
   356                                 renderer->r, renderer->g, renderer->b,
   357                                 renderer->a);
   358     }
   359 
   360     if (temp) {
   361         SDL_stack_free(temp);
   362     }
   363     return status;
   364 }
   365 
   366 static int
   367 SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   368                    int count)
   369 {
   370     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   371     SDL_Point *temp = NULL;
   372     int status;
   373 
   374     if (!surface) {
   375         return -1;
   376     }
   377 
   378     if (renderer->viewport.x || renderer->viewport.y) {
   379         int i;
   380         int x = renderer->viewport.x;
   381         int y = renderer->viewport.y;
   382 
   383         temp = SDL_stack_alloc(SDL_Point, count);
   384         for (i = 0; i < count; ++i) {
   385             temp[i].x = x + points[i].x;
   386             temp[i].y = y + points[i].y;
   387         }
   388         points = temp;
   389     }
   390 
   391     /* Draw the lines! */
   392     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   393         Uint32 color = SDL_MapRGBA(surface->format,
   394                                    renderer->r, renderer->g, renderer->b,
   395                                    renderer->a);
   396 
   397         status = SDL_DrawLines(surface, points, count, color);
   398     } else {
   399         status = SDL_BlendLines(surface, points, count,
   400                                 renderer->blendMode,
   401                                 renderer->r, renderer->g, renderer->b,
   402                                 renderer->a);
   403     }
   404 
   405     if (temp) {
   406         SDL_stack_free(temp);
   407     }
   408     return status;
   409 }
   410 
   411 static int
   412 SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count)
   413 {
   414     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   415     SDL_Rect *temp = NULL;
   416     int status;
   417 
   418     if (!surface) {
   419         return -1;
   420     }
   421 
   422     if (renderer->viewport.x || renderer->viewport.y) {
   423         int i;
   424         int x = renderer->viewport.x;
   425         int y = renderer->viewport.y;
   426 
   427         temp = SDL_stack_alloc(SDL_Rect, count);
   428         for (i = 0; i < count; ++i) {
   429             temp[i].x = x + rects[i].x;
   430             temp[i].y = y + rects[i].y;
   431             temp[i].w = rects[i].w;
   432             temp[i].h = rects[i].h;
   433         }
   434         rects = temp;
   435     }
   436 
   437     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   438         Uint32 color = SDL_MapRGBA(surface->format,
   439                                    renderer->r, renderer->g, renderer->b,
   440                                    renderer->a);
   441         status = SDL_FillRects(surface, rects, count, color);
   442     } else {
   443         status = SDL_BlendFillRects(surface, rects, count,
   444                                     renderer->blendMode,
   445                                     renderer->r, renderer->g, renderer->b,
   446                                     renderer->a);
   447     }
   448 
   449     if (temp) {
   450         SDL_stack_free(temp);
   451     }
   452     return status;
   453 }
   454 
   455 static int
   456 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   457               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   458 {
   459     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   460     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   461     SDL_Rect final_rect = *dstrect;
   462 
   463     if (!surface) {
   464         return -1;
   465     }
   466 
   467     if (renderer->viewport.x || renderer->viewport.y) {
   468         final_rect.x += renderer->viewport.x;
   469         final_rect.y += renderer->viewport.y;
   470     }
   471     if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {
   472         return SDL_BlitSurface(src, srcrect, surface, &final_rect);
   473     } else {
   474         return SDL_BlitScaled(src, srcrect, surface, &final_rect);
   475     }
   476 }
   477 
   478 static int
   479 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   480                     Uint32 format, void * pixels, int pitch)
   481 {
   482     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   483     Uint32 src_format;
   484     void *src_pixels;
   485     SDL_Rect final_rect;
   486 
   487     if (!surface) {
   488         return -1;
   489     }
   490 
   491     if (renderer->viewport.x || renderer->viewport.y) {
   492         final_rect.x = renderer->viewport.x + rect->x;
   493         final_rect.y = renderer->viewport.y + rect->y;
   494         final_rect.w = rect->w;
   495         final_rect.h = rect->h;
   496         rect = &final_rect;
   497     }
   498 
   499     if (rect->x < 0 || rect->x+rect->w > surface->w ||
   500         rect->y < 0 || rect->y+rect->h > surface->h) {
   501         SDL_SetError("Tried to read outside of surface bounds");
   502         return -1;
   503     }
   504 
   505     src_format = surface->format->format;
   506     src_pixels = (void*)((Uint8 *) surface->pixels +
   507                     rect->y * surface->pitch +
   508                     rect->x * surface->format->BytesPerPixel);
   509 
   510     return SDL_ConvertPixels(rect->w, rect->h,
   511                              src_format, src_pixels, surface->pitch,
   512                              format, pixels, pitch);
   513 }
   514 
   515 static void
   516 SW_RenderPresent(SDL_Renderer * renderer)
   517 {
   518     SDL_Window *window = renderer->window;
   519 
   520     if (window) {
   521         SDL_UpdateWindowSurface(window);
   522     }
   523 }
   524 
   525 static void
   526 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   527 {
   528     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   529 
   530     SDL_FreeSurface(surface);
   531 }
   532 
   533 static void
   534 SW_DestroyRenderer(SDL_Renderer * renderer)
   535 {
   536     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   537 
   538     if (data) {
   539         SDL_free(data);
   540     }
   541     SDL_free(renderer);
   542 }
   543 
   544 #endif /* !SDL_RENDER_DISABLED */
   545 
   546 /* vi: set ts=4 sw=4 expandtab: */