src/render/software/SDL_renderer_sw.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 03 Feb 2011 00:19:40 -0800
changeset 5156 307ccc9c135e
parent 5154 fb424691cfc7
child 5157 657543cc92f9
permissions -rw-r--r--
Made it possible to create a texture of any format, even if not supported by the renderer.
This allows me to reduce the set of formats supported by the renderers to the most optimal set, for a nice speed boost.
slouken@1895
     1
/*
slouken@1895
     2
    SDL - Simple DirectMedia Layer
slouken@3697
     3
    Copyright (C) 1997-2010 Sam Lantinga
slouken@1895
     4
slouken@1895
     5
    This library is free software; you can redistribute it and/or
slouken@1895
     6
    modify it under the terms of the GNU Lesser General Public
slouken@1895
     7
    License as published by the Free Software Foundation; either
slouken@1895
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@1895
     9
slouken@1895
    10
    This library is distributed in the hope that it will be useful,
slouken@1895
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@1895
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1895
    13
    Lesser General Public License for more details.
slouken@1895
    14
slouken@1895
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1895
    16
    License along with this library; if not, write to the Free Software
slouken@1895
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@1895
    18
slouken@1895
    19
    Sam Lantinga
slouken@1895
    20
    slouken@libsdl.org
slouken@1895
    21
*/
slouken@1895
    22
#include "SDL_config.h"
slouken@1895
    23
slouken@5154
    24
#include "../SDL_sysrender.h"
slouken@5154
    25
#include "../../video/SDL_pixels_c.h"
slouken@1895
    26
slouken@1895
    27
slouken@1895
    28
/* SDL surface based renderer implementation */
slouken@1895
    29
slouken@1918
    30
static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags);
slouken@5147
    31
static void SW_WindowEvent(SDL_Renderer * renderer,
slouken@5147
    32
                           const SDL_WindowEvent *event);
slouken@1918
    33
static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1985
    34
static int SW_SetTextureColorMod(SDL_Renderer * renderer,
slouken@1985
    35
                                 SDL_Texture * texture);
slouken@1985
    36
static int SW_SetTextureAlphaMod(SDL_Renderer * renderer,
slouken@1985
    37
                                 SDL_Texture * texture);
slouken@5141
    38
static int SW_SetTextureBlendMode(SDL_Renderer * renderer,
slouken@5141
    39
                                  SDL_Texture * texture);
slouken@1985
    40
static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1985
    41
                            const SDL_Rect * rect, const void *pixels,
slouken@1985
    42
                            int pitch);
slouken@1918
    43
static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
    44
                          const SDL_Rect * rect, void **pixels, int *pitch);
slouken@1918
    45
static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@3596
    46
static int SW_RenderDrawPoints(SDL_Renderer * renderer,
slouken@3596
    47
                               const SDL_Point * points, int count);
slouken@3596
    48
static int SW_RenderDrawLines(SDL_Renderer * renderer,
slouken@3596
    49
                              const SDL_Point * points, int count);
slouken@3596
    50
static int SW_RenderFillRects(SDL_Renderer * renderer,
slouken@3596
    51
                              const SDL_Rect ** rects, int count);
slouken@1918
    52
static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1985
    53
                         const SDL_Rect * srcrect, const SDL_Rect * dstrect);
slouken@3427
    54
static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
    55
                               Uint32 format, void * pixels, int pitch);
slouken@3427
    56
static int SW_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
    57
                                Uint32 format, const void * pixels, int pitch);
slouken@1918
    58
static void SW_RenderPresent(SDL_Renderer * renderer);
slouken@1918
    59
static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1918
    60
static void SW_DestroyRenderer(SDL_Renderer * renderer);
slouken@1895
    61
slouken@1895
    62
slouken@1918
    63
