src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 19 Jun 2015 23:20:43 -0700
changeset 9762 5c4a85c5b648
parent 9673 aea5a2032785
child 9849 1305bfa0214e
child 11075 6a683bf1446c
permissions -rw-r--r--
Fixed bug 1550 - SDL_RenderCopy/CopyEx in software should optionally render 8bit alpha

Adam M.

There are three problems in the code that I see.
1. SW_RenderCopyEx enables a color key on surface_scaled even if the source surface didn't have a color key.
2. SW_RenderCopyEx doesn't copy blend mode, color mod, or alpha mod from src to surface_scaled.
3. When SDL_BlitScaled(src, srcrect, surface_scaled, &tmp_rect) is called, it blends the src pixels into surface_scaled instead of overwriting them (if src has blending, etc. enabled).

I've attached a patch that 1) fixes the three problems that I mentioned, 2) adds the requested performance improvement of using the regular blit function if no rotation or flipping is needed, 3) avoids cloning the source surface if no stretching is required, and simplifies the rotation code slightly.
slouken@5154
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
slouken@5154
     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@5154
     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@5154
    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@5154
    20
*/
icculus@8093
    21
#include "../SDL_internal.h"
slouken@5154
    22
slouken@5154
    23
/* The SDL 2D rendering system */
slouken@5154
    24
slouken@7760
    25
#include "SDL_assert.h"
slouken@5192
    26
#include "SDL_hints.h"
slouken@5221
    27
#include "SDL_log.h"
slouken@5154
    28
#include "SDL_render.h"
slouken@5154
    29
#include "SDL_sysrender.h"
slouken@5195
    30
#include "software/SDL_render_sw_c.h"
slouken@5154
    31
slouken@5154
    32
slouken@5528
    33
#define SDL_WINDOWRENDERDATA    "_SDL_WindowRenderData"
slouken@5528
    34
slouken@5154
    35
#define CHECK_RENDERER_MAGIC(renderer, retval) \
slouken@5154
    36
    if (!renderer || renderer->magic != &renderer_magic) { \
slouken@5154
    37
        SDL_SetError("Invalid renderer"); \
slouken@5154
    38
        return retval; \
slouken@5154
    39
    }
slouken@5154
    40
slouken@5154
    41
#define CHECK_TEXTURE_MAGIC(texture, retval) \
slouken@5154
    42
    if (!texture || texture->magic != &texture_magic) { \
slouken@5154
    43
        SDL_SetError("Invalid texture"); \
slouken@5154
    44
        return retval; \
slouken@5154
    45
    }
slouken@5154
    46
slouken@5154
    47
slouken@7109
    48
#if !SDL_RENDER_DISABLED
slouken@5154
    49
static const SDL_RenderDriver *render_drivers[] = {
slouken@8599
    50
#if SDL_VIDEO_RENDER_D3D
slouken@8599
    51
    &D3D_RenderDriver,
slouken@8599
    52
#endif
slouken@8591
    53
#if SDL_VIDEO_RENDER_D3D11
slouken@8591
    54
    &D3D11_RenderDriver,
slouken@8591
    55
#endif
slouken@5154
    56
#if SDL_VIDEO_RENDER_OGL
slouken@5154
    57
    &GL_RenderDriver,
slouken@5154
    58
#endif
slouken@5209
    59
#if SDL_VIDEO_RENDER_OGL_ES2
slouken@5209
    60
    &GLES2_RenderDriver,
slouken@5209
    61
#endif
slouken@5154
    62
#if SDL_VIDEO_RENDER_OGL_ES
slouken@5201
    63
    &GLES_RenderDriver,
slouken@5201
    64
#endif
slouken@5199
    65
#if SDL_VIDEO_RENDER_DIRECTFB
slouken@5199
    66
    &DirectFB_RenderDriver,
slouken@5199
    67
#endif
kimonline@7009
    68
#if SDL_VIDEO_RENDER_PSP
kimonline@7009
    69
    &PSP_RenderDriver,
kimonline@7009
    70
#endif
slouken@5154
    71
    &SW_RenderDriver
slouken@7109
    72
};
slouken@5226
    73
#endif /* !SDL_RENDER_DISABLED */
slouken@7109
    74
slouken@5154
    75
static char renderer_magic;
slouken@5154
    76
static char texture_magic;
slouken@5154
    77
slouken@6530
    78
static int UpdateLogicalSize(SDL_Renderer *renderer);
slouken@6530
    79
slouken@5154
    80
int
slouken@5154
    81
SDL_GetNumRenderDrivers(void)
slouken@5154
    82
{
slouken@7109
    83
#if !SDL_RENDER_DISABLED
slouken@5154
    84
    return SDL_arraysize(render_drivers);
slouken@7109
    85
#else
slouken@7109
    86
    return 0;
slouken@7109
    87
#endif
slouken@5154
    88
}
slouken@5154
    89
slouken@5154
    90
int
slouken@5154
    91
SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info)
slouken@5154
    92
{
slouken@7109
    93
#if !SDL_RENDER_DISABLED
slouken@5154
    94
    if (index < 0 || index >= SDL_GetNumRenderDrivers()) {
icculus@7037
    95
        return SDL_SetError("index must be in the range of 0 - %d",
icculus@7037
    96
                            SDL_GetNumRenderDrivers() - 1);
slouken@5154
    97
    }
slouken@5154
    98
    *info = render_drivers[index]->info;
slouken@5154
    99
    return 0;
slouken@7109
   100
#else
slouken@7109
   101
    return SDL_SetError("SDL not built with rendering support");
slouken@7109
   102
#endif
slouken@5154
   103
}
slouken@5154
   104
slouken@5154
   105
static int
slouken@5154
   106
SDL_RendererEventWatch(void *userdata, SDL_Event *event)
slouken@5154
   107
{
slouken@5154
   108
    SDL_Renderer *renderer = (SDL_Renderer *)userdata;
slouken@5154
   109
slouken@5297
   110
    if (event->type == SDL_WINDOWEVENT) {
slouken@5154
   111
        SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
slouken@5154
   112
        if (window == renderer->window) {
slouken@5297
   113
            if (renderer->WindowEvent) {
slouken@5297
   114
                renderer->WindowEvent(renderer, &event->window);
slouken@5297
   115
            }
slouken@5297
   116
slouken@7240
   117
            if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
slouken@9084
   118
                /* Make sure we're operating on the default render target */
slouken@9084
   119
                SDL_Texture *saved_target = SDL_GetRenderTarget(renderer);
slouken@9084
   120
                if (saved_target) {
slouken@9084
   121
                    SDL_SetRenderTarget(renderer, NULL);
slouken@9084
   122
                }
slouken@9084
   123
slouken@6530
   124
                if (renderer->logical_w) {
slouken@6530
   125
                    UpdateLogicalSize(renderer);
slouken@7240
   126
                } else {
slouken@7240
   127
                    /* Window was resized, reset viewport */
slouken@6528
   128
                    int w, h;
slouken@6528
   129
urkle@7746
   130
                    if (renderer->GetOutputSize) {
urkle@7746
   131
                        renderer->GetOutputSize(renderer, &w, &h);
urkle@7746
   132
                    } else {
urkle@7746
   133
                        SDL_GetWindowSize(renderer->window, &w, &h);
urkle@7746
   134
                    }
urkle@7746
   135
slouken@6260
   136
                    if (renderer->target) {
slouken@6260
   137
                        renderer->viewport_backup.x = 0;
slouken@6260
   138
                        renderer->viewport_backup.y = 0;
slouken@6260
   139
                        renderer->viewport_backup.w = w;
slouken@6260
   140
                        renderer->viewport_backup.h = h;
slouken@6260
   141
                    } else {
slouken@6528
   142
                        renderer->viewport.x = 0;
slouken@6528
   143
                        renderer->viewport.y = 0;
slouken@6528
   144
                        renderer->viewport.w = w;
slouken@6528
   145
                        renderer->viewport.h = h;
slouken@6528
   146
                        renderer->UpdateViewport(renderer);
slouken@6260
   147
                    }
slouken@6260
   148
                }
slouken@9084
   149
slouken@9084
   150
                if (saved_target) {
slouken@9084
   151
                    SDL_SetRenderTarget(renderer, saved_target);
slouken@9084
   152
                }
slouken@6260
   153
            } else if (event->window.event == SDL_WINDOWEVENT_HIDDEN) {
slouken@6260
   154
                renderer->hidden = SDL_TRUE;
slouken@6260
   155
            } else if (event->window.event == SDL_WINDOWEVENT_SHOWN) {
slouken@6260
   156
                if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)) {
slouken@6260
   157
                    renderer->hidden = SDL_FALSE;
slouken@6260
   158
                }
slouken@6060
   159
            } else if (event->window.event == SDL_WINDOWEVENT_MINIMIZED) {
slouken@6260
   160
                renderer->hidden = SDL_TRUE;
slouken@6060
   161
            } else if (event->window.event == SDL_WINDOWEVENT_RESTORED) {
slouken@6260
   162
                if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN)) {
slouken@6260
   163
                    renderer->hidden = SDL_FALSE;
slouken@6260
   164
                }
slouken@5297
   165
            }
slouken@5154
   166
        }
slouken@6530
   167
    } else if (event->type == SDL_MOUSEMOTION) {
slouken@9673
   168
        SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID);
slouken@9673
   169
        if (renderer->logical_w && window == renderer->window) {
slouken@6530
   170
            event->motion.x -= renderer->viewport.x;
slouken@6530
   171
            event->motion.y -= renderer->viewport.y;
slouken@6530
   172
            event->motion.x = (int)(event->motion.x / renderer->scale.x);
slouken@6530
   173
            event->motion.y = (int)(event->motion.y / renderer->scale.y);
slouken@7496
   174
            if (event->motion.xrel > 0) {
slouken@7496
   175
                event->motion.xrel = SDL_max(1, (int)(event->motion.xrel / renderer->scale.x));
slouken@7496
   176
            } else if (event->motion.xrel < 0) {
slouken@7496
   177
                event->motion.xrel = SDL_min(-1, (int)(event->motion.xrel / renderer->scale.x));
slouken@7496
   178
            }
slouken@7496
   179
            if (event->motion.yrel > 0) {
slouken@7496
   180
                event->motion.yrel = SDL_max(1, (int)(event->motion.yrel / renderer->scale.y));
slouken@7496
   181
            } else if (event->motion.yrel < 0) {
slouken@7496
   182
                event->motion.yrel = SDL_min(-1, (int)(event->motion.yrel / renderer->scale.y));
slouken@7496
   183
            }
slouken@6530
   184
        }
slouken@6530
   185
    } else if (event->type == SDL_MOUSEBUTTONDOWN ||
slouken@6530
   186
               event->type == SDL_MOUSEBUTTONUP) {
slouken@9673
   187
        SDL_Window *window = SDL_GetWindowFromID(event->button.windowID);
slouken@9673
   188
        if (renderer->logical_w && window == renderer->window) {
slouken@6530
   189
            event->button.x -= renderer->viewport.x;
slouken@6530
   190
            event->button.y -= renderer->viewport.y;
slouken@6530
   191
            event->button.x = (int)(event->button.x / renderer->scale.x);
slouken@6530
   192
            event->button.y = (int)(event->button.y / renderer->scale.y);
slouken@6530
   193
        }
slouken@5154
   194
    }
slouken@5154
   195
    return 0;
slouken@5154
   196
}
slouken@5154
   197
slouken@6258
   198
int
slouken@6258
   199
SDL_CreateWindowAndRenderer(int width, int height, Uint32 window_flags,
slouken@6258
   200
                            SDL_Window **window, SDL_Renderer **renderer)
slouken@6258
   201
{
slouken@6258
   202
    *window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED,
slouken@6258
   203
                                     SDL_WINDOWPOS_UNDEFINED,
slouken@6258
   204
                                     width, height, window_flags);
slouken@6258
   205
    if (!*window) {
slouken@6258
   206
        *renderer = NULL;
slouken@6258
   207
        return -1;
slouken@6258
   208
    }
slouken@6258
   209
slouken@6258
   210
    *renderer = SDL_CreateRenderer(*window, -1, 0);
slouken@6258
   211
    if (!*renderer) {
slouken@6258
   212
        return -1;
slouken@6258
   213
    }
slouken@6258
   214
slouken@6258
   215
    return 0;
slouken@6258
   216
}
slouken@6258
   217
slouken@5154
   218
SDL_Renderer *
slouken@5154
   219
SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
slouken@5154
   220
{
slouken@7109
   221
#if !SDL_RENDER_DISABLED
slouken@5154
   222
    SDL_Renderer *renderer = NULL;
slouken@5154
   223
    int n = SDL_GetNumRenderDrivers();
slouken@5192
   224
    const char *hint;
slouken@5192
   225
slouken@5528
   226
    if (!window) {
slouken@5528
   227
        SDL_SetError("Invalid window");
slouken@5528
   228
        return NULL;
slouken@5528
   229
    }
slouken@5528
   230
slouken@5528
   231
    if (SDL_GetRenderer(window)) {
slouken@5528
   232
        SDL_SetError("Renderer already associated with window");
slouken@5528
   233
        return NULL;
slouken@5528
   234
    }
slouken@5528
   235
slouken@5192
   236
    hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC);
slouken@5192
   237
    if (hint) {
slouken@5192
   238
        if (*hint == '0') {
slouken@5192
   239
            flags &= ~SDL_RENDERER_PRESENTVSYNC;
slouken@5192
   240
        } else {
slouken@5192
   241
            flags |= SDL_RENDERER_PRESENTVSYNC;
slouken@5192
   242
        }
slouken@5192
   243
    }
slouken@5154
   244
slouken@5154
   245
    if (index < 0) {
slouken@5192
   246
        hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
slouken@5192
   247
        if (hint) {
slouken@5154
   248
            for (index = 0; index < n; ++index) {
slouken@5154
   249
                const SDL_RenderDriver *driver = render_drivers[index];
slouken@5154
   250
slouken@5192
   251
                if (SDL_strcasecmp(hint, driver->info.name) == 0) {
slouken@5154
   252
                    /* Create a new renderer instance */
slouken@5154
   253
                    renderer = driver->CreateRenderer(window, flags);
slouken@5154
   254
                    break;
slouken@5154
   255
                }
slouken@5154
   256
            }
slouken@5192
   257
        }
slouken@5192
   258
slouken@5192
   259
        if (!renderer) {
slouken@5154
   260
            for (index = 0; index < n; ++index) {
slouken@5154
   261
                const SDL_RenderDriver *driver = render_drivers[index];
slouken@5154
   262
slouken@5154
   263
                if ((driver->info.flags & flags) == flags) {
slouken@5154
   264
                    /* Create a new renderer instance */
slouken@5154
   265
                    renderer = driver->CreateRenderer(window, flags);
slouken@5154
   266
                    if (renderer) {
slouken@5154
   267
                        /* Yay, we got one! */
slouken@5154
   268
                        break;
slouken@5154
   269
                    }
slouken@5154
   270
                }
slouken@5154
   271
            }
slouken@5154
   272
        }
slouken@5154
   273
        if (index == n) {
slouken@5154
   274
            SDL_SetError("Couldn't find matching render driver");
slouken@5154
   275
            return NULL;
slouken@5154
   276
        }
slouken@5154
   277
    } else {
slouken@5154
   278
        if (index >= SDL_GetNumRenderDrivers()) {
slouken@5154
   279
            SDL_SetError("index must be -1 or in the range of 0 - %d",
slouken@5154
   280
                         SDL_GetNumRenderDrivers() - 1);
slouken@5154
   281
            return NULL;
slouken@5154
   282
        }
slouken@5154
   283
        /* Create a new renderer instance */
slouken@5154
   284
        renderer = render_drivers[index]->CreateRenderer(window, flags);
slouken@5154
   285
    }
slouken@5154
   286
slouken@5154
   287
    if (renderer) {
slouken@5154
   288
        renderer->magic = &renderer_magic;
slouken@5166
   289
        renderer->window = window;
slouken@6528
   290
        renderer->scale.x = 1.0f;
slouken@6528
   291
        renderer->scale.y = 1.0f;
slouken@5154
   292
slouken@6260
   293
        if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) {
slouken@6260
   294
            renderer->hidden = SDL_TRUE;
slouken@6060
   295
        } else {
slouken@6260
   296
            renderer->hidden = SDL_FALSE;
slouken@6060
   297
        }
slouken@6060
   298
slouken@5528
   299
        SDL_SetWindowData(window, SDL_WINDOWRENDERDATA, renderer);
slouken@5528
   300
slouken@5297
   301
        SDL_RenderSetViewport(renderer, NULL);
slouken@5297
   302
slouken@5154
   303
        SDL_AddEventWatch(SDL_RendererEventWatch, renderer);
slouken@5221
   304
slouken@5221
   305
        SDL_LogInfo(SDL_LOG_CATEGORY_RENDER,
slouken@5221
   306
                    "Created renderer: %s", renderer->info.name);
slouken@5154
   307
    }
slouken@5154
   308
    return renderer;
slouken@7109
   309
#else
slouken@7109
   310
    SDL_SetError("SDL not built with rendering support");
slouken@7109
   311
    return NULL;
slouken@7109
   312
#endif
slouken@5154
   313
}
slouken@5154
   314
slouken@5166
   315
SDL_Renderer *
slouken@5166
   316
SDL_CreateSoftwareRenderer(SDL_Surface * surface)
slouken@5166
   317
{
slouken@5226
   318
#if !SDL_RENDER_DISABLED
slouken@5297
   319
    SDL_Renderer *renderer;
slouken@5297
   320
slouken@5297
   321
    renderer = SW_CreateRendererForSurface(surface);
slouken@5297
   322
slouken@5297
   323
    if (renderer) {
slouken@5297
   324
        renderer->magic = &renderer_magic;
slouken@6532
   325
        renderer->scale.x = 1.0f;
slouken@6532
   326
        renderer->scale.y = 1.0f;
slouken@5297
   327
slouken@5297
   328
        SDL_RenderSetViewport(renderer, NULL);
slouken@5297
   329
    }
slouken@5297
   330
    return renderer;
slouken@5226
   331
#else
slouken@5226
   332
    SDL_SetError("SDL not built with rendering support");
slouken@5226
   333
    return NULL;
slouken@5226
   334
#endif /* !SDL_RENDER_DISABLED */
slouken@5166
   335
}
slouken@5166
   336
slouken@5528
   337
SDL_Renderer *
slouken@5528
   338
SDL_GetRenderer(SDL_Window * window)
slouken@5528
   339
{
slouken@5528
   340
    return (SDL_Renderer *)SDL_GetWindowData(window, SDL_WINDOWRENDERDATA);
slouken@5528
   341
}
slouken@5528
   342
slouken@5154
   343
int
slouken@5154
   344
SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info)
slouken@5154
   345
{
slouken@5154
   346
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
   347
slouken@5154
   348
    *info = renderer->info;
slouken@5154
   349
    return 0;
slouken@5154
   350
}
slouken@5154
   351
slouken@7239
   352
int
slouken@7239
   353
SDL_GetRendererOutputSize(SDL_Renderer * renderer, int *w, int *h)
slouken@7239
   354
{
slouken@7239
   355
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@7239
   356
slouken@7239
   357
    if (renderer->target) {
slouken@7239
   358
        return SDL_QueryTexture(renderer->target, NULL, NULL, w, h);
urkle@7746
   359
    } else if (renderer->GetOutputSize) {
urkle@7746
   360
        return renderer->GetOutputSize(renderer, w, h);
slouken@7239
   361
    } else if (renderer->window) {
slouken@7239
   362
        SDL_GetWindowSize(renderer->window, w, h);
slouken@7239
   363
        return 0;
slouken@7239
   364
    } else {
icculus@8654
   365
        SDL_assert(0 && "This should never happen");
philipp@7898
   366
        return SDL_SetError("Renderer doesn't support querying output size");
slouken@7239
   367
    }
slouken@7239
   368
}
slouken@7239
   369
slouken@5156
   370
static SDL_bool
slouken@5156
   371
IsSupportedFormat(SDL_Renderer * renderer, Uint32 format)
slouken@5156
   372
{
slouken@5156
   373
    Uint32 i;
slouken@5156
   374
slouken@5156
   375
    for (i = 0; i < renderer->info.num_texture_formats; ++i) {
slouken@5156
   376
        if (renderer->info.texture_formats[i] == format) {
slouken@5156
   377
            return SDL_TRUE;
slouken@5156
   378
        }
slouken@5156
   379
    }
slouken@5156
   380
    return SDL_FALSE;
slouken@5156
   381
}
slouken@5156
   382
slouken@5156
   383
static Uint32
slouken@5156
   384
GetClosestSupportedFormat(SDL_Renderer * renderer, Uint32 format)
slouken@5156
   385
{
slouken@5156
   386
    Uint32 i;
slouken@5156
   387
slouken@5268
   388
    if (SDL_ISPIXELFORMAT_FOURCC(format)) {
slouken@5268
   389
        /* Look for an exact match */
slouken@5268
   390
        for (i = 0; i < renderer->info.num_texture_formats; ++i) {
slouken@5268
   391
            if (renderer->info.texture_formats[i] == format) {
slouken@5268
   392
                return renderer->info.texture_formats[i];
slouken@5268
   393
            }
slouken@5268
   394
        }
slouken@5268
   395
    } else {
slouken@5268
   396
        SDL_bool hasAlpha = SDL_ISPIXELFORMAT_ALPHA(format);
slouken@5268
   397
slouken@5268
   398
        /* We just want to match the first format that has the same channels */
slouken@5268
   399
        for (i = 0; i < renderer->info.num_texture_formats; ++i) {
slouken@5300
   400
            if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
slouken@5300
   401
                SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == hasAlpha) {
slouken@5268
   402
                return renderer->info.texture_formats[i];
slouken@5268
   403
            }
slouken@5156
   404
        }
slouken@5156
   405
    }
slouken@5156
   406
    return renderer->info.texture_formats[0];
slouken@5156
   407
}
slouken@5156
   408
slouken@5154
   409
SDL_Texture *
slouken@5154
   410
SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h)
slouken@5154
   411
{
slouken@5154
   412
    SDL_Texture *texture;
slouken@5154
   413
slouken@5154
   414
    CHECK_RENDERER_MAGIC(renderer, NULL);
slouken@5154
   415
slouken@5413
   416
    if (!format) {
slouken@5413
   417
        format = renderer->info.texture_formats[0];
slouken@5413
   418
    }
icculus@8650
   419
    if (SDL_BYTESPERPIXEL(format) == 0) {
icculus@8650
   420
        SDL_SetError("Invalid texture format");
icculus@8650
   421
        return NULL;
icculus@8650
   422
    }
slouken@5156
   423
    if (SDL_ISPIXELFORMAT_INDEXED(format)) {
slouken@5156
   424
        SDL_SetError("Palettized textures are not supported");
slouken@5156
   425
        return NULL;
slouken@5156
   426
    }
slouken@5154
   427
    if (w <= 0 || h <= 0) {
slouken@5154
   428
        SDL_SetError("Texture dimensions can't be 0");
slouken@5156
   429
        return NULL;
slouken@5154
   430
    }
slouken@7770
   431
    if ((renderer->info.max_texture_width && w > renderer->info.max_texture_width) ||
slouken@7770
   432
        (renderer->info.max_texture_height && h > renderer->info.max_texture_height)) {
slouken@7770
   433
        SDL_SetError("Texture dimensions are limited to %dx%d", renderer->info.max_texture_width, renderer->info.max_texture_height);
slouken@7770
   434
        return NULL;
slouken@7770
   435
    }
slouken@5154
   436
    texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
slouken@5154
   437
    if (!texture) {
slouken@5154
   438
        SDL_OutOfMemory();
slouken@5156
   439
        return NULL;
slouken@5154
   440
    }
slouken@5154
   441
    texture->magic = &texture_magic;
slouken@5154
   442
    texture->format = format;
slouken@5154
   443
    texture->access = access;
slouken@5154
   444
    texture->w = w;
slouken@5154
   445
    texture->h = h;
slouken@5154
   446
    texture->r = 255;
slouken@5154
   447
    texture->g = 255;
slouken@5154
   448
    texture->b = 255;
slouken@5154
   449
    texture->a = 255;
slouken@5154
   450
    texture->renderer = renderer;
slouken@5154
   451
    texture->next = renderer->textures;
slouken@5154
   452
    if (renderer->textures) {
slouken@5154
   453
        renderer->textures->prev = texture;
slouken@5154
   454
    }
slouken@5154
   455
    renderer->textures = texture;
slouken@5154
   456
slouken@5156
   457
    if (IsSupportedFormat(renderer, format)) {
slouken@5156
   458
        if (renderer->CreateTexture(renderer, texture) < 0) {
slouken@5156
   459
            SDL_DestroyTexture(texture);
slouken@5156
   460
            return 0;
slouken@5156
   461
        }
slouken@5156
   462
    } else {
slouken@5156
   463
        texture->native = SDL_CreateTexture(renderer,
slouken@5156
   464
                                GetClosestSupportedFormat(renderer, format),
slouken@5156
   465
                                access, w, h);
slouken@5156
   466
        if (!texture->native) {
slouken@5156
   467
            SDL_DestroyTexture(texture);
slouken@5156
   468
            return NULL;
slouken@5156
   469
        }
slouken@5156
   470
slouken@6497
   471
        /* Swap textures to have texture before texture->native in the list */
slouken@6497
   472
        texture->native->next = texture->next;
slouken@6533
   473
        if (texture->native->next) {
slouken@6533
   474
            texture->native->next->prev = texture->native;
slouken@6533
   475
        }
slouken@6497
   476
        texture->prev = texture->native->prev;
slouken@6533
   477
        if (texture->prev) {
slouken@6533
   478
            texture->prev->next = texture;
slouken@6533
   479
        }
slouken@6497
   480
        texture->native->prev = texture;
slouken@6497
   481
        texture->next = texture->native;
slouken@6497
   482
        renderer->textures = texture;
slouken@6497
   483
slouken@5156
   484
        if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
slouken@5156
   485
            texture->yuv = SDL_SW_CreateYUVTexture(format, w, h);
slouken@5156
   486
            if (!texture->yuv) {
slouken@5156
   487
                SDL_DestroyTexture(texture);
slouken@5156
   488
                return NULL;
slouken@5156
   489
            }
slouken@5156
   490
        } else if (access == SDL_TEXTUREACCESS_STREAMING) {
slouken@5156
   491
            /* The pitch is 4 byte aligned */
slouken@5156
   492
            texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3);
slouken@5342
   493
            texture->pixels = SDL_calloc(1, texture->pitch * h);
slouken@5156
   494
            if (!texture->pixels) {
slouken@5156
   495
                SDL_DestroyTexture(texture);
slouken@5156
   496
                return NULL;
slouken@5156
   497
            }
slouken@5156
   498
        }
