src/render/software/SDL_render_sw.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 07 Oct 2016 18:00:30 -0700
changeset 10489 1e1ce9f6d215
parent 9998 f67cf37e9cd4
child 10612 6b2307dbec54
permissions -rw-r--r--
Fixed bug 3029 - software renderer cuts off edges when rotate-blitting with a multiple of 90 degrees

Adam M.

When doing a rotated texture copy with the software renderer, where the angle is a multiple of 90 degrees, one or two edges of the image get cut off. This is because of the following line in sw_rotate.c:
if ((unsigned)dx < (unsigned)sw && (unsigned)dy < (unsigned)sh) {
which is effectively saying:
if (dx >= 0 && dx < src->w-1 && dy >= 0 && dy < src->h-1) {

As a result, it doesn't process pixels in the right column or bottom row of the source image (except when they're accessed as part of the bilinear filtering for nearby pixels). This causes it to look like the edges are cut off, and it's especially obvious with an exact multiple of 90 degrees.
slouken@1895
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
slouken@1895
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1895
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1895
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1895
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@1895
    22
slouken@5226
    23
#if !SDL_RENDER_DISABLED
slouken@5226
    24
slouken@5154
    25
#include "../SDL_sysrender.h"
slouken@6044
    26
#include "SDL_render_sw_c.h"
gabomdq@6320
    27
#include "SDL_hints.h"
slouken@1895
    28
slouken@5163
    29
#include "SDL_draw.h"
slouken@5163
    30
#include "SDL_blendfillrect.h"
slouken@5163
    31
#include "SDL_blendline.h"
slouken@5163
    32
#include "SDL_blendpoint.h"
slouken@5163
    33
#include "SDL_drawline.h"
slouken@5163
    34
#include "SDL_drawpoint.h"
gabomdq@6320
    35
#include "SDL_rotate.h"
slouken@1895
    36
slouken@1895
    37
/* SDL surface based renderer implementation */
slouken@1895
    38
slouken@1918
    39
static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags);
slouken@5147
    40
static void SW_WindowEvent(SDL_Renderer * renderer,
slouken@5147
    41
                           const SDL_WindowEvent *event);
slouken@7239
    42
static int SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
slouken@1918
    43
static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1985
    44
static int SW_SetTextureColorMod(SDL_Renderer * renderer,
slouken@1985
    45
                                 SDL_Texture * texture);
slouken@1985
    46
static int SW_SetTextureAlphaMod(SDL_Renderer * renderer,
slouken@1985
    47
                                 SDL_Texture * texture);
slouken@5141
    48
static int SW_SetTextureBlendMode(SDL_Renderer * renderer,
slouken@5141
    49
                                  SDL_Texture * texture);
slouken@1985
    50
static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1985
    51
                            const SDL_Rect * rect, const void *pixels,
slouken@1985
    52
                            int pitch);
slouken@1918
    53
static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
    54
                          const SDL_Rect * rect, void **pixels, int *pitch);
slouken@1918
    55
static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@6247
    56
static int SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@5297
    57
static int SW_UpdateViewport(SDL_Renderer * renderer);
slouken@7141
    58
static int SW_UpdateClipRect(SDL_Renderer * renderer);
slouken@5297
    59
static int SW_RenderClear(SDL_Renderer * renderer);
slouken@3596
    60
static int SW_RenderDrawPoints(SDL_Renderer * renderer,
slouken@6528
    61
                               const SDL_FPoint * points, int count);
slouken@3596
    62
static int SW_RenderDrawLines(SDL_Renderer * renderer,
slouken@6528
    63
                              const SDL_FPoint * points, int count);
slouken@3596
    64
static int SW_RenderFillRects(SDL_Renderer * renderer,
slouken@6528
    65
                              const SDL_FRect * rects, int count);
slouken@1918
    66
static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
    67
                         const SDL_Rect * srcrect, const SDL_FRect * dstrect);
gabomdq@6320
    68
static int SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
    69
                          const SDL_Rect * srcrect, const SDL_FRect * dstrect,
slouken@6528
    70
                          const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
slouken@3427
    71
static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
    72
                               Uint32 format, void * pixels, int pitch);
slouken@1918
    73
static void SW_RenderPresent(SDL_Renderer * renderer);
slouken@1918
    74
static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1918
    75
static void SW_DestroyRenderer(SDL_Renderer * renderer);
slouken@1895
    76
slouken@1895
    77
slouken@1918
    78
SDL_RenderDriver SW_RenderDriver = {
slouken@1918
    79
    SW_CreateRenderer,
slouken@1895
    80
    {
slouken@1895
    81
     "software",
slouken@6246
    82
     SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE,
slouken@5156
    83
     8,
slouken@1895
    84
     {
slouken@8904
    85
      SDL_PIXELFORMAT_ARGB8888,
slouken@8904
    86
      SDL_PIXELFORMAT_ABGR8888,
slouken@8904
    87
      SDL_PIXELFORMAT_RGBA8888,
slouken@8904
    88
      SDL_PIXELFORMAT_BGRA8888,
slouken@1965
    89
      SDL_PIXELFORMAT_RGB888,
slouken@1965
    90
      SDL_PIXELFORMAT_BGR888,
slouken@8907
    91
      SDL_PIXELFORMAT_RGB565,
slouken@8907
    92
      SDL_PIXELFORMAT_RGB555
slouken@5156
    93
     },
slouken@1895
    94
     0,
slouken@1895
    95
     0}
slouken@1895
    96
};
slouken@1895
    97