SDL_RenderDriver SW_RenderDriver = {
slouken@1918
    64
    SW_CreateRenderer,
slouken@1895
    65
    {
slouken@1895
    66
     "software",
slouken@5142
    67
     (SDL_RENDERER_PRESENTVSYNC),
slouken@5156
    68
     8,
slouken@1895
    69
     {
slouken@1965
    70
      SDL_PIXELFORMAT_RGB555,
slouken@1965
    71
      SDL_PIXELFORMAT_RGB565,
slouken@1965
    72
      SDL_PIXELFORMAT_RGB888,
slouken@1965
    73
      SDL_PIXELFORMAT_BGR888,
slouken@1965
    74
      SDL_PIXELFORMAT_ARGB8888,
slouken@1965
    75
      SDL_PIXELFORMAT_RGBA8888,
slouken@1965
    76
      SDL_PIXELFORMAT_ABGR8888,
slouken@5156
    77
      SDL_PIXELFORMAT_BGRA8888
slouken@5156
    78
     },
slouken@1895
    79
     0,
slouken@1895
    80
     0}
slouken@1895
    81
};
slouken@1895
    82
slouken@1895
    83
typedef struct
slouken@1895
    84
{
slouken@1907
    85
    Uint32 format;
slouken@1972
    86
    SDL_bool updateSize;
slouken@5142
    87
    SDL_Texture *texture;
slouken@1907
    88
    SDL_Surface surface;
slouken@1895
    89
    SDL_Renderer *renderer;
slouken@1918
    90
} SW_RenderData;
slouken@1895
    91
slouken@1907
    92
static SDL_Texture *
slouken@1907
    93
CreateTexture(SDL_Renderer * renderer, Uint32 format, int w, int h)
slouken@1907
    94
{
slouken@1907
    95
    SDL_Texture *texture;
slouken@1907
    96
slouken@1920
    97
    texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
slouken@1907
    98
    if (!texture) {
slouken@1907
    99
        SDL_OutOfMemory();
slouken@1907
   100
        return NULL;
slouken@1907
   101
    }
slouken@1907
   102
slouken@1907
   103
    texture->format = format;
slouken@2222
   104
    texture->access = SDL_TEXTUREACCESS_STREAMING;
slouken@1907
   105
    texture->w = w;
slouken@1907
   106
    texture->h = h;
slouken@1907
   107
    texture->renderer = renderer;
slouken@1907
   108
slouken@1907
   109
    if (renderer->CreateTexture(renderer, texture) < 0) {
slouken@1907
   110
        SDL_free(texture);
slouken@1907
   111
        return NULL;
slouken@1907
   112
    }
slouken@1907
   113
    return texture;
slouken@1907
   114
}
slouken@1907
   115
slouken@1907
   116
static void
slouken@1907
   117
DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1907
   118
{
slouken@1907
   119
    renderer->DestroyTexture(renderer, texture);
slouken@1907
   120
    SDL_free(texture);
slouken@1907
   121
}
slouken@1907
   122
slouken@1895
   123
SDL_Renderer *
slouken@1918
   124