slouken@5154
   499
    }
slouken@5154
   500
    return texture;
slouken@5154
   501
}
slouken@5154
   502
slouken@5154
   503
SDL_Texture *
slouken@5158
   504
SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface)
slouken@5154
   505
{
slouken@5158
   506
    const SDL_PixelFormat *fmt;
slouken@5158
   507
    SDL_bool needAlpha;
slouken@5158
   508
    Uint32 i;
slouken@5158
   509
    Uint32 format;
slouken@5158
   510
    SDL_Texture *texture;
slouken@5154
   511
slouken@5154
   512
    CHECK_RENDERER_MAGIC(renderer, NULL);
slouken@5154
   513
slouken@5154
   514
    if (!surface) {
slouken@5154
   515
        SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
slouken@5154
   516
        return NULL;
slouken@5154
   517
    }
slouken@5158
   518
slouken@5158
   519
    /* See what the best texture format is */
slouken@5154
   520
    fmt = surface->format;
slouken@5158
   521
    if (fmt->Amask || SDL_GetColorKey(surface, NULL) == 0) {
slouken@5158
   522
        needAlpha = SDL_TRUE;
slouken@5154
   523
    } else {
slouken@5158
   524
        needAlpha = SDL_FALSE;
slouken@5158
   525
    }
slouken@5158
   526
    format = renderer->info.texture_formats[0];
slouken@5158
   527
    for (i = 0; i < renderer->info.num_texture_formats; ++i) {
slouken@5268
   528
        if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
slouken@5268
   529
            SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) {
slouken@5158
   530
            format = renderer->info.texture_formats[i];
slouken@5158
   531
            break;
slouken@5154
   532
        }
slouken@5154
   533
    }
slouken@5154
   534
slouken@5158
   535
    texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
slouken@5158
   536
                                surface->w, surface->h);
slouken@5154
   537
    if (!texture) {
slouken@5158
   538
        return NULL;
slouken@5154
   539
    }
slouken@5158
   540
slouken@5288
   541
    if (format == surface->format->format) {
slouken@5154
   542
        if (SDL_MUSTLOCK(surface)) {
slouken@5154
   543
            SDL_LockSurface(surface);
slouken@5158
   544
            SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
slouken@5154
   545
            SDL_UnlockSurface(surface);
slouken@5154
   546
        } else {
slouken@5158
   547
            SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
slouken@5154
   548
        }
slouken@5154
   549
    } else {
slouken@5297
   550
        SDL_PixelFormat *dst_fmt;
slouken@5158
   551
        SDL_Surface *temp = NULL;
slouken@5154
   552
slouken@5154
   553
        /* Set up a destination surface for the texture update */
slouken@5297
   554
        dst_fmt = SDL_AllocFormat(format);
slouken@9078
   555
        if (!dst_fmt) {
slouken@9078
   556
           SDL_DestroyTexture(texture);
slouken@9078
   557
           return NULL;
slouken@9078
   558
        }
slouken@5297
   559
        temp = SDL_ConvertSurface(surface, dst_fmt, 0);
slouken@5297
   560
        SDL_FreeFormat(dst_fmt);
slouken@5158
   561
        if (temp) {
slouken@5158
   562
            SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch);
slouken@5158
   563
            SDL_FreeSurface(temp);
slouken@5158
   564
        } else {
slouken@5154
   565
            SDL_DestroyTexture(texture);
slouken@5158
   566
            return NULL;
slouken@5154
   567
        }
slouken@5154
   568
    }
slouken@5154
   569
slouken@5154
   570
    {
slouken@5154
   571
        Uint8 r, g, b, a;
slouken@5154
   572
        SDL_BlendMode blendMode;
slouken@5154
   573
slouken@5154
   574
        SDL_GetSurfaceColorMod(surface, &r, &g, &b);
slouken@5154
   575
        SDL_SetTextureColorMod(texture, r, g, b);
slouken@5154
   576
slouken@5154
   577
        SDL_GetSurfaceAlphaMod(surface, &a);
slouken@5154
   578
        SDL_SetTextureAlphaMod(texture, a);
slouken@5154
   579
slouken@5154
   580
        if (SDL_GetColorKey(surface, NULL) == 0) {
slouken@5154
   581
            /* We converted to a texture with alpha format */
slouken@5154
   582
            SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
slouken@5154
   583
        } else {
slouken@5154
   584
            SDL_GetSurfaceBlendMode(surface, &blendMode);
slouken@5154
   585
            SDL_SetTextureBlendMode(texture, blendMode);
slouken@5154
   586
        }
slouken@5154
   587
    }
slouken@5154
   588
    return texture;
slouken@5154
   589
}
slouken@5154
   590
slouken@5154
   591
int
slouken@5154
   592
SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access,
slouken@5154
   593
                 int *w, int *h)
slouken@5154
   594
{
slouken@5154
   595
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
   596
slouken@5154
   597
    if (format) {
slouken@5154
   598
        *format = texture->format;
slouken@5154
   599
    }
slouken@5154
   600
    if (access) {
slouken@5154
   601
        *access = texture->access;
slouken@5154
   602
    }
slouken@5154
   603
    if (w) {
slouken@5154
   604
        *w = texture->w;
slouken@5154
   605
    }
slouken@5154
   606
    if (h) {
slouken@5154
   607
        *h = texture->h;
slouken@5154
   608
    }
slouken@5154
   609
    return 0;
slouken@5154
   610
}
slouken@5154
   611
slouken@5154
   612
int
slouken@5154
   613
SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
slouken@5154
   614
{
slouken@5154
   615
    SDL_Renderer *renderer;
slouken@5154
   616
slouken@5154
   617
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
   618
slouken@5154
   619
    renderer = texture->renderer;
slouken@5154
   620
    if (r < 255 || g < 255 || b < 255) {
slouken@5154
   621
        texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
slouken@5154
   622
    } else {
slouken@5154
   623
        texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
slouken@5154
   624
    }
slouken@5154
   625
    texture->r = r;
slouken@5154
   626
    texture->g = g;
slouken@5154
   627
    texture->b = b;
slouken@5156
   628
    if (texture->native) {
slouken@5156
   629
        return SDL_SetTextureColorMod(texture->native, r, g, b);
slouken@5156
   630
    } else if (renderer->SetTextureColorMod) {
slouken@5154
   631
        return renderer->SetTextureColorMod(renderer, texture);
slouken@5154
   632
    } else {
slouken@5154
   633
        return 0;
slouken@5154
   634
    }
slouken@5154
   635
}
slouken@5154
   636
slouken@5154
   637
int
slouken@5154
   638
SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g,
slouken@5154
   639
                       Uint8 * b)
slouken@5154
   640
{
slouken@5154
   641
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
   642
slouken@5154
   643
    if (r) {
slouken@5154
   644
        *r = texture->r;
slouken@5154
   645
    }
slouken@5154
   646
    if (g) {
slouken@5154
   647
        *g = texture->g;
slouken@5154
   648
    }
slouken@5154
   649
    if (b) {
slouken@5154
   650
        *b = texture->b;
slouken@5154
   651
    }
slouken@5154
   652
    return 0;
slouken@5154
   653
}
slouken@5154
   654
slouken@5154
   655
int
slouken@5154
   656
SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
slouken@5154
   657
{
slouken@5154
   658
    SDL_Renderer *renderer;
slouken@5154
   659
slouken@5154
   660
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
   661
slouken@5154
   662
    renderer = texture->renderer;
slouken@5154
   663
    if (alpha < 255) {
slouken@5154
   664
        texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
slouken@5154
   665
    } else {
slouken@5154
   666
        texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA;
slouken@5154
   667
    }
slouken@5154
   668
    texture->a = alpha;
slouken@5156
   669
    if (texture->native) {
slouken@5156
   670
        return SDL_SetTextureAlphaMod(texture->native, alpha);
slouken@5156
   671
    } else if (renderer->SetTextureAlphaMod) {
slouken@5154
   672
        return renderer->SetTextureAlphaMod(renderer, texture);
slouken@5154
   673
    } else {
slouken@5154
   674
        return 0;
slouken@5154
   675
    }
slouken@5154
   676
}
slouken@5154
   677
slouken@5154
   678
int
slouken@5154
   679
SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha)
slouken@5154
   680
{
slouken@5154
   681
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
   682
slouken@5154
   683
    if (alpha) {
slouken@5154
   684
        *alpha = texture->a;
slouken@5154
   685
    }
slouken@5154
   686
    return 0;
slouken@5154
   687
}
slouken@5154
   688
slouken@5154
   689
int
slouken@5154
   690
SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode)
slouken@5154
   691
{
slouken@5154
   692
    SDL_Renderer *renderer;
slouken@5154
   693
slouken@5154
   694
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
   695
slouken@5154
   696
    renderer = texture->renderer;
slouken@5154
   697
    texture->blendMode = blendMode;
slouken@5156
   698
    if (texture->native) {
slouken@5180
   699
        return SDL_SetTextureBlendMode(texture->native, blendMode);
slouken@5156
   700
    } else if (renderer->SetTextureBlendMode) {
slouken@5154
   701
        return renderer->SetTextureBlendMode(renderer, texture);
slouken@5154
   702
    } else {
slouken@5154
   703
        return 0;
slouken@5154
   704
    }
slouken@5154
   705
}
slouken@5154
   706
slouken@5154
   707
int
slouken@5154
   708
SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode)
slouken@5154
   709
{
slouken@5154
   710
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
   711
slouken@5154
   712
    if (blendMode) {
slouken@5154
   713
        *blendMode = texture->blendMode;
slouken@5154
   714
    }
slouken@5154
   715
    return 0;
slouken@5154
   716
}
slouken@5154
   717
slouken@5156
   718
static int
slouken@5156
   719
SDL_UpdateTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5156
   720
                     const void *pixels, int pitch)
slouken@5156
   721
{
slouken@5156
   722
    SDL_Texture *native = texture->native;
slouken@5156
   723
    SDL_Rect full_rect;
slouken@5156
   724
slouken@5156
   725
    if (SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch) < 0) {
slouken@5156
   726
        return -1;
slouken@5156
   727
    }
slouken@5156
   728
slouken@5156
   729
    full_rect.x = 0;
slouken@5156
   730
    full_rect.y = 0;
slouken@5156
   731
    full_rect.w = texture->w;
slouken@5156
   732
    full_rect.h = texture->h;