slouken@1895
    98
typedef struct
slouken@1895
    99
{
slouken@5166
   100
    SDL_Surface *surface;
slouken@6246
   101
    SDL_Surface *window;
slouken@1918
   102
} SW_RenderData;
slouken@1895
   103
slouken@1907
   104
slouken@5297
   105
static SDL_Surface *
slouken@5297
   106
SW_ActivateRenderer(SDL_Renderer * renderer)
slouken@5297
   107
{
slouken@5297
   108
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@5297
   109
slouken@5297
   110
    if (!data->surface) {
slouken@6246
   111
        data->surface = data->window;
slouken@6246
   112
    }
slouken@6246
   113
    if (!data->surface) {
slouken@7239
   114
        SDL_Surface *surface = SDL_GetWindowSurface(renderer->window);
slouken@7239
   115
        if (surface) {
slouken@7239
   116
            data->surface = data->window = surface;
slouken@5297
   117
slouken@7239
   118
            SW_UpdateViewport(renderer);
slouken@7322
   119
            SW_UpdateClipRect(renderer);
slouken@7239
   120
        }
slouken@5297
   121
    }
slouken@5297
   122
    return data->surface;
slouken@5297
   123
}
slouken@5297
   124
slouken@1895
   125
SDL_Renderer *
slouken@5166
   126
SW_CreateRendererForSurface(SDL_Surface * surface)
slouken@1895
   127
{
slouken@1895
   128
    SDL_Renderer *renderer;
slouken@1918
   129
    SW_RenderData *data;
slouken@1895
   130
slouken@5166
   131
    if (!surface) {
slouken@5166
   132
        SDL_SetError("Can't create renderer for NULL surface");
slouken@1895
   133
        return NULL;
slouken@1895
   134
    }
slouken@1895
   135
slouken@1895
   136
    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
slouken@1895
   137
    if (!renderer) {
slouken@1895
   138
        SDL_OutOfMemory();
slouken@1895
   139
        return NULL;
slouken@1895
   140
    }
slouken@1895
   141
slouken@1920
   142
    data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
slouken@1895
   143
    if (!data) {
slouken@1918
   144
        SW_DestroyRenderer(renderer);
slouken@1895
   145
        SDL_OutOfMemory();
slouken@1895
   146
        return NULL;
slouken@1895
   147
    }
slouken@5166
   148
    data->surface = surface;
slouken@9008
   149
    data->window = surface;
slouken@5166
   150
slouken@5147
   151
    renderer->WindowEvent = SW_WindowEvent;
slouken@7239
   152
    renderer->GetOutputSize = SW_GetOutputSize;
slouken@5154
   153
    renderer->CreateTexture = SW_CreateTexture;
slouken@5154
   154
    renderer->SetTextureColorMod = SW_SetTextureColorMod;
slouken@5154
   155
    renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
slouken@5154
   156
    renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
slouken@5154
   157
    renderer->UpdateTexture = SW_UpdateTexture;
slouken@5154
   158
    renderer->LockTexture = SW_LockTexture;
slouken@5154
   159
    renderer->UnlockTexture = SW_UnlockTexture;
slouken@6247
   160
    renderer->SetRenderTarget = SW_SetRenderTarget;
slouken@5297
   161
    renderer->UpdateViewport = SW_UpdateViewport;
slouken@7141
   162
    renderer->UpdateClipRect = SW_UpdateClipRect;
slouken@5297
   163
    renderer->RenderClear = SW_RenderClear;
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;
gabomdq@6320
   168
    renderer->RenderCopyEx = SW_RenderCopyEx;
slouken@3427
   169
    renderer->RenderReadPixels = SW_RenderReadPixels;
slouken@1918
   170
    renderer->RenderPresent = SW_RenderPresent;
slouken@6246
   171
    renderer->DestroyTexture = SW_DestroyTexture;
slouken@1918
   172
    renderer->DestroyRenderer = SW_DestroyRenderer;
slouken@5154
   173
    renderer->info = SW_RenderDriver.info;
slouken@1895
   174
    renderer->driverdata = data;
slouken@1895
   175
slouken@5297
   176
    SW_ActivateRenderer(renderer);
slouken@5297
   177
slouken@1895
   178
    return renderer;
slouken@1895
   179
}
slouken@1895
   180
slouken@5166
   181
SDL_Renderer *
slouken@5166
   182
SW_CreateRenderer(SDL_Window * window, Uint32 flags)
slouken@5166
   183
{
slouken@5166
   184
    SDL_Surface *surface;
slouken@5166
   185
slouken@5166
   186
    surface = SDL_GetWindowSurface(window);
slouken@5166
   187
    if (!surface) {
slouken@5166
   188
        return NULL;
slouken@5166
   189
    }
slouken@5166
   190
    return SW_CreateRendererForSurface(surface);
slouken@5166
   191
}
slouken@5166
   192
slouken@5147
   193
static void
slouken@5147
   194
SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
slouken@1970
   195
{
slouken@1970
   196
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@1970
   197
slouken@5276
   198
    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
slouken@5297
   199
        data->surface = NULL;
slouken@6283
   200
        data->window = NULL;
slouken@1970
   201
    }
slouken@1970
   202
}
slouken@1970
   203