SW_CreateRenderer(SDL_Window * window, Uint32 flags)
slouken@1895
   125
{
slouken@1895
   126
    SDL_Renderer *renderer;
slouken@1918
   127
    SW_RenderData *data;
slouken@5154
   128
    int i;
slouken@5156
   129
    int w, h;
slouken@5154
   130
    Uint32 format;
slouken@1895
   131
    int bpp;
slouken@1895
   132
    Uint32 Rmask, Gmask, Bmask, Amask;
slouken@1907
   133
    Uint32 renderer_flags;
slouken@1929
   134
    const char *desired_driver;
slouken@1895
   135
slouken@5154
   136
    format = SDL_GetWindowPixelFormat(window);
slouken@1895
   137
    if (!SDL_PixelFormatEnumToMasks
slouken@5154
   138
        (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
slouken@1895
   139
        SDL_SetError("Unknown display format");
slouken@1895
   140
        return NULL;
slouken@1895
   141
    }
slouken@1895
   142
slouken@1895
   143
    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
slouken@1895
   144
    if (!renderer) {
slouken@1895
   145
        SDL_OutOfMemory();
slouken@1895
   146
        return NULL;
slouken@1895
   147
    }
slouken@1895
   148
slouken@1920
   149
    data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
slouken@1895
   150
    if (!data) {
slouken@1918
   151
        SW_DestroyRenderer(renderer);
slouken@1895
   152
        SDL_OutOfMemory();
slouken@1895
   153
        return NULL;
slouken@1895
   154
    }
slouken@5147
   155
    renderer->WindowEvent = SW_WindowEvent;
slouken@5154
   156
    renderer->CreateTexture = SW_CreateTexture;
slouken@5154
   157
    renderer->SetTextureColorMod = SW_SetTextureColorMod;
slouken@5154
   158
    renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
slouken@5154
   159
    renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
slouken@5154
   160
    renderer->UpdateTexture = SW_UpdateTexture;
slouken@5154
   161
    renderer->LockTexture = SW_LockTexture;
slouken@5154
   162
    renderer->UnlockTexture = SW_UnlockTexture;
slouken@5154
   163
    renderer->DestroyTexture = SW_DestroyTexture;
slouken@3596
   164
    renderer->RenderDrawPoints = SW_RenderDrawPoints;
slouken@3596
   165
    renderer->RenderDrawLines = SW_RenderDrawLines;
slouken@3596
   166
    renderer->RenderFillRects = SW_RenderFillRects;
slouken@1918
   167
    renderer->RenderCopy = SW_RenderCopy;
slouken@3427
   168
    renderer->RenderReadPixels = SW_RenderReadPixels;
slouken@3427
   169
    renderer->RenderWritePixels = SW_RenderWritePixels;
slouken@1918
   170
    renderer->RenderPresent = SW_RenderPresent;
slouken@1918
   171
    renderer->DestroyRenderer = SW_DestroyRenderer;
slouken@5154
   172
    renderer->info = SW_RenderDriver.info;
slouken@2227
   173
    renderer->info.flags = 0;
slouken@3685
   174
    renderer->window = window;
slouken@1895
   175
    renderer->driverdata = data;
slouken@1895
   176
slouken@5154
   177
    data->format = format;
slouken@1895
   178
slouken@1895
   179
    /* Find a render driver that we can use to display data */
slouken@5142
   180
    renderer_flags = 0;
slouken@1965
   181
    if (flags & SDL_RENDERER_PRESENTVSYNC) {
slouken@1965
   182
        renderer_flags |= SDL_RENDERER_PRESENTVSYNC;
slouken@1907
   183
    }
slouken@1929
   184
    desired_driver = SDL_getenv("SDL_VIDEO_RENDERER_SWDRIVER");
slouken@5154
   185
    for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
slouken@5154
   186
        SDL_RendererInfo info;
slouken@5154
   187
        SDL_GetRenderDriverInfo(i, &info);
slouken@5154
   188
        if (SDL_strcmp(info.name, SW_RenderDriver.info.name) == 0) {
slouken@1929
   189
            continue;
slouken@1929
   190
        }
slouken@1929
   191
        if (desired_driver
slouken@5154
   192
            && SDL_strcasecmp(desired_driver, info.name) != 0) {
slouken@1929
   193
            continue;
slouken@1929
   194
        }
slouken@5154
   195
        data->renderer = SDL_CreateRenderer(window, i, renderer_flags);
slouken@1929
   196
        if (data->renderer) {
slouken@1929
   197
            break;
slouken@1895
   198
        }
slouken@1895
   199
    }
slouken@5154
   200
    if (i == SDL_GetNumRenderDrivers()) {
slouken@1918
   201
        SW_DestroyRenderer(renderer);
slouken@1895
   202
        SDL_SetError("Couldn't find display render driver");
slouken@1895
   203
        return NULL;
slouken@1895
   204
    }
slouken@1965
   205
    if (data->renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) {
slouken@1965
   206
        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
slouken@1907
   207
    }
slouken@1907
   208
slouken@1907
   209
    /* Create the textures we'll use for display */
slouken@5156
   210
    SDL_GetWindowSize(window, &w, &h);
slouken@5156
   211
    data->texture = CreateTexture(data->renderer, data->format, w, h);
slouken@5142
   212
    if (!data->texture) {
slouken@5142
   213
        SW_DestroyRenderer(renderer);
slouken@5142
   214
        return NULL;
slouken@1907
   215
    }
slouken@1907
   216
slouken@1907
   217
    /* Create a surface we'll use for rendering */
slouken@1907
   218
    data->surface.flags = SDL_PREALLOC;
slouken@1907
   219
    data->surface.format = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask);
slouken@1907
   220
    if (!data->surface.format) {
slouken@1918
   221
        SW_DestroyRenderer(renderer);
slouken@1907
   222
        return NULL;
slouken@1907
   223
    }
slouken@1907
   224
slouken@1895
   225
    return renderer;
slouken@1895
   226
}
slouken@1895
   227
slouken@5147
   228
static SDL_Texture *
slouken@1970
   229