slouken@5156
   733
    rect = &full_rect;
slouken@5156
   734
slouken@5156
   735
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@5156
   736
        /* We can lock the texture and copy to it */
slouken@5156
   737
        void *native_pixels;
slouken@5156
   738
        int native_pitch;
slouken@5156
   739
slouken@5156
   740
        if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
slouken@5156
   741
            return -1;
slouken@5156
   742
        }
slouken@5156
   743
        SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
slouken@5156
   744
                            rect->w, rect->h, native_pixels, native_pitch);
slouken@5156
   745
        SDL_UnlockTexture(native);
slouken@5156
   746
    } else {
slouken@5156
   747
        /* Use a temporary buffer for updating */
slouken@5156
   748
        void *temp_pixels;
slouken@5156
   749
        int temp_pitch;
slouken@5156
   750
slouken@5156
   751
        temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
slouken@5156
   752
        temp_pixels = SDL_malloc(rect->h * temp_pitch);
slouken@5156
   753
        if (!temp_pixels) {
icculus@7037
   754
            return SDL_OutOfMemory();
slouken@5156
   755
        }
slouken@5156
   756
        SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
slouken@5156
   757
                            rect->w, rect->h, temp_pixels, temp_pitch);
slouken@5156
   758
        SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
slouken@5156
   759
        SDL_free(temp_pixels);
slouken@5156
   760
    }
slouken@5156
   761
    return 0;
slouken@5156
   762
}
slouken@5156
   763
slouken@5156
   764
static int
slouken@5156
   765
SDL_UpdateTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5156
   766
                        const void *pixels, int pitch)
slouken@5156
   767
{
slouken@5156
   768
    SDL_Texture *native = texture->native;
slouken@5156
   769
slouken@5156
   770
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@5156
   771
        /* We can lock the texture and copy to it */
slouken@5156
   772
        void *native_pixels;
slouken@5156
   773
        int native_pitch;
slouken@5156
   774
slouken@5156
   775
        if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
slouken@5156
   776
            return -1;
slouken@5156
   777
        }
slouken@5156
   778
        SDL_ConvertPixels(rect->w, rect->h,
slouken@5156
   779
                          texture->format, pixels, pitch,
slouken@5156
   780
                          native->format, native_pixels, native_pitch);
slouken@5156
   781
        SDL_UnlockTexture(native);
slouken@5156
   782
    } else {
slouken@5156
   783
        /* Use a temporary buffer for updating */
slouken@5156
   784
        void *temp_pixels;
slouken@5156
   785
        int temp_pitch;
slouken@5156
   786
slouken@5156
   787
        temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
slouken@5156
   788
        temp_pixels = SDL_malloc(rect->h * temp_pitch);
slouken@5156
   789
        if (!temp_pixels) {
icculus@7037
   790
            return SDL_OutOfMemory();
slouken@5156
   791
        }
slouken@5156
   792
        SDL_ConvertPixels(rect->w, rect->h,
slouken@5156
   793
                          texture->format, pixels, pitch,
slouken@5156
   794
                          native->format, temp_pixels, temp_pitch);
slouken@5156
   795
        SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
slouken@5156
   796
        SDL_free(temp_pixels);
slouken@5156
   797
    }
slouken@5156
   798
    return 0;
slouken@5156
   799
}
slouken@5156
   800
slouken@5154
   801
int
slouken@5154
   802
SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5154
   803
                  const void *pixels, int pitch)
slouken@5154
   804
{
slouken@5154
   805
    SDL_Renderer *renderer;
slouken@5154
   806
    SDL_Rect full_rect;
slouken@5154
   807
slouken@5154
   808
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
   809
slouken@7409
   810
    if (!pixels) {
slouken@7409
   811
        return SDL_InvalidParamError("pixels");
slouken@7409
   812
    }
slouken@7409
   813
    if (!pitch) {
slouken@7409
   814
        return SDL_InvalidParamError("pitch");
slouken@7409
   815
    }
slouken@7409
   816
slouken@5154
   817
    if (!rect) {
slouken@5154
   818
        full_rect.x = 0;
slouken@5154
   819
        full_rect.y = 0;
slouken@5154
   820
        full_rect.w = texture->w;
slouken@5154
   821
        full_rect.h = texture->h;
slouken@5154
   822
        rect = &full_rect;
slouken@5154
   823
    }
slouken@5156
   824
icculus@9636
   825
    if ((rect->w == 0) || (rect->h == 0)) {
icculus@9636
   826
        return 0;  /* nothing to do. */
icculus@9636
   827
    } else if (texture->yuv) {
slouken@5156
   828
        return SDL_UpdateTextureYUV(texture, rect, pixels, pitch);
slouken@5156
   829
    } else if (texture->native) {
slouken@5156
   830
        return SDL_UpdateTextureNative(texture, rect, pixels, pitch);
slouken@5156
   831
    } else {
slouken@5156
   832
        renderer = texture->renderer;
slouken@5156
   833
        return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
slouken@5156
   834
    }
slouken@5156
   835
}
slouken@5156
   836
slouken@5156
   837
static int
slouken@7759
   838
SDL_UpdateTextureYUVPlanar(SDL_Texture * texture, const SDL_Rect * rect,
slouken@7759
   839
                           const Uint8 *Yplane, int Ypitch,
slouken@7759
   840
                           const Uint8 *Uplane, int Upitch,
slouken@7759
   841
                           const Uint8 *Vplane, int Vpitch)
slouken@7759
   842
{
slouken@7759
   843
    SDL_Texture *native = texture->native;
slouken@7759
   844
    SDL_Rect full_rect;
slouken@7759
   845
slouken@7759
   846
    if (SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch) < 0) {
slouken@7759
   847
        return -1;
slouken@7759
   848
    }
slouken@7759
   849
slouken@7759
   850
    full_rect.x = 0;
slouken@7759
   851
    full_rect.y = 0;
slouken@7759
   852
    full_rect.w = texture->w;
slouken@7759
   853
    full_rect.h = texture->h;
slouken@7759
   854
    rect = &full_rect;
slouken@7759
   855
slouken@7759
   856
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@7759
   857
        /* We can lock the texture and copy to it */
slouken@7759
   858
        void *native_pixels;
slouken@7759
   859
        int native_pitch;
slouken@7759
   860
slouken@7759
   861
        if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
slouken@7759
   862
            return -1;
slouken@7759
   863
        }
slouken@7759
   864
        SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
slouken@7759
   865
                            rect->w, rect->h, native_pixels, native_pitch);
slouken@7759
   866
        SDL_UnlockTexture(native);
slouken@7759
   867
    } else {
slouken@7759
   868
        /* Use a temporary buffer for updating */
slouken@7759
   869
        void *temp_pixels;
slouken@7759
   870
        int temp_pitch;
slouken@7759
   871
slouken@7759
   872
        temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
slouken@7759
   873
        temp_pixels = SDL_malloc(rect->h * temp_pitch);
slouken@7759
   874
        if (!temp_pixels) {
slouken@7759
   875
            return SDL_OutOfMemory();
slouken@7759
   876
        }
slouken@7759
   877
        SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
slouken@7759
   878
                            rect->w, rect->h, temp_pixels, temp_pitch);
slouken@7759
   879
        SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
slouken@7759
   880
        SDL_free(temp_pixels);
slouken@7759
   881
    }
slouken@7759
   882
    return 0;
slouken@7759
   883
}
slouken@7759
   884
slouken@7759
   885
int SDL_UpdateYUVTexture(SDL_Texture * texture, const SDL_Rect * rect,
slouken@7759
   886
                         const Uint8 *Yplane, int Ypitch,
slouken@7759
   887
                         const Uint8 *Uplane, int Upitch,
slouken@7759
   888
                         const Uint8 *Vplane, int Vpitch)
slouken@7759
   889
{
slouken@7759
   890
    SDL_Renderer *renderer;
slouken@7759
   891
    SDL_Rect full_rect;
slouken@7759
   892
slouken@7759
   893
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@7759
   894
slouken@7759
   895
    if (!Yplane) {
slouken@7759
   896
        return SDL_InvalidParamError("Yplane");
slouken@7759
   897
    }
slouken@7759
   898
    if (!Ypitch) {
slouken@7759
   899
        return SDL_InvalidParamError("Ypitch");
slouken@7759
   900
    }
slouken@7759
   901
    if (!Uplane) {
slouken@7759
   902
        return SDL_InvalidParamError("Uplane");
slouken@7759
   903
    }
slouken@7759
   904
    if (!Upitch) {
slouken@7759
   905
        return SDL_InvalidParamError("Upitch");
slouken@7759
   906
    }
slouken@7759
   907
    if (!Vplane) {
slouken@7759
   908
        return SDL_InvalidParamError("Vplane");
slouken@7759
   909
    }
slouken@7759
   910
    if (!Vpitch) {
slouken@7759
   911
        return SDL_InvalidParamError("Vpitch");
slouken@7759
   912
    }
slouken@7759
   913
slouken@7759
   914
    if (texture->format != SDL_PIXELFORMAT_YV12 &&
slouken@7759
   915
        texture->format != SDL_PIXELFORMAT_IYUV) {
slouken@7759
   916
        return SDL_SetError("Texture format must by YV12 or IYUV");
slouken@7759
   917
    }
slouken@7759
   918
slouken@7759
   919
    if (!rect) {
slouken@7759
   920
        full_rect.x = 0;
slouken@7759
   921
        full_rect.y = 0;
slouken@7759
   922
        full_rect.w = texture->w;
slouken@7759
   923
        full_rect.h = texture->h;
slouken@7759
   924
        rect = &full_rect;
slouken@7759
   925
    }
slouken@7759
   926
slouken@7759
   927
    if (texture->yuv) {
slouken@7759
   928
        return SDL_UpdateTextureYUVPlanar(texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
slouken@7759
   929
    } else {
slouken@7759
   930
        SDL_assert(!texture->native);
slouken@7759
   931
        renderer = texture->renderer;
slouken@7759
   932
        SDL_assert(renderer->UpdateTextureYUV);
slouken@9084
   933
        if (renderer->UpdateTextureYUV) {
slouken@9084
   934
            return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
slouken@9084
   935
        } else {
slouken@9084
   936
            return SDL_Unsupported();
slouken@9084
   937
        }
slouken@9084
   938
    }
slouken@7759
   939
}
slouken@7759
   940
slouken@7759
   941
static int
slouken@5156
   942
SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5156
   943
                   void **pixels, int *pitch)
slouken@5156
   944
{
slouken@5156
   945
    return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch);
slouken@5156
   946
}
slouken@5156
   947
slouken@5156
   948
static int
slouken@5156
   949
SDL_LockTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5156
   950
                      void **pixels, int *pitch)
slouken@5156
   951
{
slouken@5156
   952
    texture->locked_rect = *rect;
slouken@5156
   953
    *pixels = (void *) ((Uint8 *) texture->pixels +
slouken@5156
   954
                        rect->y * texture->pitch +
slouken@5156
   955
                        rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@5156
   956
    *pitch = texture->pitch;
slouken@5156
   957
    return 0;
slouken@5154
   958
}
slouken@5154
   959
slouken@5154
   960
int
slouken@5156
   961
SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5154
   962
                void **pixels, int *pitch)
slouken@5154
   963
{
slouken@5154
   964
    SDL_Renderer *renderer;
slouken@5154
   965
    SDL_Rect full_rect;
slouken@5154
   966
slouken@5154
   967
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
   968
slouken@5154
   969
    if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
icculus@7037
   970
        return SDL_SetError("SDL_LockTexture(): texture must be streaming");
slouken@5154
   971
    }
slouken@5156
   972
slouken@5154
   973
    if (!rect) {
slouken@5154
   974
        full_rect.x = 0;
slouken@5154
   975
        full_rect.y = 0;
slouken@5154
   976
        full_rect.w = texture->w;
slouken@5154
   977
        full_rect.h = texture->h;
slouken@5154
   978
        rect = &full_rect;
slouken@5154
   979
    }
slouken@5156
   980
slouken@5156
   981
    if (texture->yuv) {
slouken@5156
   982
        return SDL_LockTextureYUV(texture, rect, pixels, pitch);
slouken@5156
   983
    } else if (texture->native) {
slouken@5156
   984
        return SDL_LockTextureNative(texture, rect, pixels, pitch);
slouken@5156
   985
    } else {
slouken@5156
   986
        renderer = texture->renderer;
slouken@5156
   987
        return renderer->LockTexture(renderer, texture, rect, pixels, pitch);
slouken@5156
   988
    }