slouken@1970
   204
static int
slouken@7239
   205
SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
slouken@7239
   206
{
slouken@7239
   207
    SDL_Surface *surface = SW_ActivateRenderer(renderer);
slouken@7239
   208
slouken@7239
   209
    if (surface) {
slouken@7239
   210
        if (w) {
slouken@7239
   211
            *w = surface->w;
slouken@7239
   212
        }
slouken@7239
   213
        if (h) {
slouken@7239
   214
            *h = surface->h;
slouken@7239
   215
        }
slouken@7239
   216
        return 0;
slouken@7239
   217
    } else {
slouken@7239
   218
        SDL_SetError("Software renderer doesn't have an output surface");
slouken@7239
   219
        return -1;
slouken@7239
   220
    }
slouken@7239
   221
}
slouken@7239
   222
slouken@7239
   223
static int
slouken@1918
   224
SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
   225
{
slouken@5156
   226
    int bpp;
slouken@5156
   227
    Uint32 Rmask, Gmask, Bmask, Amask;
slouken@1895
   228
slouken@5156
   229
    if (!SDL_PixelFormatEnumToMasks
slouken@5156
   230
        (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
icculus@7037
   231
        return SDL_SetError("Unknown texture format");
slouken@5156
   232
    }
slouken@1895
   233
slouken@5156
   234
    texture->driverdata =
slouken@5156
   235
        SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
slouken@5156
   236
                             Bmask, Amask);
slouken@5156
   237
    SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
slouken@5156
   238
                           texture->b);
slouken@5156
   239
    SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
slouken@5156
   240
    SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
slouken@3053
   241
slouken@5156
   242
    if (texture->access == SDL_TEXTUREACCESS_STATIC) {
slouken@5156
   243
        SDL_SetSurfaceRLE(texture->driverdata, 1);
slouken@1895
   244
    }
slouken@1895
   245
slouken@1895
   246
    if (!texture->driverdata) {
slouken@1895
   247
        return -1;
slouken@1895
   248
    }
slouken@1895
   249
    return 0;
slouken@1895
   250
}
slouken@1895
   251
slouken@1895
   252
static int
slouken@1985
   253
SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1985
   254
{
slouken@2267
   255
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@9760
   256
    /* If the color mod is ever enabled (non-white), permanently disable RLE (which doesn't support
slouken@9760
   257
     * color mod) to avoid potentially frequent RLE encoding/decoding.
slouken@9760
   258
     */
slouken@9760
   259
    if ((texture->r & texture->g & texture->b) != 255) {
slouken@9760
   260
        SDL_SetSurfaceRLE(surface, 0);
slouken@9760
   261
    }
slouken@2267
   262
    return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
slouken@2267
   263
                                  texture->b);
slouken@1985
   264
}
slouken@1985
   265
slouken@1985
   266
static int
slouken@1985
   267
SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1985
   268
{
slouken@2267
   269
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@9760
   270
    /* If the texture ever has multiple alpha values (surface alpha plus alpha channel), permanently
slouken@9760
   271
     * disable RLE (which doesn't support this) to avoid potentially frequent RLE encoding/decoding.
slouken@9760
   272
     */
slouken@9760
   273
    if (texture->a != 255 && surface->format->Amask) {
slouken@9760
   274
        SDL_SetSurfaceRLE(surface, 0);
slouken@9760
   275
    }
slouken@2267
   276
    return SDL_SetSurfaceAlphaMod(surface, texture->a);
slouken@1985
   277
}
slouken@1985
   278
slouken@1985
   279
static int
slouken@1985
   280
SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1985
   281
{
slouken@2267
   282
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@9760
   283
    /* If add or mod blending are ever enabled, permanently disable RLE (which doesn't support
slouken@9760
   284
     * them) to avoid potentially frequent RLE encoding/decoding.
slouken@9760
   285
     */
slouken@9760
   286
    if ((texture->blendMode == SDL_BLENDMODE_ADD || texture->blendMode == SDL_BLENDMODE_MOD)) {
slouken@9760
   287
        SDL_SetSurfaceRLE(surface, 0);
slouken@9760
   288
    }
slouken@2267
   289
    return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
slouken@1985
   290
}
slouken@1985
   291
slouken@1985
   292
static int
slouken@1918
   293
SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
   294
                 const SDL_Rect * rect, const void *pixels, int pitch)
slouken@1895
   295
{
slouken@5156
   296
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@5156
   297
    Uint8 *src, *dst;
slouken@5156
   298
    int row;
slouken@5156
   299
    size_t length;
slouken@1895
   300
dimitris@5567
   301
    if(SDL_MUSTLOCK(surface))
dimitris@5567
   302
        SDL_LockSurface(surface);
slouken@5156
   303
    src = (Uint8 *) pixels;
slouken@5156
   304
    dst = (Uint8 *) surface->pixels +
slouken@5156
   305
                        rect->y * surface->pitch +
slouken@5156
   306
                        rect->x * surface->format->BytesPerPixel;
slouken@5156
   307
    length = rect->w * surface->format->BytesPerPixel;
slouken@5156
   308
    for (row = 0; row < rect->h; ++row) {
slouken@5156
   309
        SDL_memcpy(dst, src, length);
slouken@5156
   310
        src += pitch;
slouken@5156
   311
        dst += surface->pitch;
slouken@1895
   312
    }
dimitris@5567
   313
    if(SDL_MUSTLOCK(surface))
dimitris@5567
   314
        SDL_UnlockSurface(surface);
slouken@5156
   315
    return 0;
slouken@1895
   316
}
slouken@1895
   317