SW_ActivateRenderer(SDL_Renderer * renderer)
slouken@1970
   230
{
slouken@1970
   231
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@3685
   232
    SDL_Window *window = renderer->window;
slouken@1970
   233
slouken@1972
   234
    if (data->updateSize) {
slouken@1972
   235
        /* Recreate the textures for the new window size */
slouken@5156
   236
        int w, h;
slouken@5142
   237
        if (data->texture) {
slouken@5142
   238
            DestroyTexture(data->renderer, data->texture);
slouken@1972
   239
        }
slouken@5156
   240
        SDL_GetWindowSize(window, &w, &h);
slouken@5156
   241
        data->texture = CreateTexture(data->renderer, data->format, w, h);
slouken@5147
   242
        if (data->texture) {
slouken@5147
   243
            data->updateSize = SDL_FALSE;
slouken@1972
   244
        }
slouken@1972
   245
    }
slouken@5147
   246
    return data->texture;
slouken@1970
   247
}
slouken@1970
   248
slouken@5147
   249
static void
slouken@5147
   250
SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
slouken@1970
   251
{
slouken@1970
   252
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@1970
   253
slouken@5147
   254
    if (event->event == SDL_WINDOWEVENT_RESIZED) {
slouken@5147
   255
        data->updateSize = SDL_TRUE;
slouken@1970
   256
    }
slouken@1970
   257
}
slouken@1970
   258
slouken@1970
   259
static int
slouken@1918
   260
SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
   261
{
slouken@5156
   262
    int bpp;
slouken@5156
   263
    Uint32 Rmask, Gmask, Bmask, Amask;
slouken@1895
   264
slouken@5156
   265
    if (!SDL_PixelFormatEnumToMasks
slouken@5156
   266
        (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
slouken@5156
   267
        SDL_SetError("Unknown texture format");
slouken@5156
   268
        return -1;
slouken@5156
   269
    }
slouken@1895
   270
slouken@5156
   271
    texture->driverdata =
slouken@5156
   272
        SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
slouken@5156
   273
                             Bmask, Amask);
slouken@5156
   274
    SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
slouken@5156
   275
                           texture->b);
slouken@5156
   276
    SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
slouken@5156
   277
    SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
slouken@3053
   278
slouken@5156
   279
    if (texture->access == SDL_TEXTUREACCESS_STATIC) {
slouken@5156
   280
        SDL_SetSurfaceRLE(texture->driverdata, 1);
slouken@1895
   281
    }
slouken@1895
   282
slouken@1895
   283
    if (!texture->driverdata) {
slouken@1895
   284
        return -1;
slouken@1895
   285
    }
slouken@1895
   286
    return 0;
slouken@1895
   287
}
slouken@1895
   288
slouken@1895
   289
static int
slouken@1985
   290
SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1985
   291
{
slouken@2267
   292
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@2267
   293
    return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
slouken@2267
   294
                                  texture->b);
slouken@1985
   295
}
slouken@1985
   296
slouken@1985
   297
static int
slouken@1985
   298
SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1985
   299
{
slouken@2267
   300
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@2267
   301
    return SDL_SetSurfaceAlphaMod(surface, texture->a);
slouken@1985
   302
}
slouken@1985
   303
slouken@1985
   304
static int
slouken@1985
   305
SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1985
   306
{
slouken@2267
   307
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@2267
   308
    return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
slouken@1985
   309
}
slouken@1985
   310
slouken@1985
   311
static int
slouken@1918
   312
SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
   313
                 const SDL_Rect * rect, const void *pixels, int pitch)
slouken@1895
   314
{
slouken@5156
   315
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@5156
   316
    Uint8 *src, *dst;
slouken@5156
   317
    int row;
slouken@5156
   318
    size_t length;
slouken@1895
   319
slouken@5156
   320
    src = (Uint8 *) pixels;
slouken@5156
   321
    dst = (Uint8 *) surface->pixels +
slouken@5156
   322
                        rect->y * surface->pitch +
slouken@5156
   323
                        rect->x * surface->format->BytesPerPixel;
slouken@5156
   324
    length = rect->w * surface->format->BytesPerPixel;
slouken@5156
   325
    for (row = 0; row < rect->h; ++row) {
slouken@5156
   326
        SDL_memcpy(dst, src, length);
slouken@5156
   327
        src += pitch;
slouken@5156
   328
        dst += surface->pitch;
slouken@1895
   329
    }
slouken@5156
   330
    return 0;
slouken@1895
   331
}
slouken@1895
   332
