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