slouken@5156
   989
}
slouken@5156
   990
slouken@5156
   991
static void
slouken@5156
   992
SDL_UnlockTextureYUV(SDL_Texture * texture)
slouken@5156
   993
{
slouken@5156
   994
    SDL_Texture *native = texture->native;
icculus@8649
   995
    void *native_pixels = NULL;
icculus@8649
   996
    int native_pitch = 0;
slouken@5156
   997
    SDL_Rect rect;
slouken@5156
   998
slouken@5156
   999
    rect.x = 0;
slouken@5156
  1000
    rect.y = 0;
slouken@5156
  1001
    rect.w = texture->w;
slouken@5156
  1002
    rect.h = texture->h;
slouken@5156
  1003
slouken@5156
  1004
    if (SDL_LockTexture(native, &rect, &native_pixels, &native_pitch) < 0) {
slouken@5156
  1005
        return;
slouken@5156
  1006
    }
slouken@5156
  1007
    SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format,
slouken@5156
  1008
                        rect.w, rect.h, native_pixels, native_pitch);
slouken@5156
  1009
    SDL_UnlockTexture(native);
slouken@5156
  1010
}
slouken@5156
  1011
slouken@6044
  1012
static void
slouken@5156
  1013
SDL_UnlockTextureNative(SDL_Texture * texture)
slouken@5156
  1014
{
slouken@5156
  1015
    SDL_Texture *native = texture->native;
icculus@8649
  1016
    void *native_pixels = NULL;
icculus@8649
  1017
    int native_pitch = 0;
slouken@5156
  1018
    const SDL_Rect *rect = &texture->locked_rect;
slouken@5156
  1019
    const void* pixels = (void *) ((Uint8 *) texture->pixels +
slouken@5156
  1020
                        rect->y * texture->pitch +
slouken@5156
  1021
                        rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@5156
  1022
    int pitch = texture->pitch;
slouken@5156
  1023
slouken@5156
  1024
    if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
slouken@5156
  1025
        return;
slouken@5156
  1026
    }
slouken@5156
  1027
    SDL_ConvertPixels(rect->w, rect->h,
slouken@5156
  1028
                      texture->format, pixels, pitch,
slouken@5156
  1029
                      native->format, native_pixels, native_pitch);
slouken@5156
  1030
    SDL_UnlockTexture(native);
slouken@5154
  1031
}
slouken@5154
  1032
slouken@5154
  1033
void
slouken@5154
  1034
SDL_UnlockTexture(SDL_Texture * texture)
slouken@5154
  1035
{
slouken@5154
  1036
    SDL_Renderer *renderer;
slouken@5154
  1037
slouken@5154
  1038
    CHECK_TEXTURE_MAGIC(texture, );
slouken@5154
  1039
slouken@5154
  1040
    if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
slouken@5154
  1041
        return;
slouken@5154
  1042
    }
slouken@5156
  1043
    if (texture->yuv) {
slouken@5156
  1044
        SDL_UnlockTextureYUV(texture);
slouken@5156
  1045
    } else if (texture->native) {
slouken@5156
  1046
        SDL_UnlockTextureNative(texture);
slouken@5156
  1047
    } else {
slouken@5156
  1048
        renderer = texture->renderer;
slouken@5156
  1049
        renderer->UnlockTexture(renderer, texture);
slouken@5154
  1050
    }
slouken@5154
  1051
}
slouken@5154
  1052
slouken@6246
  1053
SDL_bool
slouken@6246
  1054
SDL_RenderTargetSupported(SDL_Renderer *renderer)
slouken@6246
  1055
{
slouken@6247
  1056
    if (!renderer || !renderer->SetRenderTarget) {
slouken@6246
  1057
        return SDL_FALSE;
slouken@6246
  1058
    }
slouken@6246
  1059
    return (renderer->info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
slouken@6246
  1060
}
slouken@6246
  1061
slouken@6246
  1062
int
slouken@6247
  1063
SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
slouken@6246
  1064
{
slouken@6246
  1065
    if (!SDL_RenderTargetSupported(renderer)) {
icculus@7037
  1066
        return SDL_Unsupported();
slouken@6246
  1067
    }
slouken@6246
  1068
    if (texture == renderer->target) {
slouken@6246
  1069
        /* Nothing to do! */
slouken@6246
  1070
        return 0;
slouken@6246
  1071
    }
slouken@6246
  1072
slouken@6246
  1073
    /* texture == NULL is valid and means reset the target to the window */
slouken@6246
  1074
    if (texture) {
slouken@6246
  1075
        CHECK_TEXTURE_MAGIC(texture, -1);
slouken@6246
  1076
        if (renderer != texture->renderer) {
icculus@7037
  1077
            return SDL_SetError("Texture was not created with this renderer");
slouken@6246
  1078
        }
gabomdq@6337
  1079
        if (texture->access != SDL_TEXTUREACCESS_TARGET) {
icculus@7037
  1080
            return SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET");
slouken@6246
  1081
        }
slouken@6246
  1082
        if (texture->native) {
slouken@6246
  1083
            /* Always render to the native texture */
slouken@6246
  1084
            texture = texture->native;
slouken@6246
  1085
        }
slouken@6246
  1086
    }
slouken@6246
  1087
slouken@6246
  1088
    if (texture && !renderer->target) {
slouken@6246
  1089
        /* Make a backup of the viewport */
slouken@6246
  1090
        renderer->viewport_backup = renderer->viewport;
slouken@7141
  1091
        renderer->clip_rect_backup = renderer->clip_rect;
jorgenpt@8728
  1092
        renderer->clipping_enabled_backup = renderer->clipping_enabled;
slouken@6528
  1093
        renderer->scale_backup = renderer->scale;
slouken@6581
  1094
        renderer->logical_w_backup = renderer->logical_w;
slouken@6581
  1095
        renderer->logical_h_backup = renderer->logical_h;
slouken@6246
  1096
    }
slouken@6246
  1097
    renderer->target = texture;
slouken@6246
  1098
slouken@6247
  1099
    if (renderer->SetRenderTarget(renderer, texture) < 0) {
slouken@6246
  1100
        return -1;
slouken@6246
  1101
    }
slouken@6246
  1102
slouken@6246
  1103
    if (texture) {
slouken@6528
  1104
        renderer->viewport.x = 0;
slouken@6528
  1105
        renderer->viewport.y = 0;
slouken@6528
  1106
        renderer->viewport.w = texture->w;
slouken@6528
  1107
        renderer->viewport.h = texture->h;
slouken@6528
  1108
        renderer->scale.x = 1.0f;
slouken@6528
  1109
        renderer->scale.y = 1.0f;
slouken@7339
  1110
        renderer->logical_w = texture->w;
slouken@7339
  1111
        renderer->logical_h = texture->h;
slouken@6246
  1112
    } else {
slouken@6528
  1113
        renderer->viewport = renderer->viewport_backup;
slouken@7141
  1114
        renderer->clip_rect = renderer->clip_rect_backup;
jorgenpt@8728
  1115
        renderer->clipping_enabled = renderer->clipping_enabled_backup;
slouken@6528
  1116
        renderer->scale = renderer->scale_backup;
slouken@6581
  1117
        renderer->logical_w = renderer->logical_w_backup;
slouken@6581
  1118
        renderer->logical_h = renderer->logical_h_backup;
slouken@6246
  1119
    }
slouken@6528
  1120
    if (renderer->UpdateViewport(renderer) < 0) {
slouken@6246
  1121
        return -1;
slouken@6246
  1122
    }
slouken@7141
  1123
    if (renderer->UpdateClipRect(renderer) < 0) {
slouken@7141
  1124
        return -1;
slouken@7141
  1125
    }
slouken@6246
  1126
slouken@6246
  1127
    /* All set! */
slouken@6246
  1128
    return 0;
slouken@6246
  1129
}
slouken@6246
  1130
slouken@6578
  1131
SDL_Texture *
slouken@6578
  1132
SDL_GetRenderTarget(SDL_Renderer *renderer)
slouken@6578
  1133
{
slouken@6578
  1134
    return renderer->target;
slouken@6578
  1135
}
slouken@6578
  1136
slouken@6530
  1137
static int
slouken@6530
  1138
UpdateLogicalSize(SDL_Renderer *renderer)
slouken@6530
  1139
{
icculus@8654
  1140
    int w = 1, h = 1;
slouken@6530
  1141
    float want_aspect;
slouken@6530
  1142
    float real_aspect;
slouken@6530
  1143
    float scale;
slouken@6530
  1144
    SDL_Rect viewport;
slouken@6530
  1145
slouken@7239
  1146
    if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) {
slouken@7239
  1147
        return -1;
slouken@6530
  1148
    }
slouken@6530
  1149
slouken@6530
  1150
    want_aspect = (float)renderer->logical_w / renderer->logical_h;
slouken@6530
  1151
    real_aspect = (float)w / h;
slouken@6530
  1152
slouken@6530
  1153
    /* Clear the scale because we're setting viewport in output coordinates */
slouken@6530
  1154
    SDL_RenderSetScale(renderer, 1.0f, 1.0f);
slouken@6530
  1155
slouken@6530
  1156
    if (SDL_fabs(want_aspect-real_aspect) < 0.0001) {
slouken@6530
  1157
        /* The aspect ratios are the same, just scale appropriately */
slouken@6530
  1158
        scale = (float)w / renderer->logical_w;
slouken@6530
  1159
        SDL_RenderSetViewport(renderer, NULL);
slouken@6530
  1160
    } else if (want_aspect > real_aspect) {
slouken@6530
  1161
        /* We want a wider aspect ratio than is available - letterbox it */
slouken@6530
  1162
        scale = (float)w / renderer->logical_w;
slouken@6530
  1163
        viewport.x = 0;
slouken@6530
  1164
        viewport.w = w;
slouken@6530
  1165
        viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
slouken@6530
  1166
        viewport.y = (h - viewport.h) / 2;
slouken@6530
  1167
        SDL_RenderSetViewport(renderer, &viewport);
slouken@6530
  1168
    } else {
slouken@6530
  1169
        /* We want a narrower aspect ratio than is available - use side-bars */
slouken@6530
  1170
        scale = (float)h / renderer->logical_h;
slouken@6530
  1171
        viewport.y = 0;
slouken@6530
  1172
        viewport.h = h;
slouken@6530
  1173
        viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
slouken@6530
  1174
        viewport.x = (w - viewport.w) / 2;
slouken@6530
  1175
        SDL_RenderSetViewport(renderer, &viewport);
slouken@6530
  1176
    }
slouken@6530
  1177
slouken@6530
  1178
    /* Set the new scale */
slouken@6530
  1179
    SDL_RenderSetScale(renderer, scale, scale);
slouken@6531
  1180
slouken@6531
  1181
    return 0;
slouken@6530
  1182
}
slouken@6530
  1183
slouken@6530
  1184
int
slouken@6530
  1185
SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h)
slouken@6530
  1186
{
slouken@6530
  1187
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@6530
  1188
slouken@6530
  1189
    if (!w || !h) {
slouken@6530
  1190
        /* Clear any previous logical resolution */
slouken@6530
  1191
        renderer->logical_w = 0;
slouken@6530
  1192
        renderer->logical_h = 0;
slouken@6530
  1193
        SDL_RenderSetViewport(renderer, NULL);
slouken@6530
  1194
        SDL_RenderSetScale(renderer, 1.0f, 1.0f);
slouken@6530
  1195
        return 0;
slouken@6530
  1196
    }
slouken@6530
  1197
slouken@6530
  1198
    renderer->logical_w = w;
slouken@6530
  1199
    renderer->logical_h = h;
slouken@6530
  1200
slouken@6530
  1201
    return UpdateLogicalSize(renderer);
slouken@6530
  1202
}
slouken@6530
  1203
slouken@6530
  1204
void
slouken@6530
  1205
SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h)
slouken@6530
  1206
{
slouken@6530
  1207
    CHECK_RENDERER_MAGIC(renderer, );
slouken@6530
  1208
slouken@6530
  1209
    if (w) {
slouken@6530
  1210
        *w = renderer->logical_w;
slouken@6530
  1211
    }
slouken@6530
  1212
    if (h) {
slouken@6530
  1213
        *h = renderer->logical_h;
slouken@6530
  1214
    }
slouken@6530
  1215
}
slouken@6530
  1216
slouken@5297
  1217
int
slouken@5297
  1218
SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
slouken@5297
  1219
{
slouken@5297
  1220
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5297
  1221
slouken@5297
  1222
    if (rect) {
slouken@6528
  1223
        renderer->viewport.x = (int)SDL_floor(rect->x * renderer->scale.x);
slouken@6528
  1224
        renderer->viewport.y = (int)SDL_floor(rect->y * renderer->scale.y);
slouken@6528
  1225
        renderer->viewport.w = (int)SDL_ceil(rect->w * renderer->scale.x);
slouken@6528
  1226
        renderer->viewport.h = (int)SDL_ceil(rect->h * renderer->scale.y);
slouken@5297
  1227
    } else {
slouken@5297
  1228
        renderer->viewport.x = 0;
slouken@5297
  1229
        renderer->viewport.y = 0;
slouken@7239
  1230
        if (SDL_GetRendererOutputSize(renderer, &renderer->viewport.w, &renderer->viewport.h) < 0) {
slouken@7239
  1231
            return -1;
slouken@5297
  1232
        }
slouken@5297
  1233
    }
slouken@5297
  1234
    return renderer->UpdateViewport(renderer);
slouken@5297
  1235
}
slouken@5297
  1236
slouken@5224
  1237
void
slouken@5297
  1238
SDL_RenderGetViewport(SDL_Renderer * renderer, SDL_Rect * rect)
slouken@5224
  1239
{
slouken@5224
  1240
    CHECK_RENDERER_MAGIC(renderer, );
slouken@5224
  1241
slouken@6528
  1242
    if (rect) {
slouken@6528
  1243
        rect->x = (int)(renderer->viewport.x / renderer->scale.x);
slouken@6528
  1244
        rect->y = (int)(renderer->viewport.y / renderer->scale.y);
slouken@6528
  1245
        rect->w = (int)(renderer->viewport.w / renderer->scale.x);
slouken@6528
  1246
        rect->h = (int)(renderer->viewport.h / renderer->scale.y);
slouken@6528
  1247
    }
slouken@6528
  1248
}
slouken@6528
  1249
slouken@6528
  1250
int
slouken@7141
  1251
SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
slouken@7141
  1252
{
philipp@7143
  1253
    CHECK_RENDERER_MAGIC(renderer, -1)
slouken@7141
  1254
slouken@7141
  1255
    if (rect) {
jorgenpt@8728
  1256
        renderer->clipping_enabled = SDL_TRUE;
slouken@7141
  1257
        renderer->clip_rect.x = (int)SDL_floor(rect->x * renderer->scale.x);
slouken@7141
  1258
        renderer->clip_rect.y = (int)SDL_floor(rect->y * renderer->scale.y);
slouken@7141
  1259
        renderer->clip_rect.w = (int)SDL_ceil(rect->w * renderer->scale.x);
slouken@7141
  1260
        renderer->clip_rect.h = (int)SDL_ceil(rect->h * renderer->scale.y);
slouken@7141
  1261
    } else {
jorgenpt@8728
  1262
        renderer->clipping_enabled = SDL_FALSE;
slouken@7141
  1263
        SDL_zero(renderer->clip_rect);
slouken@7141
  1264
    }
slouken@7141
  1265
    return renderer->UpdateClipRect(renderer);
slouken@7141
  1266
}
slouken@7141
  1267
slouken@7141
  1268
void
slouken@7141
  1269
SDL_RenderGetClipRect(SDL_Renderer * renderer, SDL_Rect * rect)
slouken@7141
  1270
{
slouken@7141
  1271
    CHECK_RENDERER_MAGIC(renderer, )
slouken@7141
  1272
slouken@7141
  1273
    if (rect) {
slouken@7141
  1274
        rect->x = (int)(renderer->clip_rect.x / renderer->scale.x);
slouken@7141
  1275
        rect->y = (int)(renderer->clip_rect.y / renderer->scale.y);
slouken@7141
  1276
        rect->w = (int)(renderer->clip_rect.w / renderer->scale.x);
slouken@7141
  1277
        rect->h = (int)(renderer->clip_rect.h / renderer->scale.y);
slouken@7141
  1278
    }
slouken@7141
  1279
}
slouken@7141
  1280
jorgenpt@8728
  1281
SDL_bool
jorgenpt@8728
  1282
SDL_RenderIsClipEnabled(SDL_Renderer * renderer)
jorgenpt@8728
  1283
{
jorgenpt@8728
  1284
    CHECK_RENDERER_MAGIC(renderer, SDL_FALSE)
jorgenpt@8728
  1285
    return renderer->clipping_enabled;
jorgenpt@8728
  1286
}
jorgenpt@8728
  1287
slouken@7141
  1288
int
slouken@6528
  1289
SDL_RenderSetScale(SDL_Renderer * renderer, float scaleX, float scaleY)
slouken@6528
  1290
{
slouken@6528
  1291
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@6528
  1292
slouken@6528
  1293
    renderer->scale.x = scaleX;
slouken@6528
  1294
    renderer->scale.y = scaleY;
slouken@6528
  1295
    return 0;
slouken@6528
  1296
}
slouken@6528
  1297
slouken@6528
  1298
void
slouken@6528
  1299
SDL_RenderGetScale(SDL_Renderer * renderer, float *scaleX, float *scaleY)
slouken@6528
  1300
{
slouken@6528
  1301
    CHECK_RENDERER_MAGIC(renderer, );
slouken@6528
  1302
slouken@6528
  1303
    if (scaleX) {
slouken@6528
  1304
        *scaleX = renderer->scale.x;
slouken@6528
  1305
    }
slouken@6528
  1306
    if (scaleY) {
slouken@6528
  1307
        *scaleY = renderer->scale.y;
slouken@6528
  1308
    }
slouken@5224
  1309
}
slouken@5224
  1310
slouken@5154
  1311
int
slouken@5154
  1312
SDL_SetRenderDrawColor(SDL_Renderer * renderer,
slouken@5154
  1313
                       Uint8 r, Uint8 g, Uint8 b, Uint8 a)
slouken@5154
  1314
{
slouken@5154
  1315
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1316
slouken@5154
  1317
    renderer->r = r;
slouken@5154
  1318
    renderer->g = g;
slouken@5154
  1319
    renderer->b = b;
slouken@5154
  1320
    renderer->a = a;
slouken@5154
  1321
    return 0;
slouken@5154
  1322
}
slouken@5154
  1323
slouken@5154
  1324
int
slouken@5154
  1325
SDL_GetRenderDrawColor(SDL_Renderer * renderer,
slouken@5154
  1326
                       Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
slouken@5154
  1327
{
slouken@5154
  1328
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1329
slouken@5154
  1330
    if (r) {
slouken@5154
  1331
        *r = renderer->r;
slouken@5154
  1332
    }
slouken@5154
  1333
    if (g) {
slouken@5154
  1334
        *g = renderer->g;
slouken@5154
  1335
    }
slouken@5154
  1336
    if (b) {
slouken@5154
  1337
        *b = renderer->b;
slouken@5154
  1338
    }
slouken@5154
  1339
    if (a) {
slouken@5154
  1340
        *a = renderer->a;
slouken@5154
  1341
    }
slouken@5154
  1342
    return 0;
slouken@5154
  1343
}
slouken@5154
  1344
slouken@5154
  1345
int
slouken@5154
  1346
SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
slouken@5154
  1347
{
slouken@5154
  1348
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1349
slouken@5154
  1350
    renderer->blendMode = blendMode;
slouken@5154
  1351
    return 0;
slouken@5154
  1352
}
slouken@5154
  1353
slouken@5154
  1354
int
slouken@5154
  1355
SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
slouken@5154
  1356
{
slouken@5154
  1357
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1358
slouken@5154
  1359
    *blendMode = renderer->blendMode;
slouken@5154
  1360
    return 0;
slouken@5154
  1361
}
slouken@5154
  1362
slouken@5154
  1363
int
slouken@5154
  1364
SDL_RenderClear(SDL_Renderer * renderer)
slouken@5154
  1365
{
slouken@5154
  1366
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1367
slouken@6260
  1368
    /* Don't draw while we're hidden */
slouken@6260
  1369
    if (renderer->hidden) {
slouken@6060
  1370
        return 0;
slouken@6060
  1371
    }
slouken@5154
  1372
    return renderer->RenderClear(renderer);
slouken@5154
  1373
}
slouken@5154
  1374
slouken@5154
  1375
int
slouken@5154
  1376
SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
slouken@5154
  1377
{
slouken@5154
  1378
    SDL_Point point;
slouken@5154
  1379
slouken@5154
  1380
    point.x = x;
slouken@5154
  1381
    point.y = y;
slouken@5154
  1382
    return SDL_RenderDrawPoints(renderer, &point, 1);
slouken@5154
  1383
}
slouken@5154
  1384
slouken@6528
  1385
static int
slouken@6528
  1386
RenderDrawPointsWithRects(SDL_Renderer * renderer,
slouken@6528
  1387
                     const SDL_Point * points, int count)
slouken@6528
  1388
{
slouken@6528
  1389
    SDL_FRect *frects;
slouken@6528
  1390
    int i;
slouken@6528
  1391
    int status;
slouken@6528
  1392
slouken@6528
  1393
    frects = SDL_stack_alloc(SDL_FRect, count);
slouken@6528
  1394
    if (!frects) {
icculus@7037
  1395
        return SDL_OutOfMemory();
slouken@6528
  1396
    }
slouken@6528
  1397
    for (i = 0; i < count; ++i) {
slouken@6528
  1398
        frects[i].x = points[i].x * renderer->scale.x;
slouken@6528
  1399
        frects[i].y = points[i].y * renderer->scale.y;
slouken@6528
  1400
        frects[i].w = renderer->scale.x;
slouken@6528
  1401
        frects[i].h = renderer->scale.y;
slouken@6528
  1402
    }
slouken@6528
  1403
slouken@6528
  1404
    status = renderer->RenderFillRects(renderer, frects, count);
slouken@6528
  1405
slouken@6528
  1406
    SDL_stack_free(frects);
slouken@6528
  1407
slouken@6528
  1408
    return status;
slouken@6528
  1409
}
slouken@6528
  1410
slouken@5154
  1411
int
slouken@5154
  1412
SDL_RenderDrawPoints(SDL_Renderer * renderer,
slouken@5154
  1413
                     const SDL_Point * points, int count)
slouken@5154
  1414
{
slouken@6528
  1415
    SDL_FPoint *fpoints;
slouken@6528
  1416
    int i;
slouken@6528
  1417
    int status;
slouken@6528
  1418
slouken@5154
  1419
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1420
slouken@5154
  1421
    if (!points) {
icculus@7037
  1422
        return SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
slouken@5154
  1423
    }
slouken@5154
  1424
    if (count < 1) {
slouken@5154
  1425
        return 0;
slouken@5154
  1426
    }
slouken@6260
  1427
    /* Don't draw while we're hidden */
slouken@6260
  1428
    if (renderer->hidden) {
slouken@6060
  1429
        return 0;
slouken@6060
  1430
    }
slouken@6528
  1431
slouken@6528
  1432
    if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
slouken@6528
  1433
        return RenderDrawPointsWithRects(renderer, points, count);
slouken@6528
  1434
    }
slouken@6528
  1435
slouken@6528
  1436
    fpoints = SDL_stack_alloc(SDL_FPoint, count);
slouken@6528
  1437
    if (!fpoints) {
icculus@7037
  1438
        return SDL_OutOfMemory();
slouken@6528
  1439
    }
slouken@6528
  1440
    for (i = 0; i < count; ++i) {
slouken@6528
  1441
        fpoints[i].x = points[i].x * renderer->scale.x;
slouken@6528
  1442
        fpoints[i].y = points[i].y * renderer->scale.y;
slouken@6528
  1443
    }
slouken@6528
  1444
slouken@6528
  1445
    status = renderer->RenderDrawPoints(renderer, fpoints, count);
slouken@6528
  1446
slouken@6528
  1447
    SDL_stack_free(fpoints);
slouken@6528
  1448
slouken@6528
  1449
    return status;
slouken@5154
  1450
}
slouken@5154
  1451
slouken@5154
  1452
int
slouken@5154
  1453
SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
slouken@5154
  1454
{
slouken@5154
  1455
    SDL_Point points[2];
slouken@5154
  1456
slouken@5154
  1457
    points[0].x = x1;
slouken@5154
  1458
    points[0].y = y1;
slouken@5154
  1459
    points[1].x = x2;
slouken@5154
  1460
    points[1].y = y2;
slouken@5154
  1461
    return SDL_RenderDrawLines(renderer, points, 2);
slouken@5154
  1462
}
slouken@5154
  1463