slouken@1895
   333
static int
slouken@1918
   334
SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
   335
               const SDL_Rect * rect, void **pixels, int *pitch)
slouken@1895
   336
{
slouken@5156
   337
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@1895
   338
slouken@5156
   339
    *pixels =
slouken@5156
   340
        (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
slouken@5156
   341
                  rect->x * surface->format->BytesPerPixel);
slouken@5156
   342
    *pitch = surface->pitch;
slouken@5156
   343
    return 0;
slouken@1895
   344
}
slouken@1895
   345
slouken@1895
   346
static void
slouken@1918
   347
SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
   348
{
slouken@1895
   349
}
slouken@1895
   350
slouken@1895
   351
static int
slouken@3596
   352
SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
slouken@3596
   353
                    int count)
slouken@2901
   354
{
slouken@2901
   355
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@5147
   356
    SDL_Texture *texture = SW_ActivateRenderer(renderer);
slouken@2904
   357
    SDL_Rect rect;
slouken@3536
   358
    int i;
slouken@3536
   359
    int x, y;
slouken@3536
   360
    int status = 0;
slouken@2901
   361
slouken@5147
   362
    if (!texture) {
slouken@5147
   363
        return -1;
slouken@5147
   364
    }
slouken@5147
   365
slouken@3536
   366
    /* Get the smallest rectangle that contains everything */
slouken@3536
   367
    rect.x = 0;
slouken@3536
   368
    rect.y = 0;
slouken@3536
   369
    rect.w = texture->w;
slouken@3536
   370
    rect.h = texture->h;
slouken@3536
   371
    if (!SDL_EnclosePoints(points, count, &rect, &rect)) {
slouken@3536
   372
        /* Nothing to draw */
slouken@3536
   373
        return 0;
slouken@2904
   374
    }
slouken@2904
   375
slouken@5156
   376
    if (data->renderer->LockTexture(data->renderer, texture, &rect,
slouken@2891
   377
                                    &data->surface.pixels,
slouken@2888
   378
                                    &data->surface.pitch) < 0) {
slouken@2888
   379
        return -1;
slouken@2888
   380
    }
slouken@2888
   381
slouken@3536
   382
    data->surface.clip_rect.w = data->surface.w = rect.w;
slouken@3536
   383
    data->surface.clip_rect.h = data->surface.h = rect.h;
slouken@2904
   384
slouken@3536
   385
    /* Draw the points! */
slouken@5140
   386
    if (renderer->blendMode == SDL_BLENDMODE_NONE) {
slouken@3536
   387
        Uint32 color = SDL_MapRGBA(data->surface.format,
slouken@3536
   388
                                   renderer->r, renderer->g, renderer->b,
slouken@3536
   389
                                   renderer->a);
slouken@2888
   390
slouken@3536
   391
        for (i = 0; i < count; ++i) {
slouken@3536
   392
            x = points[i].x - rect.x;
slouken@3536
   393
            y = points[i].y - rect.y;
slouken@3536
   394
slouken@3536
   395
            status = SDL_DrawPoint(&data->surface, x, y, color);
slouken@3536
   396
        }
slouken@2888
   397
    } else {
slouken@3536
   398
        for (i = 0; i < count; ++i) {
slouken@3536
   399
            x = points[i].x - rect.x;
slouken@3536
   400
            y = points[i].y - rect.y;
slouken@3536
   401
slouken@3536
   402
            status = SDL_BlendPoint(&data->surface, x, y,
slouken@3536
   403
                                    renderer->blendMode,
slouken@3536
   404
                                    renderer->r, renderer->g, renderer->b,
slouken@3536
   405
                                    renderer->a);
slouken@3536
   406
        }
slouken@2888
   407
    }
slouken@2888
   408
slouken@3536
   409
    data->renderer->UnlockTexture(data->renderer, texture);
slouken@3536
   410
slouken@2888
   411
    return status;
slouken@2888
   412
}
slouken@2888
   413
slouken@2888
   414
static int
slouken@3596
   415
SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
slouken@3596
   416
                   int count)
