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