slouken@1895
   318
static int
slouken@1918
   319
SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
   320
               const SDL_Rect * rect, void **pixels, int *pitch)
slouken@1895
   321
{
slouken@5156
   322
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@1895
   323
slouken@5156
   324
    *pixels =
slouken@5156
   325
        (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
slouken@5156
   326
                  rect->x * surface->format->BytesPerPixel);
slouken@5156
   327
    *pitch = surface->pitch;
slouken@5156
   328
    return 0;
slouken@1895
   329
}
slouken@1895
   330
slouken@1895
   331
static void
slouken@1918
   332
SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
   333
{
slouken@1895
   334
}
slouken@1895
   335
slouken@5297
   336
static int
slouken@6247
   337
SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@6246
   338
{
slouken@6246
   339
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@6246
   340
slouken@6246
   341
    if (texture ) {
slouken@6246
   342
        data->surface = (SDL_Surface *) texture->driverdata;
slouken@6246
   343
    } else {
slouken@6246
   344
        data->surface = data->window;
slouken@6246
   345
    }
slouken@6246
   346
    return 0;
slouken@6246
   347
}
slouken@6246
   348
slouken@6246
   349
static int
slouken@5297
   350
SW_UpdateViewport(SDL_Renderer * renderer)
slouken@5297
   351
{
slouken@5297
   352
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@5297
   353
    SDL_Surface *surface = data->surface;
slouken@5297
   354
slouken@5297
   355
    if (!surface) {
slouken@5297
   356
        /* We'll update the viewport after we recreate the surface */
slouken@5297
   357
        return 0;
slouken@5297
   358
    }
slouken@5297
   359
slouken@5298
   360
    SDL_SetClipRect(data->surface, &renderer->viewport);
slouken@5297
   361
    return 0;
slouken@5297
   362
}
slouken@5297
   363
slouken@5297
   364
static int
slouken@7141
   365
SW_UpdateClipRect(SDL_Renderer * renderer)
slouken@7141
   366
{
slouken@7322
   367
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@7322
   368
    SDL_Surface *surface = data->surface;
slouken@7322
   369
    if (surface) {
jorgenpt@8728
   370
        if (renderer->clipping_enabled) {
jorgenpt@8728
   371
            SDL_SetClipRect(surface, &renderer->clip_rect);
slouken@7322
   372
        } else {
slouken@7322
   373
            SDL_SetClipRect(surface, NULL);
slouken@7322
   374
        }
slouken@7141
   375
    }
slouken@7141
   376
    return 0;
slouken@7141
   377
}
slouken@7141
   378
slouken@7141
   379
static int
slouken@5297
   380
SW_RenderClear(SDL_Renderer * renderer)
slouken@5224
   381
{
slouken@5224
   382
    SDL_Surface *surface = SW_ActivateRenderer(renderer);
slouken@5297
   383
    Uint32 color;
slouken@5297
   384
    SDL_Rect clip_rect;
slouken@5224
   385
slouken@5224
   386
    if (!surface) {
slouken@5297
   387
        return -1;
slouken@5224
   388
    }
slouken@5297
   389
slouken@5297
   390
    color = SDL_MapRGBA(surface->format,
slouken@5297
   391
                        renderer->r, renderer->g, renderer->b, renderer->a);
slouken@5297
   392
slouken@5297
   393
    /* By definition the clear ignores the clip rect */
slouken@5297
   394
    clip_rect = surface->clip_rect;
slouken@5297
   395
    SDL_SetClipRect(surface, NULL);
slouken@5297
   396
    SDL_FillRect(surface, NULL, color);
slouken@5297
   397
    SDL_SetClipRect(surface, &clip_rect);
slouken@5297
   398
    return 0;
slouken@5224
   399
}
slouken@5224
   400
slouken@1895
   401
static int
slouken@6528
   402
SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
slouken@3596
   403
                    int count)
slouken@2901
   404
{
slouken@5166
   405
    SDL_Surface *surface = SW_ActivateRenderer(renderer);
slouken@6528
   406
    SDL_Point *final_points;
slouken@6528
   407
    int i, status;
slouken@2901
   408
slouken@5166
   409
    if (!surface) {
slouken@5147
   410
        return -1;
slouken@5147
   411
    }
slouken@5147
   412
slouken@6528
   413
    final_points = SDL_stack_alloc(SDL_Point, count);
slouken@6528
   414
    if (!final_points) {
icculus@7037
   415
        return SDL_OutOfMemory();
slouken@6528
   416
    }
slouken@5297
   417
    if (renderer->viewport.x || renderer->viewport.y) {
slouken@6529
   418
        int x = renderer->viewport.x;
slouken@6529
   419
        int y = renderer->viewport.y;
slouken@5297
   420
slouken@5297
   421
        for (i = 0; i < count; ++i) {
slouken@6528
   422
            final_points[i].x = (int)(x + points[i].x);
slouken@6528
   423
            final_points[i].y = (int)(y + points[i].y);
slouken@5297
   424
        }
slouken@6528
   425
    } else {
slouken@6528
   426
        for (i = 0; i < count; ++i) {
slouken@6528
   427
            final_points[i].x = (int)points[i].x;
slouken@6528
   428
            final_points[i].y = (int)points[i].y;
slouken@6528
   429
        }
slouken@5297
   430
    }
slouken@5297
   431
slouken@3536
   432
    /* Draw the points! */
slouken@5140
   433
    if (renderer->blendMode == SDL_BLENDMODE_NONE) {
slouken@5166
   434
        Uint32 color = SDL_MapRGBA(surface->format,
slouken@3536
   435
                                   renderer->r, renderer->g, renderer->b,
slouken@3536
   436
                                   renderer->a);
slouken@2888
   437
slouken@6528
   438
        status = SDL_DrawPoints(surface, final_points, count, color);
slouken@2888
   439
    } else {
slouken@6528
   440
        status = SDL_BlendPoints(surface, final_points, count,
slouken@5297
   441
                                renderer->blendMode,
slouken@5297
   442
                                renderer->r, renderer->g, renderer->b,
slouken@5297
   443
                                renderer->a);
slouken@2888
   444
    }
slouken@6528
   445
    SDL_stack_free(final_points);
slouken@5297
   446
slouken@5297
   447
    return status;
slouken@2888
   448
}
slouken@2888
   449