slouken@1895
   417
{
slouken@1918
   418
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@5147
   419
    SDL_Texture *texture = SW_ActivateRenderer(renderer);
slouken@3536
   420
    SDL_Rect clip, rect;
slouken@3536
   421
    int i;
slouken@3536
   422
    int x1, y1, x2, y2;
slouken@3536
   423
    int status = 0;
slouken@3536
   424
slouken@5147
   425
    if (!texture) {
slouken@5147
   426
        return -1;
slouken@5147
   427
    }
slouken@5147
   428
slouken@3536
   429
    /* Get the smallest rectangle that contains everything */
slouken@3536
   430
    clip.x = 0;
slouken@3536
   431
    clip.y = 0;
slouken@3536
   432
    clip.w = texture->w;
slouken@3536
   433
    clip.h = texture->h;
slouken@3536
   434
    SDL_EnclosePoints(points, count, NULL, &rect);
slouken@3536
   435
    if (!SDL_IntersectRect(&rect, &clip, &rect)) {
slouken@3536
   436
        /* Nothing to draw */
slouken@3536
   437
        return 0;
slouken@3536
   438
    }
slouken@1895
   439
slouken@5156
   440
    if (data->renderer->LockTexture(data->renderer, texture, &rect,
slouken@3536
   441
                                    &data->surface.pixels,
slouken@2735
   442
                                    &data->surface.pitch) < 0) {
slouken@1907
   443
        return -1;
slouken@1907
   444
    }
slouken@2888
   445
slouken@3536
   446
    data->surface.clip_rect.w = data->surface.w = rect.w;
slouken@3536
   447
    data->surface.clip_rect.h = data->surface.h = rect.h;
slouken@1907
   448
slouken@3536
   449
    /* Draw the points! */
slouken@5140
   450
    if (renderer->blendMode == SDL_BLENDMODE_NONE) {
slouken@3536
   451
        Uint32 color = SDL_MapRGBA(data->surface.format,
slouken@3536
   452
                                   renderer->r, renderer->g, renderer->b,
slouken@3536
   453
                                   renderer->a);
slouken@2888
   454
slouken@3536
   455
        for (i = 1; i < count; ++i) {
slouken@3536
   456
            x1 = points[i-1].x - rect.x;
slouken@3536
   457
            y1 = points[i-1].y - rect.y;
slouken@3536
   458
            x2 = points[i].x - rect.x;
slouken@3536
   459
            y2 = points[i].y - rect.y;
slouken@3536
   460
slouken@3536
   461
            status = SDL_DrawLine(&data->surface, x1, y1, x2, y2, color);
slouken@3536
   462
        }
slouken@2888
   463
    } else {
slouken@3536
   464
        for (i = 1; i < count; ++i) {
slouken@3536
   465
            x1 = points[i-1].x - rect.x;
slouken@3536
   466
            y1 = points[i-1].y - rect.y;
slouken@3536
   467
            x2 = points[i].x - rect.x;
slouken@3536
   468
            y2 = points[i].y - rect.y;
slouken@3536
   469
slouken@3536
   470
            status = SDL_BlendLine(&data->surface, x1, y1, x2, y2,
slouken@3536
   471
                                   renderer->blendMode,
slouken@3536
   472
                                   renderer->r, renderer->g, renderer->b,
slouken@3536
   473
                                   renderer->a);
slouken@3536
   474
        }
slouken@2888
   475
    }
slouken@1907
   476
slouken@3536
   477
    data->renderer->UnlockTexture(data->renderer, texture);
slouken@3536
   478
slouken@3536
   479
    return status;
slouken@3536
   480
}
slouken@3536
   481
slouken@3536
   482
static int
slouken@3596
   483
SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
slouken@3596
   484
                   int count)
