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