slouken@2888
   450
static int
slouken@6528
   451
SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
slouken@3596
   452
                   int count)
slouken@1895
   453
{
slouken@5166
   454
    SDL_Surface *surface = SW_ActivateRenderer(renderer);
slouken@6528
   455
    SDL_Point *final_points;
slouken@6528
   456
    int i, status;
slouken@3536
   457
slouken@5166
   458
    if (!surface) {
slouken@5147
   459
        return -1;
slouken@5147
   460
    }
slouken@5147
   461
slouken@6528
   462
    final_points = SDL_stack_alloc(SDL_Point, count);
slouken@6528
   463
    if (!final_points) {
icculus@7037
   464
        return SDL_OutOfMemory();
slouken@6528
   465
    }
slouken@5297
   466
    if (renderer->viewport.x || renderer->viewport.y) {
slouken@6529
   467
        int x = renderer->viewport.x;
slouken@6529
   468
        int y = renderer->viewport.y;
slouken@5297
   469
slouken@5297
   470
        for (i = 0; i < count; ++i) {
slouken@6528
   471
            final_points[i].x = (int)(x + points[i].x);
slouken@6528
   472
            final_points[i].y = (int)(y + points[i].y);
slouken@5297
   473
        }
slouken@6528
   474
    } else {
slouken@6528
   475
        for (i = 0; i < count; ++i) {
slouken@6528
   476
            final_points[i].x = (int)points[i].x;
slouken@6528
   477
            final_points[i].y = (int)points[i].y;
slouken@6528
   478
        }
slouken@5297
   479
    }
slouken@5297
   480
slouken@5166
   481
    /* Draw the lines! */
slouken@5140
   482
    if (renderer->blendMode == SDL_BLENDMODE_NONE) {
slouken@5166
   483
        Uint32 color = SDL_MapRGBA(surface->format,
slouken@3536
   484
                                   renderer->r, renderer->g, renderer->b,
slouken@3536
   485
                                   renderer->a);
slouken@2888
   486
slouken@6528
   487
        status = SDL_DrawLines(surface, final_points, count, color);
slouken@2888
   488
    } else {
slouken@6528
   489
        status = SDL_BlendLines(surface, final_points, count,
slouken@5297
   490
                                renderer->blendMode,
slouken@5297
   491
                                renderer->r, renderer->g, renderer->b,
slouken@5297
   492
                                renderer->a);
slouken@2888
   493
    }
slouken@6528
   494
    SDL_stack_free(final_points);
slouken@5297
   495
slouken@5297
   496
    return status;
slouken@3536
   497
}
slouken@3536
   498
slouken@3536
   499
static int
slouken@6528
   500
SW_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
slouken@3536
   501
{
slouken@5166
   502
    SDL_Surface *surface = SW_ActivateRenderer(renderer);
slouken@6528
   503
    SDL_Rect *final_rects;
slouken@6528
   504
    int i, status;
slouken@6528
   505
slouken@6528
   506
    if (!surface) {
slouken@6528
   507
        return -1;
slouken@6528
   508
    }
slouken@6528
   509
slouken@6528
   510
    final_rects = SDL_stack_alloc(SDL_Rect, count);
slouken@6528
   511
    if (!final_rects) {
icculus@7037
   512
        return SDL_OutOfMemory();
slouken@6528
   513
    }
slouken@6528
   514
    if (renderer->viewport.x || renderer->viewport.y) {
slouken@6529
   515
        int x = renderer->viewport.x;
slouken@6529
   516
        int y = renderer->viewport.y;
slouken@6528
   517
slouken@6528
   518
        for (i = 0; i < count; ++i) {
slouken@6528
   519
            final_rects[i].x = (int)(x + rects[i].x);
slouken@6528
   520
            final_rects[i].y = (int)(y + rects[i].y);
slouken@6528
   521
            final_rects[i].w = SDL_max((int)rects[i].w, 1);
slouken@6528
   522
            final_rects[i].h = SDL_max((int)rects[i].h, 1);
slouken@6528
   523
        }
slouken@6528
   524
    } else {
slouken@6528
   525
        for (i = 0; i < count; ++i) {
slouken@6528
   526
            final_rects[i].x = (int)rects[i].x;
slouken@6528
   527
            final_rects[i].y = (int)rects[i].y;
slouken@6528
   528
            final_rects[i].w = SDL_max((int)rects[i].w, 1);
slouken@6528
   529
            final_rects[i].h = SDL_max((int)rects[i].h, 1);
slouken@6528
   530
        }
slouken@6528
   531
    }
slouken@6528
   532
slouken@6528
   533
    if (renderer->blendMode == SDL_BLENDMODE_NONE) {
slouken@6528
   534
        Uint32 color = SDL_MapRGBA(surface->format,
slouken@6528
   535
                                   renderer->r, renderer->g, renderer->b,
slouken@6528
   536
                                   renderer->a);
slouken@6528
   537
        status = SDL_FillRects(surface, final_rects, count, color);
slouken@6528
   538
    } else {
slouken@6528
   539
        status = SDL_BlendFillRects(surface, final_rects, count,
slouken@6528
   540
                                    renderer->blendMode,
slouken@6528
   541
                                    renderer->r, renderer->g, renderer->b,
slouken@6528
   542
                                    renderer->a);
slouken@6528
   543
    }
slouken@6528
   544
    SDL_stack_free(final_rects);
slouken@6528
   545
slouken@6528
   546
    return status;
slouken@6528
   547
}
slouken@6528
   548