slouken@3536
   485
{
slouken@3536
   486
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@5147
   487
    SDL_Texture *texture = SW_ActivateRenderer(renderer);
slouken@3536
   488
    SDL_Rect clip, rect;
slouken@3536
   489
    Uint32 color = 0;
slouken@3536
   490
    int i;
slouken@3536
   491
    int status = 0;
slouken@3536
   492
slouken@5147
   493
    if (!texture) {
slouken@5147
   494
        return -1;
slouken@5147
   495
    }
slouken@5147
   496
slouken@3536
   497
    clip.x = 0;
slouken@3536
   498
    clip.y = 0;
slouken@3536
   499
    clip.w = texture->w;
slouken@3536
   500
    clip.h = texture->h;
slouken@3536
   501
slouken@5140
   502
    if (renderer->blendMode == SDL_BLENDMODE_NONE) {
slouken@3536
   503
        color = SDL_MapRGBA(data->surface.format,
slouken@3536
   504
                            renderer->r, renderer->g, renderer->b,
slouken@3536
   505
                            renderer->a);
slouken@3536
   506
    }
slouken@3536
   507
slouken@3536
   508
    for (i = 0; i < count; ++i) {
slouken@3536
   509
        if (!SDL_IntersectRect(rects[i], &clip, &rect)) {
slouken@3536
   510
            /* Nothing to draw */
slouken@3536
   511
            continue;
slouken@3536
   512
        }
slouken@3536
   513
slouken@5156
   514
        if (data->renderer->LockTexture(data->renderer, texture, &rect,
slouken@3536
   515
                                        &data->surface.pixels,
slouken@3536
   516
                                        &data->surface.pitch) < 0) {
slouken@3536
   517
            return -1;
slouken@3536
   518
        }
slouken@3536
   519
slouken@3536
   520
        data->surface.clip_rect.w = data->surface.w = rect.w;
slouken@3536
   521
        data->surface.clip_rect.h = data->surface.h = rect.h;
slouken@3536
   522
slouken@5140
   523
        if (renderer->blendMode == SDL_BLENDMODE_NONE) {
slouken@3536
   524
            status = SDL_FillRect(&data->surface, NULL, color);
slouken@3536
   525
        } else {
slouken@3596
   526
            status = SDL_BlendFillRect(&data->surface, NULL,
slouken@3596
   527
                                       renderer->blendMode,
slouken@3596
   528
                                       renderer->r, renderer->g, renderer->b,
slouken@3596
   529
                                       renderer->a);
slouken@3536
   530
        }
slouken@3536
   531
slouken@3536
   532
        data->renderer->UnlockTexture(data->renderer, texture);
slouken@3536
   533
    }
slouken@1907
   534
    return status;
slouken@1895
   535
}
slouken@1895
   536
slouken@1895
   537
static int
slouken@1918
   538
SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1985
   539
              const SDL_Rect * srcrect, const SDL_Rect * dstrect)
slouken@1895
   540
{
slouken@1918
   541
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@5156
   542
    SDL_Surface *surface;
slouken@5156
   543
    SDL_Rect real_srcrect;
slouken@5156
   544
    SDL_Rect real_dstrect;
slouken@1907
   545
    int status;
slouken@1895
   546
slouken@5147
   547
    if (!SW_ActivateRenderer(renderer)) {
slouken@5147
   548
        return -1;
slouken@5147
   549
    }
slouken@5147
   550
slouken@5156
   551
    if (data->renderer->LockTexture(data->renderer, data->texture, dstrect,
slouken@5156
   552
                                    &data->surface.pixels,
slouken@2735
   553
                                    &data->surface.pitch) < 0) {
slouken@1907
   554
        return -1;
slouken@1907
   555
    }
slouken@1907
   556
slouken@5156
   557
    surface = (SDL_Surface *) texture->driverdata;
slouken@5156
   558
    real_srcrect = *srcrect;
slouken@1907
   559
slouken@5156
   560
    data->surface.w = dstrect->w;
slouken@5156
   561
    data->surface.h = dstrect->h;
slouken@5156
   562
    data->surface.clip_rect.w = dstrect->w;
slouken@5156
   563
    data->surface.clip_rect.h = dstrect->h;
slouken@5156
   564
    real_dstrect = data->surface.clip_rect;
slouken@1895
   565
slouken@5156
   566
    status = SDL_LowerBlit(surface, &real_srcrect, &data->surface, &real_dstrect);
slouken@5142
   567
    data->renderer->UnlockTexture(data->renderer, data->texture);
slouken@1907
   568
    return status;
slouken@1895
   569
}
slouken@1895
   570
slouken@3427
   571
static int
slouken@3427
   572
SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
   573
                    Uint32 format, void * pixels, int pitch)