slouken@6528
  1464
static int
slouken@6528
  1465
RenderDrawLinesWithRects(SDL_Renderer * renderer,
slouken@6528
  1466
                     const SDL_Point * points, int count)
slouken@6528
  1467
{
slouken@6528
  1468
    SDL_FRect *frect;
slouken@6528
  1469
    SDL_FRect *frects;
slouken@6528
  1470
    SDL_FPoint fpoints[2];
slouken@6528
  1471
    int i, nrects;
slouken@6528
  1472
    int status;
slouken@6528
  1473
slouken@6528
  1474
    frects = SDL_stack_alloc(SDL_FRect, count-1);
slouken@6528
  1475
    if (!frects) {
icculus@7037
  1476
        return SDL_OutOfMemory();
slouken@6528
  1477
    }
slouken@6528
  1478
slouken@6528
  1479
    status = 0;
slouken@6528
  1480
    nrects = 0;
slouken@6528
  1481
    for (i = 0; i < count-1; ++i) {
slouken@6528
  1482
        if (points[i].x == points[i+1].x) {
slouken@6528
  1483
            int minY = SDL_min(points[i].y, points[i+1].y);
slouken@6528
  1484
            int maxY = SDL_max(points[i].y, points[i+1].y);
slouken@6528
  1485
slouken@6528
  1486
            frect = &frects[nrects++];
slouken@6528
  1487
            frect->x = points[i].x * renderer->scale.x;
slouken@6528
  1488
            frect->y = minY * renderer->scale.y;
slouken@6528
  1489
            frect->w = renderer->scale.x;
slouken@6528
  1490
            frect->h = (maxY - minY + 1) * renderer->scale.y;
slouken@6528
  1491
        } else if (points[i].y == points[i+1].y) {
slouken@6528
  1492
            int minX = SDL_min(points[i].x, points[i+1].x);
slouken@6528
  1493
            int maxX = SDL_max(points[i].x, points[i+1].x);
slouken@6528
  1494
slouken@6528
  1495
            frect = &frects[nrects++];
slouken@6528
  1496
            frect->x = minX * renderer->scale.x;
slouken@6528
  1497
            frect->y = points[i].y * renderer->scale.y;
slouken@6528
  1498
            frect->w = (maxX - minX + 1) * renderer->scale.x;
slouken@6528
  1499
            frect->h = renderer->scale.y;
slouken@6528
  1500
        } else {
slouken@6528
  1501
            /* FIXME: We can't use a rect for this line... */
aschiffler@7073
  1502
            fpoints[0].x = points[i].x * renderer->scale.x;
aschiffler@7073
  1503
            fpoints[0].y = points[i].y * renderer->scale.y;
aschiffler@7073
  1504
            fpoints[1].x = points[i+1].x * renderer->scale.x;
aschiffler@7073
  1505
            fpoints[1].y = points[i+1].y * renderer->scale.y;
slouken@6528
  1506
            status += renderer->RenderDrawLines(renderer, fpoints, 2);
slouken@6528
  1507
        }
slouken@6528
  1508
    }
slouken@6528
  1509
slouken@6528
  1510
    status += renderer->RenderFillRects(renderer, frects, nrects);
slouken@6528
  1511
slouken@6528
  1512
    SDL_stack_free(frects);
slouken@6528
  1513
slouken@6528
  1514
    if (status < 0) {
slouken@6528
  1515
        status = -1;
slouken@6528
  1516
    }
slouken@6528
  1517
    return status;
slouken@6528
  1518
}
slouken@6528
  1519
slouken@5154
  1520
int
slouken@5154
  1521
SDL_RenderDrawLines(SDL_Renderer * renderer,
slouken@5154
  1522
                    const SDL_Point * points, int count)
slouken@5154
  1523
{
slouken@6528
  1524
    SDL_FPoint *fpoints;
slouken@6528
  1525
    int i;
slouken@6528
  1526
    int status;
slouken@6528
  1527
slouken@5154
  1528
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1529
slouken@5154
  1530
    if (!points) {
icculus@7037
  1531
        return SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
slouken@5154
  1532
    }
slouken@5154
  1533
    if (count < 2) {
slouken@5154
  1534
        return 0;
slouken@5154
  1535
    }
slouken@6260
  1536
    /* Don't draw while we're hidden */
slouken@6260
  1537
    if (renderer->hidden) {
slouken@6060
  1538
        return 0;
slouken@6060
  1539
    }
slouken@6528
  1540
slouken@6528
  1541
    if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
slouken@6528
  1542
        return RenderDrawLinesWithRects(renderer, points, count);
slouken@6528
  1543
    }
slouken@6528
  1544
slouken@6528
  1545
    fpoints = SDL_stack_alloc(SDL_FPoint, count);
slouken@6528
  1546
    if (!fpoints) {
icculus@7037
  1547
        return SDL_OutOfMemory();
slouken@6528
  1548
    }
slouken@6528
  1549
    for (i = 0; i < count; ++i) {
slouken@6528
  1550
        fpoints[i].x = points[i].x * renderer->scale.x;
slouken@6528
  1551
        fpoints[i].y = points[i].y * renderer->scale.y;
slouken@6528
  1552
    }
slouken@6528
  1553
slouken@6528
  1554
    status = renderer->RenderDrawLines(renderer, fpoints, count);
slouken@6528
  1555
slouken@6528
  1556
    SDL_stack_free(fpoints);
slouken@6528
  1557
slouken@6528
  1558
    return status;
slouken@5154
  1559
}
slouken@5154
  1560
slouken@5154
  1561
int
slouken@5154
  1562
SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
slouken@5154
  1563
{
slouken@5154
  1564
    SDL_Rect full_rect;
slouken@5154
  1565
    SDL_Point points[5];
slouken@5154
  1566
slouken@5154
  1567
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1568
slouken@5154
  1569
    /* If 'rect' == NULL, then outline the whole surface */
slouken@5154
  1570
    if (!rect) {
slouken@6528
  1571
        SDL_RenderGetViewport(renderer, &full_rect);
slouken@5154
  1572
        full_rect.x = 0;
slouken@5154
  1573
        full_rect.y = 0;
slouken@5154
  1574
        rect = &full_rect;
slouken@5154
  1575
    }
slouken@5154
  1576
slouken@5154
  1577
    points[0].x = rect->x;
slouken@5154
  1578
    points[0].y = rect->y;
slouken@5154
  1579
    points[1].x = rect->x+rect->w-1;
slouken@5154
  1580
    points[1].y = rect->y;
slouken@5154
  1581
    points[2].x = rect->x+rect->w-1;
slouken@5154
  1582
    points[2].y = rect->y+rect->h-1;
slouken@5154
  1583
    points[3].x = rect->x;
slouken@5154
  1584
    points[3].y = rect->y+rect->h-1;
slouken@5154
  1585
    points[4].x = rect->x;
slouken@5154
  1586
    points[4].y = rect->y;
slouken@5154
  1587
    return SDL_RenderDrawLines(renderer, points, 5);
slouken@5154
  1588
}
slouken@5154
  1589
slouken@5154
  1590
int
slouken@5154
  1591
SDL_RenderDrawRects(SDL_Renderer * renderer,
slouken@5297
  1592
                    const SDL_Rect * rects, int count)
slouken@5154
  1593
{
slouken@5154
  1594
    int i;
slouken@5154
  1595
slouken@5154
  1596
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1597
slouken@5154
  1598
    if (!rects) {
icculus@7037
  1599
        return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
slouken@5154
  1600
    }
slouken@5154
  1601
    if (count < 1) {
slouken@5154
  1602
        return 0;
slouken@5154
  1603
    }
slouken@5154
  1604
slouken@6260
  1605
    /* Don't draw while we're hidden */
slouken@6260
  1606
    if (renderer->hidden) {
slouken@6060
  1607
        return 0;
slouken@6060
  1608
    }
slouken@5154
  1609
    for (i = 0; i < count; ++i) {
slouken@5297
  1610
        if (SDL_RenderDrawRect(renderer, &rects[i]) < 0) {
slouken@5154
  1611
            return -1;
slouken@5154
  1612
        }
slouken@5154
  1613
    }
slouken@5154
  1614
    return 0;
slouken@5154
  1615
}
slouken@5154
  1616
slouken@5154
  1617
int
slouken@5154
  1618
SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
slouken@5154
  1619
{
slouken@7511
  1620
    SDL_Rect full_rect = { 0, 0, 0, 0 };
slouken@6232
  1621
slouken@5331
  1622
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@6232
  1623
slouken@5331
  1624
    /* If 'rect' == NULL, then outline the whole surface */
slouken@5331
  1625
    if (!rect) {
slouken@6528
  1626
        SDL_RenderGetViewport(renderer, &full_rect);
slouken@5331
  1627
        full_rect.x = 0;
slouken@5331
  1628
        full_rect.y = 0;
slouken@5331
  1629
        rect = &full_rect;
slouken@5331
  1630
    }
slouken@5297
  1631
    return SDL_RenderFillRects(renderer, rect, 1);
slouken@5154
  1632
}
slouken@5154
  1633
slouken@5154
  1634
int
slouken@5154
  1635
SDL_RenderFillRects(SDL_Renderer * renderer,
slouken@5297
  1636
                    const SDL_Rect * rects, int count)
slouken@5154
  1637
{
slouken@6528
  1638
    SDL_FRect *frects;
slouken@6528
  1639
    int i;
slouken@6528
  1640
    int status;
slouken@6528
  1641
slouken@5154
  1642
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1643
slouken@5154
  1644
    if (!rects) {
icculus@7037
  1645
        return SDL_SetError("SDL_RenderFillRects(): Passed NULL rects");
slouken@5154
  1646
    }
slouken@5154
  1647
    if (count < 1) {
slouken@5154
  1648
        return 0;
slouken@5154
  1649
    }
slouken@6260
  1650
    /* Don't draw while we're hidden */
slouken@6260
  1651
    if (renderer->hidden) {
slouken@6060
  1652
        return 0;
slouken@6060
  1653
    }
slouken@6528
  1654
slouken@6528
  1655
    frects = SDL_stack_alloc(SDL_FRect, count);
slouken@6528
  1656
    if (!frects) {
icculus@7037
  1657
        return SDL_OutOfMemory();
slouken@6528
  1658
    }
slouken@6528
  1659
    for (i = 0; i < count; ++i) {
slouken@6528
  1660
        frects[i].x = rects[i].x * renderer->scale.x;
slouken@6528
  1661
        frects[i].y = rects[i].y * renderer->scale.y;
slouken@6528
  1662
        frects[i].w = rects[i].w * renderer->scale.x;
slouken@6528
  1663
        frects[i].h = rects[i].h * renderer->scale.y;
slouken@6528
  1664
    }
slouken@6528
  1665
slouken@6528
  1666
    status = renderer->RenderFillRects(renderer, frects, count);
slouken@6528
  1667
slouken@6528
  1668
    SDL_stack_free(frects);
slouken@6528
  1669
slouken@6528
  1670
    return status;
slouken@5154
  1671
}
slouken@5154
  1672
slouken@5154
  1673
int
slouken@5154
  1674
SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5154
  1675
               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
slouken@5154
  1676
{
icculus@6545
  1677
    SDL_Rect real_srcrect = { 0, 0, 0, 0 };
icculus@6545
  1678
    SDL_Rect real_dstrect = { 0, 0, 0, 0 };
slouken@6528
  1679
    SDL_FRect frect;
slouken@5154
  1680
slouken@5154
  1681
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1682
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
  1683
slouken@5154
  1684
    if (renderer != texture->renderer) {
icculus@7037
  1685
        return SDL_SetError("Texture was not created with this renderer");
slouken@5154
  1686
    }
slouken@5154
  1687
slouken@5154
  1688
    real_srcrect.x = 0;
slouken@5154
  1689
    real_srcrect.y = 0;
slouken@5154
  1690
    real_srcrect.w = texture->w;
slouken@5154
  1691
    real_srcrect.h = texture->h;
slouken@5154
  1692
    if (srcrect) {
slouken@5154
  1693
        if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
slouken@5154
  1694
            return 0;
slouken@5154
  1695
        }
slouken@5154
  1696
    }
slouken@5154
  1697
slouken@6528
  1698
    SDL_RenderGetViewport(renderer, &real_dstrect);
slouken@5154
  1699
    real_dstrect.x = 0;
slouken@5154
  1700
    real_dstrect.y = 0;