slouken@6528
   549
static int
slouken@6528
   550
SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
   551
              const SDL_Rect * srcrect, const SDL_FRect * dstrect)
slouken@6528
   552
{
slouken@6528
   553
    SDL_Surface *surface = SW_ActivateRenderer(renderer);
slouken@6528
   554
    SDL_Surface *src = (SDL_Surface *) texture->driverdata;
slouken@6528
   555
    SDL_Rect final_rect;
slouken@3536
   556
slouken@5166
   557
    if (!surface) {
slouken@5147
   558
        return -1;
slouken@5147
   559
    }
slouken@5147
   560
slouken@5297
   561
    if (renderer->viewport.x || renderer->viewport.y) {
slouken@6529
   562
        final_rect.x = (int)(renderer->viewport.x + dstrect->x);
slouken@6529
   563
        final_rect.y = (int)(renderer->viewport.y + dstrect->y);
slouken@6528
   564
    } else {
slouken@6528
   565
        final_rect.x = (int)dstrect->x;
slouken@6528
   566
        final_rect.y = (int)dstrect->y;
slouken@6528
   567
    }
slouken@6528
   568
    final_rect.w = (int)dstrect->w;
slouken@6528
   569
    final_rect.h = (int)dstrect->h;
slouken@5297
   570
ken@5296
   571
    if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {
ken@5296
   572
        return SDL_BlitSurface(src, srcrect, surface, &final_rect);
ken@5296
   573
    } else {
slouken@9760
   574
        /* If scaling is ever done, permanently disable RLE (which doesn't support scaling)
slouken@9760
   575
         * to avoid potentially frequent RLE encoding/decoding.
slouken@9760
   576
         */
slouken@9760
   577
        SDL_SetSurfaceRLE(surface, 0);
ken@5296
   578
        return SDL_BlitScaled(src, srcrect, surface, &final_rect);
ken@5296
   579
    }
slouken@1895
   580
}
slouken@1895
   581
slouken@3427
   582
static int
gabomdq@6320
   583
GetScaleQuality(void)
gabomdq@6320
   584
{
gabomdq@6320
   585
    const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
gabomdq@6320
   586
gabomdq@6320
   587
    if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
gabomdq@6320
   588
        return 0;
gabomdq@6320
   589
    } else {
gabomdq@6320
   590
        return 1;
gabomdq@6320
   591
    }
gabomdq@6320
   592
}
gabomdq@6320
   593
gabomdq@6320
   594
static int
gabomdq@6320
   595
SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
   596
                const SDL_Rect * srcrect, const SDL_FRect * dstrect,
slouken@6528
   597
                const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