slouken@3427
   574
{
slouken@3427
   575
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@3427
   576
slouken@5147
   577
    if (!SW_ActivateRenderer(renderer)) {
slouken@5147
   578
        return -1;
slouken@5147
   579
    }
slouken@5147
   580
slouken@5156
   581
    if (data->renderer->LockTexture(data->renderer, data->texture, rect,
slouken@5156
   582
                                    &data->surface.pixels,
slouken@3427
   583
                                    &data->surface.pitch) < 0) {
slouken@3427
   584
        return -1;
slouken@3427
   585
    }
slouken@3427
   586
slouken@3435
   587
    SDL_ConvertPixels(rect->w, rect->h,
slouken@3435
   588
                      data->format, data->surface.pixels, data->surface.pitch,
slouken@3435
   589
                      format, pixels, pitch);
slouken@3427
   590
slouken@5142
   591
    data->renderer->UnlockTexture(data->renderer, data->texture);
slouken@3427
   592
    return 0;
slouken@3427
   593
}
slouken@3427
   594
slouken@3427
   595
static int
slouken@3427
   596
SW_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
   597
                     Uint32 format, const void * pixels, int pitch)
slouken@3427
   598
{
slouken@3427
   599
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@3427
   600
slouken@5147
   601
    if (!SW_ActivateRenderer(renderer)) {
slouken@5147
   602
        return -1;
slouken@5147
   603
    }
slouken@5147
   604
slouken@5156
   605
    if (data->renderer->LockTexture(data->renderer, data->texture, rect,
slouken@5156
   606
                                    &data->surface.pixels,
slouken@3427
   607
                                    &data->surface.pitch) < 0) {
slouken@3427
   608
        return -1;
slouken@3427
   609
    }
slouken@3427
   610
slouken@3435
   611
    SDL_ConvertPixels(rect->w, rect->h, format, pixels, pitch,
slouken@3435
   612
                      data->format, data->surface.pixels, data->surface.pitch);
slouken@3427
   613
slouken@5142
   614
    data->renderer->UnlockTexture(data->renderer, data->texture);
slouken@3427
   615
    return 0;
slouken@3427
   616
}
slouken@3427
   617
slouken@1895
   618
static void
slouken@1918
   619
SW_RenderPresent(SDL_Renderer * renderer)
slouken@1895
   620
{
slouken@1918
   621
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@5147
   622
    SDL_Texture *texture = SW_ActivateRenderer(renderer);
slouken@5142
   623
    SDL_Rect rect;
slouken@1895
   624
slouken@5147
   625
    if (!texture) {
slouken@5147
   626
        return;
slouken@5147
   627
    }
slouken@5147
   628
slouken@1895
   629
    /* Send the data to the display */
slouken@5142
   630
    rect.x = 0;
slouken@5142
   631
    rect.y = 0;
slouken@5142
   632
    rect.w = texture->w;
slouken@5142
   633
    rect.h = texture->h;
slouken@5142
   634
    data->renderer->RenderCopy(data->renderer, texture, &rect, &rect);
slouken@1895
   635
    data->renderer->RenderPresent(data->renderer);
slouken@1895
   636
}
slouken@1895
   637
slouken@1895
   638
static void
slouken@1918
   639
SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
   640
{
slouken@5156
   641
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@1895
   642
slouken@5156
   643
    SDL_FreeSurface(surface);
slouken@1895
   644
}
slouken@1895
   645
slouken@1895
   646
static void
slouken@1918
   647
SW_DestroyRenderer(SDL_Renderer * renderer)
slouken@1895
   648
{
slouken@1918
   649
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@3685
   650
    SDL_Window *window = renderer->window;
slouken@1895
   651
slouken@1895
   652
    if (data) {
slouken@5142
   653
        if (data->texture) {
slouken@5142
   654
            DestroyTexture(data->renderer, data->texture);
slouken@1895
   655
        }
slouken@1907
   656
        if (data->surface.format) {
slouken@1907
   657
            SDL_FreeFormat(data->surface.format);
slouken@1907
   658
        }
slouken@1907
   659
        if (data->renderer) {
slouken@1907
   660
            data->renderer->DestroyRenderer(data->renderer);
slouken@1907
   661
        }
slouken@1895
   662
        SDL_free(data);
slouken@1895
   663
    }
slouken@1895
   664
    SDL_free(renderer);
slouken@1895
   665
}
slouken@1895
   666
slouken@1895
   667
/* vi: set ts=4 sw=4 expandtab: */