src/render/SDL_render.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 29 May 2013 03:22:19 -0700
changeset 7240 39eb4958950a
parent 7239 04dda95ba22c
child 7318 46a5a6b8678e
permissions -rw-r--r--
When the window is resized, the viewport is automatically reset.
This resolves lots of confusion around resizable windows. Most people don't expect a viewport to be implicitly set when the renderer is created and then not to be reset to the window size if the window is resized.

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