gabomdq@6320
   598
{
gabomdq@6320
   599
    SDL_Surface *surface = SW_ActivateRenderer(renderer);
gabomdq@6320
   600
    SDL_Surface *src = (SDL_Surface *) texture->driverdata;
slouken@6528
   601
    SDL_Rect final_rect, tmp_rect;
gabomdq@6320
   602
    SDL_Surface *surface_rotated, *surface_scaled;
gabomdq@6320
   603
    int retval, dstwidth, dstheight, abscenterx, abscentery;
gabomdq@6320
   604
    double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
gabomdq@6320
   605
gabomdq@6320
   606
    if (!surface) {
gabomdq@6320
   607
        return -1;
gabomdq@6320
   608
    }
gabomdq@6320
   609
gabomdq@6320
   610
    if (renderer->viewport.x || renderer->viewport.y) {
slouken@6529
   611
        final_rect.x = (int)(renderer->viewport.x + dstrect->x);
slouken@6529
   612
        final_rect.y = (int)(renderer->viewport.y + dstrect->y);
slouken@6528
   613
    } else {
slouken@6528
   614
        final_rect.x = (int)dstrect->x;
slouken@6528
   615
        final_rect.y = (int)dstrect->y;
gabomdq@6320
   616
    }
slouken@6528
   617
    final_rect.w = (int)dstrect->w;
slouken@6528
   618
    final_rect.h = (int)dstrect->h;
gabomdq@6320
   619
slouken@9762
   620
    /* SDLgfx_rotateSurface doesn't accept a source rectangle, so crop and scale if we need to */
slouken@9762
   621
    tmp_rect = final_rect;
slouken@9762
   622
    tmp_rect.x = 0;
slouken@9762
   623
    tmp_rect.y = 0;
slouken@9762
   624
    if (srcrect->w == final_rect.w && srcrect->h == final_rect.h && srcrect->x == 0 && srcrect->y == 0) {
slouken@9762
   625
        surface_scaled = src; /* but if we don't need to, just use the original */
slouken@9762
   626
        retval = 0;
slouken@9762
   627
    } else {
slouken@9762
   628
        SDL_Surface *blit_src = src;
slouken@9762
   629
        Uint32 colorkey;
slouken@9762
   630
        SDL_BlendMode blendMode;
slouken@9762
   631
        Uint8 alphaMod, r, g, b;
slouken@9762
   632
        SDL_bool cloneSource = SDL_FALSE;
slouken@6528
   633
slouken@9762
   634
        surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel,
slouken@9762
   635
                                              src->format->Rmask, src->format->Gmask,
slouken@9762
   636
                                              src->format->Bmask, src->format->Amask );
slouken@9762
   637
        if (!surface_scaled) {
slouken@9762
   638
            return -1;
slouken@9762
   639
        }
gabomdq@6320
   640
slouken@9762
   641
        /* copy the color key, alpha mod, blend mode, and color mod so the scaled surface behaves like the source */
slouken@9762
   642
        if (SDL_GetColorKey(src, &colorkey) == 0) {
slouken@9762
   643
            SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey);
slouken@9762
   644
            cloneSource = SDL_TRUE;
slouken@9762
   645
        }
slouken@9762
   646
        SDL_GetSurfaceAlphaMod(src, &alphaMod); /* these will be copied to surface_scaled below if necessary */
slouken@9762
   647
        SDL_GetSurfaceBlendMode(src, &blendMode);
slouken@9762
   648
        SDL_GetSurfaceColorMod(src, &r, &g, &b);
gabomdq@6320
   649
slouken@9762
   650
        /* now we need to blit the src into surface_scaled. since we want to copy the colors from the source to
slouken@9762
   651
         * surface_scaled rather than blend them, etc. we'll need to disable the blend mode, alpha mod, etc.
slouken@9762
   652
         * but we don't want to modify src (in case it's being used on other threads), so we'll need to clone it
slouken@9762
   653
         * before changing the blend options
slouken@9762
   654
         */
slouken@9762
   655
        cloneSource |= blendMode != SDL_BLENDMODE_NONE || (alphaMod & r & g & b) != 255;
slouken@9762
   656
        if (cloneSource) {
slouken@9762
   657
            blit_src = SDL_ConvertSurface(src, src->format, src->flags); /* clone src */
slouken@9762
   658
            if (!blit_src) {
slouken@9762
   659
                SDL_FreeSurface(surface_scaled);
slouken@9762
   660
                return -1;
slouken@9762
   661
            }
slouken@9762
   662
            SDL_SetSurfaceAlphaMod(blit_src, 255); /* disable all blending options in blit_src */
slouken@9762
   663
            SDL_SetSurfaceBlendMode(blit_src, SDL_BLENDMODE_NONE);
slouken@9762
   664
            SDL_SetColorKey(blit_src, 0, 0);
slouken@9762
   665
            SDL_SetSurfaceColorMod(blit_src, 255, 255, 255);
slouken@9762
   666
            SDL_SetSurfaceRLE(blit_src, 0); /* don't RLE encode a surface we'll only use once */
gabomdq@6320
   667
slouken@9762
   668
            SDL_SetSurfaceAlphaMod(surface_scaled, alphaMod); /* copy blending options to surface_scaled */
slouken@9762
   669
            SDL_SetSurfaceBlendMode(surface_scaled, blendMode);
slouken@9762
   670
            SDL_SetSurfaceColorMod(surface_scaled, r, g, b);
slouken@9762
   671
        }
gabomdq@6320
   672
slouken@9762
   673
        retval = SDL_BlitScaled(blit_src, srcrect, surface_scaled, &tmp_rect);
slouken@9762
   674
        if (blit_src != src) {
slouken@9762
   675
            SDL_FreeSurface(blit_src);
gabomdq@6320
   676
        }
gabomdq@6320
   677
    }
gabomdq@6320
   678
slouken@9762
   679
    if (!retval) {
slouken@10489
   680
        SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, &dstwidth, &dstheight, &cangle, &sangle);
