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