src/render/software/SDL_render_sw.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 08 Feb 2011 10:04:09 -0800
changeset 5226 710d00cb3a6a
parent 5224 2178ffe17222
child 5262 b530ef003506
permissions -rw-r--r--
Made it possible to disable the rendering subsystem with configure --disable-render
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 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_RENDER_DISABLED
    25 
    26 #include "../SDL_sysrender.h"
    27 #include "../../video/SDL_pixels_c.h"
    28 
    29 #include "SDL_draw.h"
    30 #include "SDL_blendfillrect.h"
    31 #include "SDL_blendline.h"
    32 #include "SDL_blendpoint.h"
    33 #include "SDL_drawline.h"
    34 #include "SDL_drawpoint.h"
    35 
    36 
    37 /* SDL surface based renderer implementation */
    38 
    39 static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags);
    40 static void SW_WindowEvent(SDL_Renderer * renderer,
    41                            const SDL_WindowEvent *event);
    42 static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    43 static int SW_SetTextureColorMod(SDL_Renderer * renderer,
    44                                  SDL_Texture * texture);
    45 static int SW_SetTextureAlphaMod(SDL_Renderer * renderer,
    46                                  SDL_Texture * texture);
    47 static int SW_SetTextureBlendMode(SDL_Renderer * renderer,
    48                                   SDL_Texture * texture);
    49 static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    50                             const SDL_Rect * rect, const void *pixels,
    51                             int pitch);
    52 static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    53                           const SDL_Rect * rect, void **pixels, int *pitch);
    54 static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    55 static void SW_SetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect);
    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      0,
    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_bool updateSize;
    94     SDL_Surface *surface;
    95 } SW_RenderData;
    96 
    97 
    98 SDL_Renderer *
    99 SW_CreateRendererForSurface(SDL_Surface * surface)
   100 {
   101     SDL_Renderer *renderer;
   102     SW_RenderData *data;
   103 
   104     if (!surface) {
   105         SDL_SetError("Can't create renderer for NULL surface");
   106         return NULL;
   107     }
   108 
   109     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   110     if (!renderer) {
   111         SDL_OutOfMemory();
   112         return NULL;
   113     }
   114 
   115     data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
   116     if (!data) {
   117         SW_DestroyRenderer(renderer);
   118         SDL_OutOfMemory();
   119         return NULL;
   120     }
   121     data->surface = surface;
   122 
   123     renderer->WindowEvent = SW_WindowEvent;
   124     renderer->CreateTexture = SW_CreateTexture;
   125     renderer->SetTextureColorMod = SW_SetTextureColorMod;
   126     renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
   127     renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
   128     renderer->UpdateTexture = SW_UpdateTexture;
   129     renderer->LockTexture = SW_LockTexture;
   130     renderer->UnlockTexture = SW_UnlockTexture;
   131     renderer->SetClipRect = SW_SetClipRect;
   132     renderer->DestroyTexture = SW_DestroyTexture;
   133     renderer->RenderDrawPoints = SW_RenderDrawPoints;
   134     renderer->RenderDrawLines = SW_RenderDrawLines;
   135     renderer->RenderFillRects = SW_RenderFillRects;
   136     renderer->RenderCopy = SW_RenderCopy;
   137     renderer->RenderReadPixels = SW_RenderReadPixels;
   138     renderer->RenderPresent = SW_RenderPresent;
   139     renderer->DestroyRenderer = SW_DestroyRenderer;
   140     renderer->info = SW_RenderDriver.info;
   141     renderer->driverdata = data;
   142 
   143     return renderer;
   144 }
   145 
   146 SDL_Renderer *
   147 SW_CreateRenderer(SDL_Window * window, Uint32 flags)
   148 {
   149     SDL_Surface *surface;
   150 
   151     surface = SDL_GetWindowSurface(window);
   152     if (!surface) {
   153         return NULL;
   154     }
   155     return SW_CreateRendererForSurface(surface);
   156 }
   157 
   158 static SDL_Surface *
   159 SW_ActivateRenderer(SDL_Renderer * renderer)
   160 {
   161     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   162     SDL_Window *window = renderer->window;
   163 
   164     if (data->updateSize) {
   165         data->surface = SDL_GetWindowSurface(window);
   166         data->updateSize = SDL_FALSE;
   167     }
   168     return data->surface;
   169 }
   170 
   171 static void
   172 SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   173 {
   174     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   175 
   176     if (event->event == SDL_WINDOWEVENT_RESIZED) {
   177         data->updateSize = SDL_TRUE;
   178     }
   179 }
   180 
   181 static int
   182 SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   183 {
   184     int bpp;
   185     Uint32 Rmask, Gmask, Bmask, Amask;
   186 
   187     if (!SDL_PixelFormatEnumToMasks
   188         (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   189         SDL_SetError("Unknown texture format");
   190         return -1;
   191     }
   192 
   193     texture->driverdata =
   194         SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
   195                              Bmask, Amask);
   196     SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
   197                            texture->b);
   198     SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
   199     SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
   200 
   201     if (texture->access == SDL_TEXTUREACCESS_STATIC) {
   202         SDL_SetSurfaceRLE(texture->driverdata, 1);
   203     }
   204 
   205     if (!texture->driverdata) {
   206         return -1;
   207     }
   208     return 0;
   209 }
   210 
   211 static int
   212 SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   213 {
   214     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   215     return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
   216                                   texture->b);
   217 }
   218 
   219 static int
   220 SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   221 {
   222     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   223     return SDL_SetSurfaceAlphaMod(surface, texture->a);
   224 }
   225 
   226 static int
   227 SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   228 {
   229     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   230     return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
   231 }
   232 
   233 static int
   234 SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   235                  const SDL_Rect * rect, const void *pixels, int pitch)
   236 {
   237     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   238     Uint8 *src, *dst;
   239     int row;
   240     size_t length;
   241 
   242     src = (Uint8 *) pixels;
   243     dst = (Uint8 *) surface->pixels +
   244                         rect->y * surface->pitch +
   245                         rect->x * surface->format->BytesPerPixel;
   246     length = rect->w * surface->format->BytesPerPixel;
   247     for (row = 0; row < rect->h; ++row) {
   248         SDL_memcpy(dst, src, length);
   249         src += pitch;
   250         dst += surface->pitch;
   251     }
   252     return 0;
   253 }
   254 
   255 static int
   256 SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   257                const SDL_Rect * rect, void **pixels, int *pitch)
   258 {
   259     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   260 
   261     *pixels =
   262         (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
   263                   rect->x * surface->format->BytesPerPixel);
   264     *pitch = surface->pitch;
   265     return 0;
   266 }
   267 
   268 static void
   269 SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   270 {
   271 }
   272 
   273 static void
   274 SW_SetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
   275 {
   276     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   277 
   278     if (!surface) {
   279         return;
   280     }
   281     SDL_SetClipRect(surface, rect);
   282 }
   283 
   284 static int
   285 SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   286                     int count)
   287 {
   288     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   289 
   290     if (!surface) {
   291         return -1;
   292     }
   293 
   294     /* Draw the points! */
   295     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   296         Uint32 color = SDL_MapRGBA(surface->format,
   297                                    renderer->r, renderer->g, renderer->b,
   298                                    renderer->a);
   299 
   300         return SDL_DrawPoints(surface, points, count, color);
   301     } else {
   302         return SDL_BlendPoints(surface, points, count,
   303                                renderer->blendMode,
   304                                renderer->r, renderer->g, renderer->b,
   305                                renderer->a);
   306     }
   307 }
   308 
   309 static int
   310 SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   311                    int count)
   312 {
   313     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   314 
   315     if (!surface) {
   316         return -1;
   317     }
   318 
   319     /* Draw the lines! */
   320     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   321         Uint32 color = SDL_MapRGBA(surface->format,
   322                                    renderer->r, renderer->g, renderer->b,
   323                                    renderer->a);
   324 
   325         return SDL_DrawLines(surface, points, count, color);
   326     } else {
   327         return SDL_BlendLines(surface, points, count,
   328                               renderer->blendMode,
   329                               renderer->r, renderer->g, renderer->b,
   330                               renderer->a);
   331     }
   332 }
   333 
   334 static int
   335 SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
   336                    int count)
   337 {
   338     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   339 
   340     if (!surface) {
   341         return -1;
   342     }
   343 
   344     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
   345         Uint32 color = SDL_MapRGBA(surface->format,
   346                                    renderer->r, renderer->g, renderer->b,
   347                                    renderer->a);
   348         return SDL_FillRects(surface, rects, count, color);
   349     } else {
   350         return SDL_BlendFillRects(surface, rects, count,
   351                                      renderer->blendMode,
   352                                      renderer->r, renderer->g, renderer->b,
   353                                      renderer->a);
   354     }
   355 }
   356 
   357 static int
   358 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   359               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   360 {
   361     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   362     SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   363     SDL_Rect final_rect = *dstrect;
   364 
   365     if (!surface) {
   366         return -1;
   367     }
   368     return SDL_BlitSurface(src, srcrect, surface, &final_rect);
   369 }
   370 
   371 static int
   372 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   373                     Uint32 format, void * pixels, int pitch)
   374 {
   375     SDL_Surface *surface = SW_ActivateRenderer(renderer);
   376     Uint32 src_format;
   377     void *src_pixels;
   378 
   379     if (!surface) {
   380         return -1;
   381     }
   382 
   383     if (rect->x < 0 || rect->x+rect->w > surface->w ||
   384         rect->y < 0 || rect->y+rect->h > surface->h) {
   385         SDL_SetError("Tried to read outside of surface bounds");
   386         return -1;
   387     }
   388 
   389     src_format = SDL_MasksToPixelFormatEnum(
   390                     surface->format->BitsPerPixel,
   391                     surface->format->Rmask, surface->format->Gmask,
   392                     surface->format->Bmask, surface->format->Amask);
   393 
   394     src_pixels = (void*)((Uint8 *) surface->pixels +
   395                     rect->y * surface->pitch +
   396                     rect->x * surface->format->BytesPerPixel);
   397 
   398     return SDL_ConvertPixels(rect->w, rect->h,
   399                              src_format, src_pixels, surface->pitch,
   400                              format, pixels, pitch);
   401 }
   402 
   403 static void
   404 SW_RenderPresent(SDL_Renderer * renderer)
   405 {
   406     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   407     SDL_Window *window = renderer->window;
   408 
   409     if (window) {
   410         SDL_UpdateWindowSurface(window);
   411     }
   412 }
   413 
   414 static void
   415 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   416 {
   417     SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
   418 
   419     SDL_FreeSurface(surface);
   420 }
   421 
   422 static void
   423 SW_DestroyRenderer(SDL_Renderer * renderer)
   424 {
   425     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
   426 
   427     if (data) {
   428         SDL_free(data);
   429     }
   430     SDL_free(renderer);
   431 }
   432 
   433 #endif /* !SDL_RENDER_DISABLED */
   434 
   435 /* vi: set ts=4 sw=4 expandtab: */