slouken@10489
   681
        surface_rotated = SDLgfx_rotateSurface(surface_scaled, angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
slouken@9762
   682
        if(surface_rotated) {
slouken@9762
   683
            /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
slouken@9762
   684
            abscenterx = final_rect.x + (int)center->x;
slouken@9762
   685
            abscentery = final_rect.y + (int)center->y;
slouken@9762
   686
            /* Compensate the angle inversion to match the behaviour of the other backends */
slouken@9762
   687
            sangle = -sangle;
slouken@9762
   688
slouken@9762
   689
            /* Top Left */
slouken@9762
   690
            px = final_rect.x - abscenterx;
slouken@9762
   691
            py = final_rect.y - abscentery;
slouken@9762
   692
            p1x = px * cangle - py * sangle + abscenterx;
slouken@9762
   693
            p1y = px * sangle + py * cangle + abscentery;
slouken@9762
   694
slouken@9762
   695
            /* Top Right */
slouken@9762
   696
            px = final_rect.x + final_rect.w - abscenterx;
slouken@9762
   697
            py = final_rect.y - abscentery;
slouken@9762
   698
            p2x = px * cangle - py * sangle + abscenterx;
slouken@9762
   699
            p2y = px * sangle + py * cangle + abscentery;
slouken@9762
   700
slouken@9762
   701
            /* Bottom Left */
slouken@9762
   702
            px = final_rect.x - abscenterx;
slouken@9762
   703
            py = final_rect.y + final_rect.h - abscentery;
slouken@9762
   704
            p3x = px * cangle - py * sangle + abscenterx;
slouken@9762
   705
            p3y = px * sangle + py * cangle + abscentery;
slouken@9762
   706
slouken@9762
   707
            /* Bottom Right */
slouken@9762
   708
            px = final_rect.x + final_rect.w - abscenterx;
slouken@9762
   709
            py = final_rect.y + final_rect.h - abscentery;
slouken@9762
   710
            p4x = px * cangle - py * sangle + abscenterx;
slouken@9762
   711
            p4y = px * sangle + py * cangle + abscentery;
slouken@9762
   712
slouken@9762
   713
            tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
slouken@9762
   714
            tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
slouken@9762
   715
            tmp_rect.w = dstwidth;
slouken@9762
   716
            tmp_rect.h = dstheight;
slouken@9762
   717
slouken@9762
   718
            retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect);
slouken@9762
   719
            SDL_FreeSurface(surface_rotated);
slouken@9762
   720
        }
slouken@9762
   721
    }
slouken@9762
   722
slouken@9762
   723
    if (surface_scaled != src) {
slouken@9762
   724
        SDL_FreeSurface(surface_scaled);
slouken@9762
   725
    }
slouken@9762
   726
    return retval;
gabomdq@6320
   727
}
gabomdq@6320
   728
gabomdq@6320
   729
static int
slouken@3427
   730
SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
   731
                    Uint32 format, void * pixels, int pitch)
slouken@3427
   732
{
slouken@5166
   733
    SDL_Surface *surface = SW_ActivateRenderer(renderer);
slouken@5166
   734
    Uint32 src_format;
slouken@5166
   735
    void *src_pixels;
slouken@5297
   736
    SDL_Rect final_rect;
slouken@3427
   737
slouken@5166
   738
    if (!surface) {
slouken@5147
   739
        return -1;
slouken@5147
   740
    }
slouken@5147
   741
slouken@5297
   742
    if (renderer->viewport.x || renderer->viewport.y) {
slouken@5297
   743
        final_rect.x = renderer->viewport.x + rect->x;
slouken@5297
   744
        final_rect.y = renderer->viewport.y + rect->y;
slouken@5297
   745
        final_rect.w = rect->w;
slouken@5297
   746
        final_rect.h = rect->h;
slouken@5297
   747
        rect = &final_rect;
slouken@5297
   748
    }
slouken@5297
   749
slouken@5166
   750
    if (rect->x < 0 || rect->x+rect->w > surface->w ||
slouken@5166
   751
        rect->y < 0 || rect->y+rect->h > surface->h) {
icculus@7037
   752
        return SDL_SetError("Tried to read outside of surface bounds");
slouken@3427
   753
    }
slouken@3427
   754
slouken@5297
   755
    src_format = surface->format->format;
slouken@5166
   756
    src_pixels = (void*)((Uint8 *) surface->pixels +
slouken@5166
   757
                    rect->y * surface->pitch +
slouken@5166
   758
                    rect->x * surface->format->BytesPerPixel);
slouken@5166
   759
slouken@5166
   760
    return SDL_ConvertPixels(rect->w, rect->h,
slouken@5166
   761
                             src_format, src_pixels, surface->pitch,
slouken@5166
   762
                             format, pixels, pitch);
slouken@3427
   763
}
slouken@3427
   764
slouken@1895
   765
static void
slouken@1918
   766
SW_RenderPresent(SDL_Renderer * renderer)
slouken@1895
   767
{
slouken@5166
   768
    SDL_Window *window = renderer->window;
slouken@1895
   769
slouken@5166
   770
    if (window) {
slouken@5166
   771
        SDL_UpdateWindowSurface(window);
slouken@5147
   772
    }
slouken@1895
   773
}
slouken@1895
   774
slouken@1895
   775
static void
slouken@1918
   776
SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
   777
{
slouken@5156
   778
    SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
slouken@1895
   779
slouken@5156
   780
    SDL_FreeSurface(surface);
slouken@1895
   781
}
slouken@1895
   782
slouken@1895
   783
static void
slouken@1918
   784
SW_DestroyRenderer(SDL_Renderer * renderer)
slouken@1895
   785
{
slouken@1918
   786
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
slouken@1895
   787
slouken@7719
   788
    SDL_free(data);
slouken@1895
   789
    SDL_free(renderer);
slouken@1895
   790
}
slouken@1895
   791
slouken@5226
   792
#endif /* !SDL_RENDER_DISABLED */
slouken@5226
   793
slouken@1895
   794
/* vi: set ts=4 sw=4 expandtab: */