slouken@5369
  1701
    if (dstrect) {
slouken@7563
  1702
        if (!SDL_HasIntersection(dstrect, &real_dstrect)) {
slouken@5369
  1703
            return 0;
slouken@5369
  1704
        }
slouken@7563
  1705
        real_dstrect = *dstrect;
slouken@5154
  1706
    }
slouken@5154
  1707
slouken@5156
  1708
    if (texture->native) {
slouken@5156
  1709
        texture = texture->native;
slouken@5156
  1710
    }
slouken@5156
  1711
slouken@6260
  1712
    /* Don't draw while we're hidden */
slouken@6260
  1713
    if (renderer->hidden) {
slouken@6060
  1714
        return 0;
slouken@6060
  1715
    }
slouken@6528
  1716
slouken@6528
  1717
    frect.x = real_dstrect.x * renderer->scale.x;
slouken@6528
  1718
    frect.y = real_dstrect.y * renderer->scale.y;
slouken@6528
  1719
    frect.w = real_dstrect.w * renderer->scale.x;
slouken@6528
  1720
    frect.h = real_dstrect.h * renderer->scale.y;
slouken@6528
  1721
slouken@6528
  1722
    return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect);
slouken@5154
  1723
}
slouken@5154
  1724
gabomdq@6320
  1725
gabomdq@6320
  1726
int
gabomdq@6320
  1727
SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
gabomdq@6320
  1728
               const SDL_Rect * srcrect, const SDL_Rect * dstrect,
gabomdq@6320
  1729
               const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
gabomdq@6320
  1730
{
icculus@6546
  1731
    SDL_Rect real_srcrect = { 0, 0, 0, 0 };
icculus@6546
  1732
    SDL_Rect real_dstrect = { 0, 0, 0, 0 };
gabomdq@6320
  1733
    SDL_Point real_center;
slouken@6528
  1734
    SDL_FRect frect;
slouken@6528
  1735
    SDL_FPoint fcenter;
gabomdq@6320
  1736
slouken@9762
  1737
    if (flip == SDL_FLIP_NONE && angle == 0) { /* fast path when we don't need rotation or flipping */
slouken@9762
  1738
        return SDL_RenderCopy(renderer, texture, srcrect, dstrect);
slouken@9762
  1739
    }
slouken@9762
  1740
gabomdq@6320
  1741
    CHECK_RENDERER_MAGIC(renderer, -1);
gabomdq@6320
  1742
    CHECK_TEXTURE_MAGIC(texture, -1);
gabomdq@6320
  1743
gabomdq@6320
  1744
    if (renderer != texture->renderer) {
icculus@7037
  1745
        return SDL_SetError("Texture was not created with this renderer");
gabomdq@6320
  1746
    }
gabomdq@6320
  1747
    if (!renderer->RenderCopyEx) {
icculus@7037
  1748
        return SDL_SetError("Renderer does not support RenderCopyEx");
gabomdq@6320
  1749
    }
slouken@7191
  1750
gabomdq@6320
  1751
    real_srcrect.x = 0;
gabomdq@6320
  1752
    real_srcrect.y = 0;
gabomdq@6320
  1753
    real_srcrect.w = texture->w;
gabomdq@6320
  1754
    real_srcrect.h = texture->h;
gabomdq@6320
  1755
    if (srcrect) {
gabomdq@6320
  1756
        if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
gabomdq@6320
  1757
            return 0;
gabomdq@6320
  1758
        }
gabomdq@6320
  1759
    }
gabomdq@6320
  1760
gabomdq@6320
  1761
    /* We don't intersect the dstrect with the viewport as RenderCopy does because of potential rotation clipping issues... TODO: should we? */
slouken@6528
  1762
    if (dstrect) {
slouken@6528
  1763
        real_dstrect = *dstrect;
slouken@6528
  1764
    } else {
slouken@6528
  1765
        SDL_RenderGetViewport(renderer, &real_dstrect);
gabomdq@6399
  1766
        real_dstrect.x = 0;
gabomdq@6399
  1767
        real_dstrect.y = 0;
gabomdq@6320
  1768
    }
gabomdq@6320
  1769
gabomdq@6320
  1770
    if (texture->native) {
gabomdq@6320
  1771
        texture = texture->native;
gabomdq@6320
  1772
    }
gabomdq@6320
  1773
gabomdq@6320
  1774
    if(center) real_center = *center;
gabomdq@6320
  1775
    else {
gabomdq@6320
  1776
        real_center.x = real_dstrect.w/2;
gabomdq@6320
  1777
        real_center.y = real_dstrect.h/2;
gabomdq@6320
  1778
    }
gabomdq@6320
  1779
slouken@6528
  1780
    frect.x = real_dstrect.x * renderer->scale.x;
slouken@6528
  1781
    frect.y = real_dstrect.y * renderer->scale.y;
slouken@6528
  1782
    frect.w = real_dstrect.w * renderer->scale.x;
slouken@6528
  1783
    frect.h = real_dstrect.h * renderer->scale.y;
slouken@6528
  1784
slouken@6528
  1785
    fcenter.x = real_center.x * renderer->scale.x;
slouken@6528
  1786
    fcenter.y = real_center.y * renderer->scale.y;
slouken@6528
  1787
slouken@6528
  1788
    return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &frect, angle, &fcenter, flip);
gabomdq@6320
  1789
}
gabomdq@6320
  1790
slouken@5154
  1791
int
slouken@5154
  1792
SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@5154
  1793
                     Uint32 format, void * pixels, int pitch)
slouken@5154
  1794
{
slouken@5154
  1795
    SDL_Rect real_rect;
slouken@5154
  1796
slouken@5154
  1797
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  1798
slouken@5154
  1799
    if (!renderer->RenderReadPixels) {
icculus@7037
  1800
        return SDL_Unsupported();
slouken@5154
  1801
    }
slouken@5154
  1802
slouken@5154
  1803
    if (!format) {
icculus@6389
  1804
        format = SDL_GetWindowPixelFormat(renderer->window);
slouken@5154
  1805
    }
slouken@5154
  1806
slouken@5464
  1807
    real_rect.x = renderer->viewport.x;
slouken@5464
  1808
    real_rect.y = renderer->viewport.y;
slouken@5297
  1809
    real_rect.w = renderer->viewport.w;
slouken@5297
  1810
    real_rect.h = renderer->viewport.h;
slouken@5154
  1811
    if (rect) {
slouken@5154
  1812
        if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
slouken@5154
  1813
            return 0;
slouken@5154
  1814
        }
slouken@5154
  1815
        if (real_rect.y > rect->y) {
slouken@5154
  1816
            pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y);
slouken@5154
  1817
        }
slouken@5154
  1818
        if (real_rect.x > rect->x) {
slouken@5464
  1819
            int bpp = SDL_BYTESPERPIXEL(format);
slouken@5154
  1820
            pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x);
slouken@5154
  1821
        }
slouken@5154
  1822
    }
slouken@5154
  1823
slouken@5154
  1824
    return renderer->RenderReadPixels(renderer, &real_rect,
slouken@5154
  1825
                                      format, pixels, pitch);
slouken@5154
  1826
}
slouken@5154
  1827
slouken@5154
  1828
void
slouken@5154
  1829
SDL_RenderPresent(SDL_Renderer * renderer)
slouken@5154
  1830
{
slouken@5154
  1831
    CHECK_RENDERER_MAGIC(renderer, );
slouken@5154
  1832
slouken@6260
  1833
    /* Don't draw while we're hidden */
slouken@6260
  1834
    if (renderer->hidden) {
slouken@6060
  1835
        return;
slouken@6060
  1836
    }
slouken@5154
  1837
    renderer->RenderPresent(renderer);
slouken@5154
  1838
}
slouken@5154
  1839
slouken@5154
  1840
void
slouken@5154
  1841
SDL_DestroyTexture(SDL_Texture * texture)
slouken@5154
  1842
{
slouken@5154
  1843
    SDL_Renderer *renderer;
slouken@5154
  1844
slouken@5154
  1845
    CHECK_TEXTURE_MAGIC(texture, );
slouken@7419
  1846
slouken@7419
  1847
    renderer = texture->renderer;
slouken@7419
  1848
    if (texture == renderer->target) {
slouken@7419
  1849
        SDL_SetRenderTarget(renderer, NULL);
slouken@7419
  1850
    }
slouken@7419
  1851
slouken@5154
  1852
    texture->magic = NULL;
slouken@5154
  1853
slouken@5154
  1854
    if (texture->next) {
slouken@5154
  1855
        texture->next->prev = texture->prev;
slouken@5154
  1856
    }
slouken@5154
  1857
    if (texture->prev) {
slouken@5154
  1858
        texture->prev->next = texture->next;
slouken@5154
  1859
    } else {
slouken@5154
  1860
        renderer->textures = texture->next;
slouken@5154
  1861
    }
slouken@5154
  1862
slouken@5156
  1863
    if (texture->native) {
slouken@5156
  1864
        SDL_DestroyTexture(texture->native);
slouken@5156
  1865
    }
slouken@5156
  1866
    if (texture->yuv) {
slouken@5156
  1867
        SDL_SW_DestroyYUVTexture(texture->yuv);
slouken@5156
  1868
    }
slouken@7719
  1869
    SDL_free(texture->pixels);
slouken@5156
  1870
slouken@5154
  1871
    renderer->DestroyTexture(renderer, texture);
slouken@5154
  1872
    SDL_free(texture);
slouken@5154
  1873
}
slouken@5154
  1874
slouken@5154
  1875
void
slouken@5154
  1876
SDL_DestroyRenderer(SDL_Renderer * renderer)
slouken@5154
  1877
{
slouken@5154
  1878
    CHECK_RENDERER_MAGIC(renderer, );
slouken@5154
  1879
slouken@5154
  1880
    SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
slouken@5154
  1881
slouken@5154
  1882
    /* Free existing textures for this renderer */
slouken@5154
  1883
    while (renderer->textures) {
slouken@5154
  1884
        SDL_DestroyTexture(renderer->textures);
slouken@5154
  1885
    }
slouken@5154
  1886
slouken@6417
  1887
    if (renderer->window) {
slouken@6417
  1888
        SDL_SetWindowData(renderer->window, SDL_WINDOWRENDERDATA, NULL);
slouken@6417
  1889
    }
slouken@5528
  1890
slouken@5154
  1891
    /* It's no longer magical... */
slouken@5154
  1892
    renderer->magic = NULL;
slouken@5154
  1893
slouken@5154
  1894
    /* Free the renderer instance */
slouken@5154
  1895
    renderer->DestroyRenderer(renderer);
slouken@5154
  1896
}
slouken@5154
  1897
gabomdq@6414
  1898
int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh)
gabomdq@6414
  1899
{
gabomdq@6414
  1900
    SDL_Renderer *renderer;
gabomdq@6414
  1901
gabomdq@6415
  1902
    CHECK_TEXTURE_MAGIC(texture, -1);
gabomdq@6414
  1903
    renderer = texture->renderer;
slouken@7318
  1904
    if (texture->native) {
slouken@7318
  1905
        return SDL_GL_BindTexture(texture->native, texw, texh);
slouken@7318
  1906
    } else if (renderer && renderer->GL_BindTexture) {
gabomdq@6414
  1907
        return renderer->GL_BindTexture(renderer, texture, texw, texh);
slouken@7318
  1908
    } else {
slouken@7318
  1909
        return SDL_Unsupported();
gabomdq@6414
  1910
    }
gabomdq@6414
  1911
}
gabomdq@6414
  1912
gabomdq@6414
  1913
int SDL_GL_UnbindTexture(SDL_Texture *texture)
gabomdq@6414
  1914
{
gabomdq@6414
  1915
    SDL_Renderer *renderer;
gabomdq@6414
  1916
gabomdq@6415
  1917
    CHECK_TEXTURE_MAGIC(texture, -1);
gabomdq@6414
  1918
    renderer = texture->renderer;
gabomdq@8249
  1919
    if (texture->native) {
gabomdq@8249
  1920
        return SDL_GL_UnbindTexture(texture->native);
gabomdq@8249
  1921
    } else if (renderer && renderer->GL_UnbindTexture) {
gabomdq@6414
  1922
        return renderer->GL_UnbindTexture(renderer, texture);
gabomdq@6414
  1923
    }
gabomdq@6414
  1924
icculus@7037
  1925
    return SDL_Unsupported();
gabomdq@6414
  1926
}
gabomdq@6414
  1927
slouken@5154
  1928
/* vi: set ts=4 sw=4 expandtab: */