src/render/SDL_render.c
author Ozkan Sezer <sezeroz@gmail.com>
Thu, 01 Nov 2018 20:04:24 +0300
changeset 12383 f6430feceeda
parent 12382 03d0bddca61b
child 12447 0844007ea1c2
permissions -rw-r--r--
fix build using Watcom :

./src/render/SDL_render.c(2168): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2168): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2175): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2175): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2322): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2322): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2322): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2322): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2329): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2329): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2329): Error! E1054: Expression must be constant
./src/render/SDL_render.c(2329): Error! E1054: Expression must be constant

./src/render/software/SDL_render_sw.c(602): Error! E1054: Expression must be constant
./src/render/software/SDL_render_sw.c(602): Error! E1054: Expression must be constant
./src/render/software/SDL_render_sw.c(602): Error! E1054: Expression must be constant
./src/render/software/SDL_render_sw.c(602): Error! E1054: Expression must be constant
slouken@5154
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 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@11294
    36
    SDL_assert(renderer && renderer->magic == &renderer_magic); \
slouken@5154
    37
    if (!renderer || renderer->magic != &renderer_magic) { \
slouken@5154
    38
        SDL_SetError("Invalid renderer"); \
slouken@5154
    39
        return retval; \
slouken@5154
    40
    }
slouken@5154
    41
slouken@5154
    42
#define CHECK_TEXTURE_MAGIC(texture, retval) \
slouken@11294
    43
    SDL_assert(texture && texture->magic == &texture_magic); \
slouken@5154
    44
    if (!texture || texture->magic != &texture_magic) { \
slouken@5154
    45
        SDL_SetError("Invalid texture"); \
slouken@5154
    46
        return retval; \
slouken@5154
    47
    }
slouken@5154
    48
slouken@11282
    49
/* Predefined blend modes */
slouken@11282
    50
#define SDL_COMPOSE_BLENDMODE(srcColorFactor, dstColorFactor, colorOperation, \
slouken@11282
    51
                              srcAlphaFactor, dstAlphaFactor, alphaOperation) \
slouken@11282
    52
    (SDL_BlendMode)(((Uint32)colorOperation << 0) | \
slouken@11282
    53
                    ((Uint32)srcColorFactor << 4) | \
slouken@11282
    54
                    ((Uint32)dstColorFactor << 8) | \
slouken@11282
    55
                    ((Uint32)alphaOperation << 16) | \
slouken@11282
    56
                    ((Uint32)srcAlphaFactor << 20) | \
slouken@11282
    57
                    ((Uint32)dstAlphaFactor << 24))
slouken@11282
    58
slouken@11282
    59
#define SDL_BLENDMODE_NONE_FULL \
slouken@11282
    60
    SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO, SDL_BLENDOPERATION_ADD, \
slouken@11282
    61
                          SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO, SDL_BLENDOPERATION_ADD)
slouken@11282
    62
slouken@11282
    63
#define SDL_BLENDMODE_BLEND_FULL \
slouken@11282
    64
    SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, \
slouken@11282
    65
                          SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD)
slouken@11282
    66
slouken@11282
    67
#define SDL_BLENDMODE_ADD_FULL \
slouken@11282
    68
    SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD, \
slouken@11282
    69
                          SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD)
slouken@11282
    70
slouken@11282
    71
#define SDL_BLENDMODE_MOD_FULL \
slouken@11282
    72
    SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_COLOR, SDL_BLENDOPERATION_ADD, \
slouken@11282
    73
                          SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD)
slouken@5154
    74
slouken@7109
    75
#if !SDL_RENDER_DISABLED
slouken@5154
    76
static const SDL_RenderDriver *render_drivers[] = {
slouken@8599
    77
#if SDL_VIDEO_RENDER_D3D
slouken@8599
    78
    &D3D_RenderDriver,
slouken@8599
    79
#endif
slouken@8591
    80
#if SDL_VIDEO_RENDER_D3D11
slouken@8591
    81
    &D3D11_RenderDriver,
slouken@8591
    82
#endif
slouken@5154
    83
#if SDL_VIDEO_RENDER_OGL
slouken@5154
    84
    &GL_RenderDriver,
slouken@5154
    85
#endif
slouken@5209
    86
#if SDL_VIDEO_RENDER_OGL_ES2
slouken@5209
    87
    &GLES2_RenderDriver,
slouken@5209
    88
#endif
slouken@5154
    89
#if SDL_VIDEO_RENDER_OGL_ES
slouken@5201
    90
    &GLES_RenderDriver,
slouken@5201
    91
#endif
slouken@5199
    92
#if SDL_VIDEO_RENDER_DIRECTFB
slouken@5199
    93
    &DirectFB_RenderDriver,
slouken@5199
    94
#endif
icculus@11729
    95
#if SDL_VIDEO_RENDER_METAL
icculus@11729
    96
    &METAL_RenderDriver,
icculus@11729
    97
#endif
kimonline@7009
    98
#if SDL_VIDEO_RENDER_PSP
kimonline@7009
    99
    &PSP_RenderDriver,
kimonline@7009
   100
#endif
slouken@5154
   101
    &SW_RenderDriver
slouken@7109
   102
};
slouken@5226
   103
#endif /* !SDL_RENDER_DISABLED */
slouken@7109
   104
slouken@5154
   105
static char renderer_magic;
slouken@5154
   106
static char texture_magic;
slouken@5154
   107
icculus@12216
   108
static SDL_INLINE void
icculus@12216
   109
DebugLogRenderCommands(const SDL_RenderCommand *cmd)
icculus@12216
   110
{
icculus@12216
   111
#if 0
icculus@12216
   112
    unsigned int i = 1;
icculus@12216
   113
    SDL_Log("Render commands to flush:");
icculus@12216
   114
    while (cmd) {
icculus@12216
   115
        switch (cmd->command) {
icculus@12216
   116
            case SDL_RENDERCMD_NO_OP:
icculus@12216
   117
                SDL_Log(" %u. no-op", i++);
icculus@12216
   118
                break;
icculus@12216
   119
icculus@12216
   120
            case SDL_RENDERCMD_SETVIEWPORT:
icculus@12216
   121
                SDL_Log(" %u. set viewport (first=%u, rect={(%d, %d), %dx%d})", i++,
icculus@12216
   122
                        (unsigned int) cmd->data.viewport.first,
icculus@12216
   123
                        cmd->data.viewport.rect.x, cmd->data.viewport.rect.y,
icculus@12216
   124
                        cmd->data.viewport.rect.w, cmd->data.viewport.rect.h);
icculus@12216
   125
                break;
icculus@12216
   126
icculus@12216
   127
            case SDL_RENDERCMD_SETCLIPRECT:
icculus@12216
   128
                SDL_Log(" %u. set cliprect (enabled=%s, rect={(%d, %d), %dx%d})", i++,
icculus@12216
   129
                        cmd->data.cliprect.enabled ? "true" : "false",
icculus@12216
   130
                        cmd->data.cliprect.rect.x, cmd->data.cliprect.rect.y,
icculus@12216
   131
                        cmd->data.cliprect.rect.w, cmd->data.cliprect.rect.h);
icculus@12216
   132
                break;
icculus@12216
   133
icculus@12216
   134
            case SDL_RENDERCMD_SETDRAWCOLOR:
icculus@12216
   135
                SDL_Log(" %u. set draw color (first=%u, r=%d, g=%d, b=%d, a=%d)", i++,
icculus@12216
   136
                        (unsigned int) cmd->data.color.first,
icculus@12216
   137
                        (int) cmd->data.color.r, (int) cmd->data.color.g,
icculus@12216
   138
                        (int) cmd->data.color.b, (int) cmd->data.color.a);
icculus@12216
   139
                break;
icculus@12216
   140
icculus@12216
   141
            case SDL_RENDERCMD_CLEAR:
icculus@12216
   142
                SDL_Log(" %u. clear (first=%u, r=%d, g=%d, b=%d, a=%d)", i++,
icculus@12216
   143
                        (unsigned int) cmd->data.color.first,
icculus@12216
   144
                        (int) cmd->data.color.r, (int) cmd->data.color.g,
icculus@12216
   145
                        (int) cmd->data.color.b, (int) cmd->data.color.a);
icculus@12216
   146
                break;
icculus@12216
   147
icculus@12216
   148
            case SDL_RENDERCMD_DRAW_POINTS:
icculus@12216
   149
                SDL_Log(" %u. draw points (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
icculus@12216
   150
                        (unsigned int) cmd->data.draw.first,
icculus@12216
   151
                        (unsigned int) cmd->data.draw.count,
icculus@12216
   152
                        (int) cmd->data.draw.r, (int) cmd->data.draw.g,
icculus@12216
   153
                        (int) cmd->data.draw.b, (int) cmd->data.draw.a,
icculus@12216
   154
                        (int) cmd->data.draw.blend);
icculus@12216
   155
                break;
icculus@12216
   156
icculus@12216
   157
            case SDL_RENDERCMD_DRAW_LINES:
icculus@12216
   158
                SDL_Log(" %u. draw lines (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
icculus@12216
   159
                        (unsigned int) cmd->data.draw.first,
icculus@12216
   160
                        (unsigned int) cmd->data.draw.count,
icculus@12216
   161
                        (int) cmd->data.draw.r, (int) cmd->data.draw.g,
icculus@12216
   162
                        (int) cmd->data.draw.b, (int) cmd->data.draw.a,
icculus@12216
   163
                        (int) cmd->data.draw.blend);
icculus@12216
   164
                break;
icculus@12216
   165
icculus@12216
   166
            case SDL_RENDERCMD_FILL_RECTS:
icculus@12216
   167
                SDL_Log(" %u. fill rects (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
icculus@12216
   168
                        (unsigned int) cmd->data.draw.first,
icculus@12216
   169
                        (unsigned int) cmd->data.draw.count,
icculus@12216
   170
                        (int) cmd->data.draw.r, (int) cmd->data.draw.g,
icculus@12216
   171
                        (int) cmd->data.draw.b, (int) cmd->data.draw.a,
icculus@12216
   172
                        (int) cmd->data.draw.blend);
icculus@12216
   173
                break;
icculus@12216
   174
icculus@12216
   175
            case SDL_RENDERCMD_COPY:
icculus@12216
   176
                SDL_Log(" %u. copy (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, tex=%p)", i++,
icculus@12216
   177
                        (unsigned int) cmd->data.draw.first,
icculus@12216
   178
                        (unsigned int) cmd->data.draw.count,
icculus@12216
   179
                        (int) cmd->data.draw.r, (int) cmd->data.draw.g,
icculus@12216
   180
                        (int) cmd->data.draw.b, (int) cmd->data.draw.a,
icculus@12216
   181
                        (int) cmd->data.draw.blend, cmd->data.draw.texture);
icculus@12216
   182
                break;
icculus@12216
   183
icculus@12216
   184
icculus@12216
   185
            case SDL_RENDERCMD_COPY_EX:
icculus@12216
   186
                SDL_Log(" %u. copyex (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, tex=%p)", i++,
icculus@12216
   187
                        (unsigned int) cmd->data.draw.first,
icculus@12216
   188
                        (unsigned int) cmd->data.draw.count,
icculus@12216
   189
                        (int) cmd->data.draw.r, (int) cmd->data.draw.g,
icculus@12216
   190
                        (int) cmd->data.draw.b, (int) cmd->data.draw.a,
icculus@12216
   191
                        (int) cmd->data.draw.blend, cmd->data.draw.texture);
icculus@12216
   192
                break;
icculus@12216
   193
        }
icculus@12216
   194
        cmd = cmd->next;
icculus@12216
   195
    }
icculus@12216
   196
#endif
icculus@12216
   197
}
icculus@12211
   198
icculus@12211
   199
static int
icculus@12211
   200
FlushRenderCommands(SDL_Renderer *renderer)
icculus@12211
   201
{
icculus@12214
   202
    SDL_AllocVertGap *prevgap = &renderer->vertex_data_gaps;
icculus@12214
   203
    SDL_AllocVertGap *gap = prevgap;
icculus@12211
   204
    int retval;
icculus@12214
   205
icculus@12211
   206
    SDL_assert((renderer->render_commands == NULL) == (renderer->render_commands_tail == NULL));
icculus@12211
   207
icculus@12211
   208
    if (renderer->render_commands == NULL) {  /* nothing to do! */
icculus@12211
   209
        SDL_assert(renderer->vertex_data_used == 0);
icculus@12211
   210
        return 0;
icculus@12211
   211
    }
icculus@12211
   212
icculus@12216
   213
    DebugLogRenderCommands(renderer->render_commands);
icculus@12216
   214
icculus@12211
   215
    retval = renderer->RunCommandQueue(renderer, renderer->render_commands, renderer->vertex_data, renderer->vertex_data_used);
icculus@12211
   216
icculus@12214
   217
    while (gap) {
icculus@12214
   218
        prevgap = gap;
icculus@12214
   219
        gap = gap->next;
icculus@12214
   220
    }
icculus@12214
   221
    prevgap->next = renderer->vertex_data_gaps_pool;
icculus@12214
   222
    renderer->vertex_data_gaps_pool = renderer->vertex_data_gaps.next;
icculus@12214
   223
    renderer->vertex_data_gaps.next = NULL;
icculus@12214
   224
icculus@12211
   225
    /* Move the whole render command queue to the unused pool so we can reuse them next time. */
icculus@12211
   226
    if (renderer->render_commands_tail != NULL) {
icculus@12211
   227
        renderer->render_commands_tail->next = renderer->render_commands_pool;
icculus@12211
   228
        renderer->render_commands_pool = renderer->render_commands;
icculus@12211
   229
        renderer->render_commands_tail = NULL;
icculus@12211
   230
        renderer->render_commands = NULL;
icculus@12211
   231
    }
icculus@12211
   232
    renderer->vertex_data_used = 0;
icculus@12211
   233
    renderer->render_command_generation++;
icculus@12214
   234
    renderer->color_queued = SDL_FALSE;
icculus@12214
   235
    renderer->viewport_queued = SDL_FALSE;
icculus@12214
   236
    renderer->cliprect_queued = SDL_FALSE;
icculus@12211
   237
    return retval;
icculus@12211
   238
}
icculus@12211
   239
icculus@12211
   240
static int
icculus@12211
   241
FlushRenderCommandsIfTextureNeeded(SDL_Texture *texture)
icculus@12211
   242
{
icculus@12211
   243
    SDL_Renderer *renderer = texture->renderer;
icculus@12211
   244
    if (texture->last_command_generation == renderer->render_command_generation) {
icculus@12211
   245
        /* the current command queue depends on this texture, flush the queue now before it changes */
icculus@12211
   246
        return FlushRenderCommands(renderer);
icculus@12211
   247
    }
icculus@12211
   248
    return 0;
icculus@12211
   249
}
icculus@12211
   250
icculus@12211
   251
static SDL_INLINE int
icculus@12211
   252
FlushRenderCommandsIfNotBatching(SDL_Renderer *renderer)
icculus@12211
   253
{
icculus@12211
   254
    return renderer->batching ? 0 : FlushRenderCommands(renderer);
icculus@12211
   255
}
icculus@12211
   256
icculus@12290
   257
int
icculus@12290
   258
SDL_RenderFlush(SDL_Renderer * renderer)
icculus@12290
   259
{
icculus@12290
   260
    return FlushRenderCommands(renderer);
icculus@12290
   261
}
icculus@12290
   262
icculus@12214
   263
static SDL_AllocVertGap *
icculus@12214
   264
AllocateVertexGap(SDL_Renderer *renderer)
icculus@12214
   265
{
icculus@12214
   266
    SDL_AllocVertGap *retval = renderer->vertex_data_gaps_pool;
icculus@12214
   267
    if (retval) {
icculus@12214
   268
        renderer->vertex_data_gaps_pool = retval->next;
icculus@12214
   269
        retval->next = NULL;
icculus@12214
   270
    } else {
icculus@12214
   271
        retval = (SDL_AllocVertGap *) SDL_malloc(sizeof (SDL_AllocVertGap));
icculus@12214
   272
        if (!retval) {
icculus@12214
   273
            SDL_OutOfMemory();
icculus@12214
   274
        }
icculus@12214
   275
    }
icculus@12214
   276
    return retval;
icculus@12214
   277
}
icculus@12214
   278
icculus@12214
   279
icculus@12211
   280
void *
icculus@12214
   281
SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, const size_t alignment, size_t *offset)
icculus@12211
   282
{
icculus@12214
   283
    const size_t needed = renderer->vertex_data_used + numbytes + alignment;
icculus@12214
   284
    size_t aligner, aligned;
icculus@12211
   285
    void *retval;
icculus@12211
   286
icculus@12214
   287
    SDL_AllocVertGap *prevgap = &renderer->vertex_data_gaps;
icculus@12214
   288
    SDL_AllocVertGap *gap = prevgap->next;
icculus@12214
   289
    while (gap) {
icculus@12214
   290
        const size_t gapoffset = gap->offset;
icculus@12214
   291
        aligner = (alignment && ((gap->offset % alignment) != 0)) ? (alignment - (gap->offset % alignment)) : 0;
icculus@12214
   292
        aligned = gapoffset + aligner;
icculus@12214
   293
icculus@12214
   294
        /* Can we use this gap? */
icculus@12214
   295
        if ((aligner < gap->len) && ((gap->len - aligner) >= numbytes)) {
icculus@12214
   296
            /* we either finished this gap off, trimmed the left, trimmed the right, or split it into two gaps. */
icculus@12214
   297
            if (gap->len == numbytes) {  /* finished it off, remove it */
icculus@12214
   298
                SDL_assert(aligned == gapoffset);
icculus@12214
   299
                prevgap->next = gap->next;
icculus@12214
   300
                gap->next = renderer->vertex_data_gaps_pool;
icculus@12214
   301
                renderer->vertex_data_gaps_pool = gap;
icculus@12214
   302
            } else if (aligned == gapoffset) {  /* trimmed the left */
icculus@12214
   303
                gap->offset += numbytes;
icculus@12214
   304
                gap->len -= numbytes;
icculus@12214
   305
            } else if (((aligned - gapoffset) + numbytes) == gap->len) {  /* trimmed the right */
icculus@12214
   306
                gap->len -= numbytes;
icculus@12214
   307
            } else {  /* split into two gaps */
icculus@12214
   308
                SDL_AllocVertGap *newgap = AllocateVertexGap(renderer);
icculus@12214
   309
                if (!newgap) {
icculus@12214
   310
                    return NULL;
icculus@12214
   311
                }
icculus@12214
   312
                newgap->offset = aligned + numbytes;
icculus@12214
   313
                newgap->len = gap->len - (aligner + numbytes);
icculus@12214
   314
                newgap->next = gap->next;
icculus@12214
   315
                // gap->offset doesn't change.
icculus@12214
   316
                gap->len = aligner;
icculus@12214
   317
                gap->next = newgap;
icculus@12214
   318
            }
icculus@12214
   319
icculus@12214
   320
            if (offset) {
icculus@12214
   321
                *offset = aligned;
icculus@12214
   322
            }
icculus@12214
   323
            return ((Uint8 *) renderer->vertex_data) + aligned;
icculus@12214
   324
        }
icculus@12214
   325
icculus@12214
   326
        /* Try the next gap */
icculus@12214
   327
        prevgap = gap;
icculus@12214
   328
        gap = gap->next;
icculus@12214
   329
    }
icculus@12214
   330
icculus@12214
   331
    /* no gaps with enough space; get a new piece of the vertex buffer */
icculus@12211
   332
    while (needed > renderer->vertex_data_allocation) {
icculus@12214
   333
        const size_t current_allocation = renderer->vertex_data ? renderer->vertex_data_allocation : 1024;
icculus@12211
   334
        const size_t newsize = current_allocation * 2;
icculus@12211
   335
        void *ptr = SDL_realloc(renderer->vertex_data, newsize);
icculus@12211
   336
        if (ptr == NULL) {
icculus@12211
   337
            SDL_OutOfMemory();
icculus@12211
   338
            return NULL;
icculus@12211
   339
        }
icculus@12211
   340
        renderer->vertex_data = ptr;
icculus@12211
   341
        renderer->vertex_data_allocation = newsize;
icculus@12211
   342
    }
icculus@12211
   343
icculus@12214
   344
    aligner = (alignment && ((renderer->vertex_data_used % alignment) != 0)) ? (alignment - (renderer->vertex_data_used % alignment)) : 0;
icculus@12214
   345
    aligned = renderer->vertex_data_used + aligner;
icculus@12214
   346
icculus@12214
   347
    retval = ((Uint8 *) renderer->vertex_data) + aligned;
icculus@12211
   348
    if (offset) {
icculus@12214
   349
        *offset = aligned;
icculus@12211
   350
    }
icculus@12211
   351
icculus@12214
   352
    if (aligner) {  /* made a new gap... */
icculus@12214
   353
        SDL_AllocVertGap *newgap = AllocateVertexGap(renderer);
icculus@12214
   354
        if (newgap) {  /* just let it slide as lost space if malloc fails. */
icculus@12214
   355
            newgap->offset = renderer->vertex_data_used;
icculus@12214
   356
            newgap->len = aligner;
icculus@12214
   357
            newgap->next = NULL;
icculus@12214
   358
            prevgap->next = newgap;
icculus@12214
   359
        }
icculus@12214
   360
    }
icculus@12214
   361
icculus@12214
   362
    renderer->vertex_data_used += aligner + numbytes;
icculus@12214
   363
icculus@12211
   364
    return retval;
icculus@12211
   365
}
icculus@12211
   366
icculus@12211
   367
static SDL_RenderCommand *
icculus@12211
   368
AllocateRenderCommand(SDL_Renderer *renderer)
icculus@12211
   369
{
icculus@12211
   370
    SDL_RenderCommand *retval = NULL;
icculus@12211
   371
icculus@12211
   372
    /* !!! FIXME: are there threading limitations in SDL's render API? If not, we need to mutex this. */
icculus@12211
   373
    retval = renderer->render_commands_pool;
icculus@12211
   374
    if (retval != NULL) {
icculus@12211
   375
        renderer->render_commands_pool = retval->next;
icculus@12211
   376
        retval->next = NULL;
icculus@12211
   377
    } else {
icculus@12211
   378
        retval = SDL_calloc(1, sizeof (*retval));
icculus@12211
   379
        if (!retval) {
icculus@12211
   380
            SDL_OutOfMemory();
icculus@12211
   381
            return NULL;
icculus@12211
   382
        }
icculus@12211
   383
    }
icculus@12211
   384
icculus@12211
   385
    SDL_assert((renderer->render_commands == NULL) == (renderer->render_commands_tail == NULL));
icculus@12211
   386
    if (renderer->render_commands_tail != NULL) {
icculus@12211
   387
        renderer->render_commands_tail->next = retval;
icculus@12211
   388
    } else {
icculus@12211
   389
        renderer->render_commands = retval;
icculus@12211
   390
    }
icculus@12211
   391
    renderer->render_commands_tail = retval;
icculus@12211
   392
icculus@12211
   393
    return retval;
icculus@12211
   394
}
icculus@12211
   395
icculus@12211
   396
static int
icculus@12214
   397
QueueCmdSetViewport(SDL_Renderer *renderer)
icculus@12211
   398
{
icculus@12214
   399
    int retval = 0;
icculus@12214
   400
    if (!renderer->viewport_queued || (SDL_memcmp(&renderer->viewport, &renderer->last_queued_viewport, sizeof (SDL_Rect)) != 0)) {
icculus@12214
   401
        SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
icculus@12214
   402
        retval = -1;
icculus@12214
   403
        if (cmd != NULL) {
icculus@12214
   404
            cmd->command = SDL_RENDERCMD_SETVIEWPORT;
icculus@12214
   405
            cmd->data.viewport.first = 0;  /* render backend will fill this in. */
icculus@12214
   406
            SDL_memcpy(&cmd->data.viewport.rect, &renderer->viewport, sizeof (renderer->viewport));
icculus@12214
   407
            retval = renderer->QueueSetViewport(renderer, cmd);
icculus@12214
   408
            if (retval < 0) {
icculus@12214
   409
                cmd->command = SDL_RENDERCMD_NO_OP;
icculus@12214
   410
            } else {
icculus@12214
   411
                SDL_memcpy(&renderer->last_queued_viewport, &renderer->viewport, sizeof (SDL_Rect));
icculus@12214
   412
                renderer->viewport_queued = SDL_TRUE;
icculus@12214
   413
            }
icculus@12214
   414
        }
icculus@12211
   415
    }
icculus@12236
   416
    return retval;
icculus@12211
   417
}
icculus@12211
   418
icculus@12211
   419
static int
icculus@12214
   420
QueueCmdSetClipRect(SDL_Renderer *renderer)
icculus@12211
   421
{
icculus@12214
   422
    int retval = 0;
icculus@12214
   423
    if ((!renderer->cliprect_queued) ||
icculus@12214
   424
         (renderer->clipping_enabled != renderer->last_queued_cliprect_enabled) ||
icculus@12214
   425
         (SDL_memcmp(&renderer->clip_rect, &renderer->last_queued_cliprect, sizeof (SDL_Rect)) != 0)) {
icculus@12214
   426
        SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
icculus@12214
   427
        if (cmd == NULL) {
icculus@12214
   428
            retval = -1;
icculus@12214
   429
        } else {
icculus@12214
   430
            cmd->command = SDL_RENDERCMD_SETCLIPRECT;
icculus@12214
   431
            cmd->data.cliprect.enabled = renderer->clipping_enabled;
icculus@12214
   432
            SDL_memcpy(&cmd->data.cliprect.rect, &renderer->clip_rect, sizeof (cmd->data.cliprect.rect));
icculus@12214
   433
            SDL_memcpy(&renderer->last_queued_cliprect, &renderer->clip_rect, sizeof (SDL_Rect));
icculus@12214
   434
            renderer->last_queued_cliprect_enabled = renderer->clipping_enabled;
icculus@12214
   435
            renderer->cliprect_queued = SDL_TRUE;
icculus@12214
   436
        }
icculus@12211
   437
    }
icculus@12236
   438
    return retval;
icculus@12214
   439
}
icculus@12214
   440
icculus@12214
   441
static int
icculus@12214
   442
QueueCmdSetDrawColor(SDL_Renderer *renderer, const Uint8 r, const Uint8 g, const Uint8 b, const Uint8 a)
icculus@12214
   443
{
icculus@12214
   444
    const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
icculus@12214
   445
    int retval = 0;
icculus@12214
   446
    
icculus@12214
   447
    if (!renderer->color_queued || (color != renderer->last_queued_color)) {
icculus@12214
   448
        SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
icculus@12214
   449
        retval = -1;
icculus@12214
   450
icculus@12214
   451
        if (cmd != NULL) {
icculus@12214
   452
            cmd->command = SDL_RENDERCMD_SETDRAWCOLOR;
icculus@12214
   453
            cmd->data.color.first = 0;  /* render backend will fill this in. */
icculus@12214
   454
            cmd->data.color.r = r;
icculus@12214
   455
            cmd->data.color.g = g;
icculus@12214
   456
            cmd->data.color.b = b;
icculus@12214
   457
            cmd->data.color.a = a;
icculus@12214
   458
            retval = renderer->QueueSetDrawColor(renderer, cmd);
icculus@12214
   459
            if (retval < 0) {
icculus@12214
   460
                cmd->command = SDL_RENDERCMD_NO_OP;
icculus@12214
   461
            } else {
icculus@12214
   462
                renderer->last_queued_color = color;
icculus@12214
   463
                renderer->color_queued = SDL_TRUE;
icculus@12214
   464
            }
icculus@12214
   465
        }
icculus@12214
   466
    }
icculus@12236
   467
    return retval;
icculus@12211
   468
}
icculus@12211
   469
icculus@12211
   470
static int
icculus@12211
   471
QueueCmdClear(SDL_Renderer *renderer)
icculus@12211
   472
{
icculus@12211
   473
    SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
icculus@12211
   474
    if (cmd == NULL) {
icculus@12211
   475
        return -1;
icculus@12211
   476
    }
icculus@12211
   477
icculus@12211
   478
    cmd->command = SDL_RENDERCMD_CLEAR;
icculus@12214
   479
    cmd->data.color.first = 0;
icculus@12211
   480
    cmd->data.color.r = renderer->r;
icculus@12211
   481
    cmd->data.color.g = renderer->g;
icculus@12211
   482
    cmd->data.color.b = renderer->b;
icculus@12211
   483
    cmd->data.color.a = renderer->a;
icculus@12236
   484
    return 0;
icculus@12211
   485
}
icculus@12211
   486
icculus@12214
   487
static int
icculus@12214
   488
PrepQueueCmdDraw(SDL_Renderer *renderer, const Uint8 r, const Uint8 g, const Uint8 b, const Uint8 a)
icculus@12214
   489
{
icculus@12214
   490
    int retval = 0;
icculus@12214
   491
    if (retval == 0) {
icculus@12214
   492
        retval = QueueCmdSetDrawColor(renderer, r, g, b, a);
icculus@12214
   493
    }
icculus@12214
   494
    if (retval == 0) {
icculus@12214
   495
        retval = QueueCmdSetViewport(renderer);
icculus@12214
   496
    }
icculus@12214
   497
    if (retval == 0) {
icculus@12214
   498
        retval = QueueCmdSetClipRect(renderer);
icculus@12214
   499
    }
icculus@12214
   500
    return retval;
icculus@12214
   501
}
icculus@12214
   502
icculus@12211
   503
static SDL_RenderCommand *
icculus@12211
   504
PrepQueueCmdDrawSolid(SDL_Renderer *renderer, const SDL_RenderCommandType cmdtype)
icculus@12211
   505
{
icculus@12262
   506
    /* !!! FIXME: drop this draw if viewport w or h is zero. */
icculus@12214
   507
    SDL_RenderCommand *cmd = NULL;
icculus@12214
   508
    if (PrepQueueCmdDraw(renderer, renderer->r, renderer->g, renderer->b, renderer->a) == 0) {
icculus@12214
   509
        cmd = AllocateRenderCommand(renderer);
icculus@12214
   510
        if (cmd != NULL) {
icculus@12214
   511
            cmd->command = cmdtype;
icculus@12214
   512
            cmd->data.draw.first = 0;  /* render backend will fill this in. */
icculus@12214
   513
            cmd->data.draw.count = 0;  /* render backend will fill this in. */
icculus@12214
   514
            cmd->data.draw.r = renderer->r;
icculus@12214
   515
            cmd->data.draw.g = renderer->g;
icculus@12214
   516
            cmd->data.draw.b = renderer->b;
icculus@12214
   517
            cmd->data.draw.a = renderer->a;
icculus@12214
   518
            cmd->data.draw.blend = renderer->blendMode;
icculus@12214
   519
            cmd->data.draw.texture = NULL;  /* no texture. */
icculus@12214
   520
        }
icculus@12211
   521
    }
icculus@12211
   522
    return cmd;
icculus@12211
   523
}
icculus@12211
   524
icculus@12211
   525
static int
icculus@12211
   526
QueueCmdDrawPoints(SDL_Renderer *renderer, const SDL_FPoint * points, const int count)
icculus@12211
   527
{
icculus@12211
   528
    SDL_RenderCommand *cmd = PrepQueueCmdDrawSolid(renderer, SDL_RENDERCMD_DRAW_POINTS);
icculus@12211
   529
    int retval = -1;
icculus@12211
   530
    if (cmd != NULL) {
icculus@12211
   531
        retval = renderer->QueueDrawPoints(renderer, cmd, points, count);
icculus@12211
   532
        if (retval < 0) {
icculus@12211
   533
            cmd->command = SDL_RENDERCMD_NO_OP;
icculus@12211
   534
        }
icculus@12211
   535
    }
icculus@12236
   536
    return retval;
icculus@12211
   537
}
icculus@12211
   538
icculus@12211
   539
static int
icculus@12211
   540
QueueCmdDrawLines(SDL_Renderer *renderer, const SDL_FPoint * points, const int count)
icculus@12211
   541
{
icculus@12211
   542
    SDL_RenderCommand *cmd = PrepQueueCmdDrawSolid(renderer, SDL_RENDERCMD_DRAW_LINES);
icculus@12211
   543
    int retval = -1;
icculus@12211
   544
    if (cmd != NULL) {
icculus@12211
   545
        retval = renderer->QueueDrawLines(renderer, cmd, points, count);
icculus@12211
   546
        if (retval < 0) {
icculus@12211
   547
            cmd->command = SDL_RENDERCMD_NO_OP;
icculus@12211
   548
        }
icculus@12211
   549
    }
icculus@12236
   550
    return retval;
icculus@12211
   551
}
icculus@12211
   552
icculus@12211
   553
static int
icculus@12211
   554
QueueCmdFillRects(SDL_Renderer *renderer, const SDL_FRect * rects, const int count)
icculus@12211
   555
{
icculus@12211
   556
    SDL_RenderCommand *cmd = PrepQueueCmdDrawSolid(renderer, SDL_RENDERCMD_FILL_RECTS);
icculus@12211
   557
    int retval = -1;
icculus@12211
   558
    if (cmd != NULL) {
icculus@12211
   559
        retval = renderer->QueueFillRects(renderer, cmd, rects, count);
icculus@12211
   560
        if (retval < 0) {
icculus@12211
   561
            cmd->command = SDL_RENDERCMD_NO_OP;
icculus@12211
   562
        }
icculus@12211
   563
    }
icculus@12236
   564
    return retval;
icculus@12211
   565
}
icculus@12211
   566
icculus@12211
   567
static SDL_RenderCommand *
icculus@12211
   568
PrepQueueCmdDrawTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_RenderCommandType cmdtype)
icculus@12211
   569
{
icculus@12262
   570
    /* !!! FIXME: drop this draw if viewport w or h is zero. */
icculus@12214
   571
    SDL_RenderCommand *cmd = NULL;
icculus@12214
   572
    if (PrepQueueCmdDraw(renderer, texture->r, texture->g, texture->b, texture->a) == 0) {
icculus@12214
   573
        cmd = AllocateRenderCommand(renderer);
icculus@12214
   574
        if (cmd != NULL) {
icculus@12214
   575
            cmd->command = cmdtype;
icculus@12214
   576
            cmd->data.draw.first = 0;  /* render backend will fill this in. */
icculus@12214
   577
            cmd->data.draw.count = 0;  /* render backend will fill this in. */
icculus@12214
   578
            cmd->data.draw.r = texture->r;
icculus@12214
   579
            cmd->data.draw.g = texture->g;
icculus@12214
   580
            cmd->data.draw.b = texture->b;
icculus@12214
   581
            cmd->data.draw.a = texture->a;
icculus@12214
   582
            cmd->data.draw.blend = texture->blendMode;
icculus@12214
   583
            cmd->data.draw.texture = texture;
icculus@12214
   584
        }
icculus@12211
   585
    }
icculus@12211
   586
    return cmd;
icculus@12211
   587
}
icculus@12211
   588
icculus@12211
   589
static int
icculus@12211
   590
QueueCmdCopy(SDL_Renderer *renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect)
icculus@12211
   591
{
icculus@12211
   592
    SDL_RenderCommand *cmd = PrepQueueCmdDrawTexture(renderer, texture, SDL_RENDERCMD_COPY);
icculus@12211
   593
    int retval = -1;
icculus@12211
   594
    if (cmd != NULL) {
icculus@12211
   595
        retval = renderer->QueueCopy(renderer, cmd, texture, srcrect, dstrect);
icculus@12211
   596
        if (retval < 0) {
icculus@12211
   597
            cmd->command = SDL_RENDERCMD_NO_OP;
icculus@12211
   598
        }
icculus@12211
   599
    }
icculus@12236
   600
    return retval;
icculus@12211
   601
}
icculus@12211
   602
icculus@12211
   603
static int
icculus@12211
   604
QueueCmdCopyEx(SDL_Renderer *renderer, SDL_Texture * texture,
icculus@12211
   605
               const SDL_Rect * srcquad, const SDL_FRect * dstrect,
icculus@12211
   606
               const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
icculus@12211
   607
{
icculus@12211
   608
    SDL_RenderCommand *cmd = PrepQueueCmdDrawTexture(renderer, texture, SDL_RENDERCMD_COPY_EX);
icculus@12264
   609
    int retval = -1;
icculus@12211
   610
    SDL_assert(renderer->QueueCopyEx != NULL);  /* should have caught at higher level. */
icculus@12211
   611
    if (cmd != NULL) {
icculus@12211
   612
        retval = renderer->QueueCopyEx(renderer, cmd, texture, srcquad, dstrect, angle, center, flip);
icculus@12211
   613
        if (retval < 0) {
icculus@12211
   614
            cmd->command = SDL_RENDERCMD_NO_OP;
icculus@12211
   615
        }
icculus@12211
   616
    }
icculus@12236
   617
    return retval;
icculus@12211
   618
}
icculus@12211
   619
icculus@12211
   620
slouken@6530
   621
static int UpdateLogicalSize(SDL_Renderer *renderer);
slouken@6530
   622
slouken@5154
   623
int
slouken@5154
   624
SDL_GetNumRenderDrivers(void)
slouken@5154
   625
{
slouken@7109
   626
#if !SDL_RENDER_DISABLED
slouken@5154
   627
    return SDL_arraysize(render_drivers);
slouken@7109
   628
#else
slouken@7109
   629
    return 0;
slouken@7109
   630
#endif
slouken@5154
   631
}
slouken@5154
   632
slouken@5154
   633
int
slouken@5154
   634
SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info)
slouken@5154
   635
{
slouken@7109
   636
#if !SDL_RENDER_DISABLED
slouken@5154
   637
    if (index < 0 || index >= SDL_GetNumRenderDrivers()) {
icculus@7037
   638
        return SDL_SetError("index must be in the range of 0 - %d",
icculus@7037
   639
                            SDL_GetNumRenderDrivers() - 1);
slouken@5154
   640
    }
slouken@5154
   641
    *info = render_drivers[index]->info;
slouken@5154
   642
    return 0;
slouken@7109
   643
#else
slouken@7109
   644
    return SDL_SetError("SDL not built with rendering support");
slouken@7109
   645
#endif
slouken@5154
   646
}
slouken@5154
   647
slouken@12021
   648
static void GetWindowViewportValues(SDL_Renderer *renderer, int *logical_w, int *logical_h, SDL_Rect *viewport, SDL_FPoint *scale)
slouken@12021
   649
{
slouken@12021
   650
    SDL_LockMutex(renderer->target_mutex);
slouken@12021
   651
    *logical_w = renderer->target ? renderer->logical_w_backup : renderer->logical_w;
slouken@12021
   652
    *logical_h = renderer->target ? renderer->logical_h_backup : renderer->logical_h;
slouken@12021
   653
    *viewport = renderer->target ? renderer->viewport_backup : renderer->viewport;
slouken@12021
   654
    *scale = renderer->target ? renderer->scale_backup : renderer->scale;
slouken@12021
   655
    SDL_UnlockMutex(renderer->target_mutex);
slouken@12021
   656
}
slouken@12021
   657
slouken@11272
   658
static int SDLCALL
slouken@5154
   659
SDL_RendererEventWatch(void *userdata, SDL_Event *event)
slouken@5154
   660
{
slouken@5154
   661
    SDL_Renderer *renderer = (SDL_Renderer *)userdata;
slouken@5154
   662
slouken@5297
   663
    if (event->type == SDL_WINDOWEVENT) {
slouken@5154
   664
        SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
slouken@5154
   665
        if (window == renderer->window) {
slouken@5297
   666
            if (renderer->WindowEvent) {
slouken@5297
   667
                renderer->WindowEvent(renderer, &event->window);
slouken@5297
   668
            }
slouken@5297
   669
slouken@7240
   670
            if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
slouken@9084
   671
                /* Make sure we're operating on the default render target */
slouken@9084
   672
                SDL_Texture *saved_target = SDL_GetRenderTarget(renderer);
slouken@9084
   673
                if (saved_target) {
slouken@9084
   674
                    SDL_SetRenderTarget(renderer, NULL);
slouken@9084
   675
                }
slouken@9084
   676
slouken@6530
   677
                if (renderer->logical_w) {
slouken@6530
   678
                    UpdateLogicalSize(renderer);
slouken@7240
   679
                } else {
slouken@7240
   680
                    /* Window was resized, reset viewport */
slouken@6528
   681
                    int w, h;
slouken@6528
   682
urkle@7746
   683
                    if (renderer->GetOutputSize) {
urkle@7746
   684
                        renderer->GetOutputSize(renderer, &w, &h);
urkle@7746
   685
                    } else {
urkle@7746
   686
                        SDL_GetWindowSize(renderer->window, &w, &h);
urkle@7746
   687
                    }
urkle@7746
   688
slouken@6260
   689
                    if (renderer->target) {
slouken@6260
   690
                        renderer->viewport_backup.x = 0;
slouken@6260
   691
                        renderer->viewport_backup.y = 0;
slouken@6260
   692
                        renderer->viewport_backup.w = w;
slouken@6260
   693
                        renderer->viewport_backup.h = h;
slouken@6260
   694
                    } else {
slouken@6528
   695
                        renderer->viewport.x = 0;
slouken@6528
   696
                        renderer->viewport.y = 0;
slouken@6528
   697
                        renderer->viewport.w = w;
slouken@6528
   698
                        renderer->viewport.h = h;
icculus@12214
   699
                        QueueCmdSetViewport(renderer);
icculus@12236
   700
                        FlushRenderCommandsIfNotBatching(renderer);
slouken@6260
   701
                    }
slouken@6260
   702
                }
slouken@9084
   703
slouken@9084
   704
                if (saved_target) {
slouken@9084
   705
                    SDL_SetRenderTarget(renderer, saved_target);
slouken@9084
   706
                }
slouken@6260
   707
            } else if (event->window.event == SDL_WINDOWEVENT_HIDDEN) {
slouken@6260
   708
                renderer->hidden = SDL_TRUE;
slouken@6260
   709
            } else if (event->window.event == SDL_WINDOWEVENT_SHOWN) {
slouken@6260
   710
                if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)) {
slouken@6260
   711
                    renderer->hidden = SDL_FALSE;
slouken@6260
   712
                }
slouken@6060
   713
            } else if (event->window.event == SDL_WINDOWEVENT_MINIMIZED) {
slouken@6260
   714
                renderer->hidden = SDL_TRUE;
dludwig@9968
   715
            } else if (event->window.event == SDL_WINDOWEVENT_RESTORED || 
dludwig@9968
   716
                       event->window.event == SDL_WINDOWEVENT_MAXIMIZED) {
slouken@6260
   717
                if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN)) {
slouken@6260
   718
                    renderer->hidden = SDL_FALSE;
slouken@6260
   719
                }
slouken@5297
   720
            }
slouken@5154
   721
        }
slouken@6530
   722
    } else if (event->type == SDL_MOUSEMOTION) {
slouken@9673
   723
        SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID);
slouken@12021
   724
        if (window == renderer->window) {
slouken@12021
   725
            int logical_w, logical_h;
slouken@12021
   726
            SDL_Rect viewport;
slouken@12021
   727
            SDL_FPoint scale;
slouken@12021
   728
            GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale);
slouken@12021
   729
            if (logical_w) {
slouken@12021
   730
                event->motion.x -= (int)(viewport.x * renderer->dpi_scale.x);
slouken@12021
   731
                event->motion.y -= (int)(viewport.y * renderer->dpi_scale.y);
slouken@12021
   732
                event->motion.x = (int)(event->motion.x / (scale.x * renderer->dpi_scale.x));
slouken@12021
   733
                event->motion.y = (int)(event->motion.y / (scale.y * renderer->dpi_scale.y));
slouken@12021
   734
                if (event->motion.xrel > 0) {
slouken@12021
   735
                    event->motion.xrel = SDL_max(1, (int)(event->motion.xrel / (scale.x * renderer->dpi_scale.x)));
slouken@12021
   736
                } else if (event->motion.xrel < 0) {
slouken@12021
   737
                    event->motion.xrel = SDL_min(-1, (int)(event->motion.xrel / (scale.x * renderer->dpi_scale.x)));
slouken@12021
   738
                }
slouken@12021
   739
                if (event->motion.yrel > 0) {
slouken@12021
   740
                    event->motion.yrel = SDL_max(1, (int)(event->motion.yrel / (scale.y * renderer->dpi_scale.y)));
slouken@12021
   741
                } else if (event->motion.yrel < 0) {
slouken@12021
   742
                    event->motion.yrel = SDL_min(-1, (int)(event->motion.yrel / (scale.y * renderer->dpi_scale.y)));
slouken@12021
   743
                }
slouken@7496
   744
            }
slouken@6530
   745
        }
slouken@6530
   746
    } else if (event->type == SDL_MOUSEBUTTONDOWN ||
slouken@6530
   747
               event->type == SDL_MOUSEBUTTONUP) {
slouken@9673
   748
        SDL_Window *window = SDL_GetWindowFromID(event->button.windowID);
slouken@12021
   749
        if (window == renderer->window) {
slouken@12021
   750
            int logical_w, logical_h;
slouken@12021
   751
            SDL_Rect viewport;
slouken@12021
   752
            SDL_FPoint scale;
slouken@12021
   753
            GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale);
slouken@12021
   754
            if (logical_w) {
slouken@12021
   755
                event->button.x -= (int)(viewport.x * renderer->dpi_scale.x);
slouken@12021
   756
                event->button.y -= (int)(viewport.y * renderer->dpi_scale.y);
slouken@12021
   757
                event->button.x = (int)(event->button.x / (scale.x * renderer->dpi_scale.x));
slouken@12021
   758
                event->button.y = (int)(event->button.y / (scale.y * renderer->dpi_scale.y));
slouken@12021
   759
            }
slouken@6530
   760
        }
slouken@11603
   761
    } else if (event->type == SDL_FINGERDOWN ||
slouken@11603
   762
               event->type == SDL_FINGERUP ||
slouken@11603
   763
               event->type == SDL_FINGERMOTION) {
slouken@12021
   764
        int logical_w, logical_h;
slouken@12021
   765
        SDL_Rect viewport;
slouken@12021
   766
        SDL_FPoint scale;
slouken@12021
   767
        GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale);
slouken@12021
   768
        if (logical_w) {
slouken@11603
   769
            int w = 1;
slouken@11603
   770
            int h = 1;
slouken@11603
   771
            SDL_GetRendererOutputSize(renderer, &w, &h);
slouken@11603
   772
slouken@11603
   773
            event->tfinger.x *= (w - 1);
slouken@11603
   774
            event->tfinger.y *= (h - 1);
slouken@11603
   775
slouken@12021
   776
            event->tfinger.x -= (viewport.x * renderer->dpi_scale.x);
slouken@12021
   777
            event->tfinger.y -= (viewport.y * renderer->dpi_scale.y);
slouken@12021
   778
            event->tfinger.x = (event->tfinger.x / (scale.x * renderer->dpi_scale.x));
slouken@12021
   779
            event->tfinger.y = (event->tfinger.y / (scale.y * renderer->dpi_scale.y));
slouken@11603
   780
slouken@12021
   781
            if (logical_w > 1) {
slouken@12021
   782
                event->tfinger.x = event->tfinger.x / (logical_w - 1);
slouken@11603
   783
            } else {
slouken@11603
   784
                event->tfinger.x = 0.5f;
slouken@11603
   785
            }
slouken@12021
   786
            if (logical_h > 1) {
slouken@12021
   787
                event->tfinger.y = event->tfinger.y / (logical_h - 1);
slouken@11603
   788
            } else {
slouken@11603
   789
                event->tfinger.y = 0.5f;
slouken@11603
   790
            }
slouken@11603
   791
        }
slouken@5154
   792
    }
slouken@11603
   793
slouken@5154
   794
    return 0;
slouken@5154
   795
}
slouken@5154
   796
slouken@6258
   797
int
slouken@6258
   798
SDL_CreateWindowAndRenderer(int width, int height, Uint32 window_flags,
slouken@6258
   799
                            SDL_Window **window, SDL_Renderer **renderer)
slouken@6258
   800
{
slouken@6258
   801
    *window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED,
slouken@6258
   802
                                     SDL_WINDOWPOS_UNDEFINED,
slouken@6258
   803
                                     width, height, window_flags);
slouken@6258
   804
    if (!*window) {
slouken@6258
   805
        *renderer = NULL;
slouken@6258
   806
        return -1;
slouken@6258
   807
    }
slouken@6258
   808
slouken@6258
   809
    *renderer = SDL_CreateRenderer(*window, -1, 0);
slouken@6258
   810
    if (!*renderer) {
slouken@6258
   811
        return -1;
slouken@6258
   812
    }
slouken@6258
   813
slouken@6258
   814
    return 0;
slouken@6258
   815
}
slouken@6258
   816
icculus@12211
   817
static SDL_INLINE
icculus@12211
   818
void VerifyDrawQueueFunctions(const SDL_Renderer *renderer)
icculus@12211
   819
{
icculus@12211
   820
    /* all of these functions are required to be implemented, even as no-ops, so we don't
icculus@12211
   821
        have to check that they aren't NULL over and over. */
icculus@12214
   822
    SDL_assert(renderer->QueueSetViewport != NULL);
icculus@12214
   823
    SDL_assert(renderer->QueueSetDrawColor != NULL);
icculus@12211
   824
    SDL_assert(renderer->QueueDrawPoints != NULL);
icculus@12211
   825
    SDL_assert(renderer->QueueDrawLines != NULL);
icculus@12211
   826
    SDL_assert(renderer->QueueFillRects != NULL);
icculus@12211
   827
    SDL_assert(renderer->QueueCopy != NULL);
icculus@12211
   828
    SDL_assert(renderer->RunCommandQueue != NULL);
icculus@12211
   829
}
icculus@12211
   830
slouken@5154
   831
SDL_Renderer *
slouken@5154
   832
SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
slouken@5154
   833
{
slouken@7109
   834
#if !SDL_RENDER_DISABLED
slouken@5154
   835
    SDL_Renderer *renderer = NULL;
slouken@5154
   836
    int n = SDL_GetNumRenderDrivers();
icculus@12211
   837
    SDL_bool batching = SDL_TRUE;
slouken@5192
   838
    const char *hint;
slouken@5192
   839
slouken@5528
   840
    if (!window) {
slouken@5528
   841
        SDL_SetError("Invalid window");
slouken@5528
   842
        return NULL;
slouken@5528
   843
    }
slouken@5528
   844
slouken@5528
   845
    if (SDL_GetRenderer(window)) {
slouken@5528
   846
        SDL_SetError("Renderer already associated with window");
slouken@5528
   847
        return NULL;
slouken@5528
   848
    }
slouken@5528
   849
slouken@10499
   850
    if (SDL_GetHint(SDL_HINT_RENDER_VSYNC)) {
slouken@10499
   851
        if (SDL_GetHintBoolean(SDL_HINT_RENDER_VSYNC, SDL_TRUE)) {
slouken@10499
   852
            flags |= SDL_RENDERER_PRESENTVSYNC;
slouken@10499
   853
        } else {
slouken@5192
   854
            flags &= ~SDL_RENDERER_PRESENTVSYNC;
slouken@5192
   855
        }
slouken@5192
   856
    }
slouken@5154
   857
slouken@5154
   858
    if (index < 0) {
slouken@5192
   859
        hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
slouken@5192
   860
        if (hint) {
slouken@5154
   861
            for (index = 0; index < n; ++index) {
slouken@5154
   862
                const SDL_RenderDriver *driver = render_drivers[index];
slouken@5154
   863
slouken@5192
   864
                if (SDL_strcasecmp(hint, driver->info.name) == 0) {
slouken@5154
   865
                    /* Create a new renderer instance */
slouken@5154
   866
                    renderer = driver->CreateRenderer(window, flags);
icculus@12211
   867
                    if (renderer) {
icculus@12211
   868
                        batching = SDL_FALSE;
icculus@12211
   869
                    }
slouken@5154
   870
                    break;
slouken@5154
   871
                }
slouken@5154
   872
            }
slouken@5192
   873
        }
slouken@5192
   874
slouken@5192
   875
        if (!renderer) {
slouken@5154
   876
            for (index = 0; index < n; ++index) {
slouken@5154
   877
                const SDL_RenderDriver *driver = render_drivers[index];
slouken@5154
   878
slouken@5154
   879
                if ((driver->info.flags & flags) == flags) {
slouken@5154
   880
                    /* Create a new renderer instance */
slouken@5154
   881
                    renderer = driver->CreateRenderer(window, flags);
slouken@5154
   882
                    if (renderer) {
slouken@5154
   883
                        /* Yay, we got one! */
slouken@5154
   884
                        break;
slouken@5154
   885
                    }
slouken@5154
   886
                }
slouken@5154
   887
            }
slouken@5154
   888
        }
slouken@5154
   889
        if (index == n) {
slouken@5154
   890
            SDL_SetError("Couldn't find matching render driver");
slouken@5154
   891
            return NULL;
slouken@5154
   892
        }
slouken@5154
   893
    } else {
slouken@5154
   894
        if (index >= SDL_GetNumRenderDrivers()) {
slouken@5154
   895
            SDL_SetError("index must be -1 or in the range of 0 - %d",
slouken@5154
   896
                         SDL_GetNumRenderDrivers() - 1);
slouken@5154
   897
            return NULL;
slouken@5154
   898
        }
slouken@5154
   899
        /* Create a new renderer instance */
slouken@5154
   900
        renderer = render_drivers[index]->CreateRenderer(window, flags);
icculus@12211
   901
        batching = SDL_FALSE;
slouken@5154
   902
    }
slouken@5154
   903
slouken@5154
   904
    if (renderer) {
icculus@12211
   905
        VerifyDrawQueueFunctions(renderer);
icculus@12211
   906
icculus@12211
   907
        /* let app/user override batching decisions. */
icculus@12214
   908
        if (renderer->always_batch) {
icculus@12214
   909
            batching = SDL_TRUE;
icculus@12214
   910
        } else if (SDL_GetHint(SDL_HINT_RENDER_BATCHING)) {
icculus@12211
   911
            batching = SDL_GetHintBoolean(SDL_HINT_RENDER_BATCHING, SDL_TRUE);
icculus@12211
   912
        }
icculus@12211
   913
icculus@12211
   914
        renderer->batching = batching;
slouken@5154
   915
        renderer->magic = &renderer_magic;
slouken@5166
   916
        renderer->window = window;
slouken@12021
   917
        renderer->target_mutex = SDL_CreateMutex();
slouken@6528
   918
        renderer->scale.x = 1.0f;
slouken@6528
   919
        renderer->scale.y = 1.0f;
slouken@11178
   920
        renderer->dpi_scale.x = 1.0f;
slouken@11178
   921
        renderer->dpi_scale.y = 1.0f;
slouken@11178
   922
icculus@12211
   923
        /* new textures start at zero, so we start at 1 so first render doesn't flush by accident. */
icculus@12211
   924
        renderer->render_command_generation = 1;
icculus@12211
   925
slouken@11178
   926
        if (window && renderer->GetOutputSize) {
slouken@11178
   927
            int window_w, window_h;
slouken@11178
   928
            int output_w, output_h;
slouken@11178
   929
            if (renderer->GetOutputSize(renderer, &output_w, &output_h) == 0) {
slouken@11178
   930
                SDL_GetWindowSize(renderer->window, &window_w, &window_h);
slouken@11178
   931
                renderer->dpi_scale.x = (float)window_w / output_w;
slouken@11178
   932
                renderer->dpi_scale.y = (float)window_h / output_h;
slouken@11178
   933
            }
slouken@11178
   934
        }
slouken@5154
   935
slouken@6260
   936
        if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) {
slouken@6260
   937
            renderer->hidden = SDL_TRUE;
slouken@6060
   938
        } else {
slouken@6260
   939
            renderer->hidden = SDL_FALSE;
slouken@6060
   940
        }
slouken@6060
   941
slouken@5528
   942
        SDL_SetWindowData(window, SDL_WINDOWRENDERDATA, renderer);
slouken@5528
   943
slouken@5297
   944
        SDL_RenderSetViewport(renderer, NULL);
slouken@5297
   945
slouken@5154
   946
        SDL_AddEventWatch(SDL_RendererEventWatch, renderer);
slouken@5221
   947
slouken@5221
   948
        SDL_LogInfo(SDL_LOG_CATEGORY_RENDER,
slouken@5221
   949
                    "Created renderer: %s", renderer->info.name);
slouken@5154
   950
    }
slouken@5154
   951
    return renderer;
slouken@7109
   952
#else
slouken@7109
   953
    SDL_SetError("SDL not built with rendering support");
slouken@7109
   954
    return NULL;
slouken@7109
   955
#endif
slouken@5154
   956
}
slouken@5154
   957
slouken@5166
   958
SDL_Renderer *
slouken@5166
   959
SDL_CreateSoftwareRenderer(SDL_Surface * surface)
slouken@5166
   960
{
slouken@5226
   961
#if !SDL_RENDER_DISABLED
slouken@5297
   962
    SDL_Renderer *renderer;
slouken@5297
   963
slouken@5297
   964
    renderer = SW_CreateRendererForSurface(surface);
slouken@5297
   965
slouken@5297
   966
    if (renderer) {
icculus@12211
   967
        VerifyDrawQueueFunctions(renderer);
slouken@5297
   968
        renderer->magic = &renderer_magic;
slouken@12021
   969
        renderer->target_mutex = SDL_CreateMutex();
slouken@6532
   970
        renderer->scale.x = 1.0f;
slouken@6532
   971
        renderer->scale.y = 1.0f;
slouken@5297
   972
icculus@12211
   973
        /* new textures start at zero, so we start at 1 so first render doesn't flush by accident. */
icculus@12211
   974
        renderer->render_command_generation = 1;
icculus@12211
   975
slouken@5297
   976
        SDL_RenderSetViewport(renderer, NULL);
slouken@5297
   977
    }
slouken@5297
   978
    return renderer;
slouken@5226
   979
#else
slouken@5226
   980
    SDL_SetError("SDL not built with rendering support");
slouken@5226
   981
    return NULL;
slouken@5226
   982
#endif /* !SDL_RENDER_DISABLED */
slouken@5166
   983
}
slouken@5166
   984
slouken@5528
   985
SDL_Renderer *
slouken@5528
   986
SDL_GetRenderer(SDL_Window * window)
slouken@5528
   987
{
slouken@5528
   988
    return (SDL_Renderer *)SDL_GetWindowData(window, SDL_WINDOWRENDERDATA);
slouken@5528
   989
}
slouken@5528
   990
slouken@5154
   991
int
slouken@5154
   992
SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info)
slouken@5154
   993
{
slouken@5154
   994
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
   995
slouken@5154
   996
    *info = renderer->info;
slouken@5154
   997
    return 0;
slouken@5154
   998
}
slouken@5154
   999
slouken@7239
  1000
int
slouken@7239
  1001
SDL_GetRendererOutputSize(SDL_Renderer * renderer, int *w, int *h)
slouken@7239
  1002
{
slouken@7239
  1003
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@7239
  1004
slouken@7239
  1005
    if (renderer->target) {
slouken@7239
  1006
        return SDL_QueryTexture(renderer->target, NULL, NULL, w, h);
urkle@7746
  1007
    } else if (renderer->GetOutputSize) {
urkle@7746
  1008
        return renderer->GetOutputSize(renderer, w, h);
slouken@7239
  1009
    } else if (renderer->window) {
slouken@7239
  1010
        SDL_GetWindowSize(renderer->window, w, h);
slouken@7239
  1011
        return 0;
slouken@7239
  1012
    } else {
icculus@8654
  1013
        SDL_assert(0 && "This should never happen");
philipp@7898
  1014
        return SDL_SetError("Renderer doesn't support querying output size");
slouken@7239
  1015
    }
slouken@7239
  1016
}
slouken@7239
  1017
slouken@5156
  1018
static SDL_bool
slouken@11282
  1019
IsSupportedBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
slouken@11282
  1020
{
slouken@11282
  1021
    switch (blendMode)
slouken@11282
  1022
    {
slouken@11282
  1023
    /* These are required to be supported by all renderers */
slouken@11282
  1024
    case SDL_BLENDMODE_NONE:
slouken@11282
  1025
    case SDL_BLENDMODE_BLEND:
slouken@11282
  1026
    case SDL_BLENDMODE_ADD:
slouken@11282
  1027
    case SDL_BLENDMODE_MOD:
slouken@11282
  1028
        return SDL_TRUE;
slouken@11282
  1029
slouken@11282
  1030
    default:
slouken@11282
  1031
        return renderer->SupportsBlendMode && renderer->SupportsBlendMode(renderer, blendMode);
slouken@11282
  1032
    }
slouken@11282
  1033
}
slouken@11282
  1034
slouken@11282
  1035
static SDL_bool
slouken@5156
  1036
IsSupportedFormat(SDL_Renderer * renderer, Uint32 format)
slouken@5156
  1037
{
slouken@5156
  1038
    Uint32 i;
slouken@5156
  1039
slouken@5156
  1040
    for (i = 0; i < renderer->info.num_texture_formats; ++i) {
slouken@5156
  1041
        if (renderer->info.texture_formats[i] == format) {
slouken@5156
  1042
            return SDL_TRUE;
slouken@5156
  1043
        }
slouken@5156
  1044
    }
slouken@5156
  1045
    return SDL_FALSE;
slouken@5156
  1046
}
slouken@5156
  1047
slouken@5156
  1048
static Uint32
slouken@5156
  1049
GetClosestSupportedFormat(SDL_Renderer * renderer, Uint32 format)
slouken@5156
  1050
{
slouken@5156
  1051
    Uint32 i;
slouken@5156
  1052
slouken@5268
  1053
    if (SDL_ISPIXELFORMAT_FOURCC(format)) {
slouken@5268
  1054
        /* Look for an exact match */
slouken@5268
  1055
        for (i = 0; i < renderer->info.num_texture_formats; ++i) {
slouken@5268
  1056
            if (renderer->info.texture_formats[i] == format) {
slouken@5268
  1057
                return renderer->info.texture_formats[i];
slouken@5268
  1058
            }
slouken@5268
  1059
        }
slouken@5268
  1060
    } else {
slouken@5268
  1061
        SDL_bool hasAlpha = SDL_ISPIXELFORMAT_ALPHA(format);
slouken@5268
  1062
slouken@5268
  1063
        /* We just want to match the first format that has the same channels */
slouken@5268
  1064
        for (i = 0; i < renderer->info.num_texture_formats; ++i) {
slouken@5300
  1065
            if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
slouken@5300
  1066
                SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == hasAlpha) {
slouken@5268
  1067
                return renderer->info.texture_formats[i];
slouken@5268
  1068
            }
slouken@5156
  1069
        }
slouken@5156
  1070
    }
slouken@5156
  1071
    return renderer->info.texture_formats[0];
slouken@5156
  1072
}
slouken@5156
  1073
slouken@12242
  1074
slouken@12242
  1075
static SDL_ScaleMode SDL_GetScaleMode(void)
slouken@11958
  1076
{
slouken@11958
  1077
    const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
slouken@11958
  1078
slouken@11958
  1079
    if (!hint || SDL_strcasecmp(hint, "nearest") == 0) {
slouken@11958
  1080
        return SDL_ScaleModeNearest;
slouken@11958
  1081
    } else if (SDL_strcasecmp(hint, "linear") == 0) {
slouken@11958
  1082
        return SDL_ScaleModeLinear;
slouken@11958
  1083
    } else if (SDL_strcasecmp(hint, "best") == 0) {
slouken@11958
  1084
        return SDL_ScaleModeBest;
slouken@11958
  1085
    } else {
slouken@11958
  1086
        return (SDL_ScaleMode)SDL_atoi(hint);
slouken@11958
  1087
    }
slouken@11958
  1088
}
slouken@11958
  1089
slouken@5154
  1090
SDL_Texture *
slouken@5154
  1091
SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h)
slouken@5154
  1092
{
slouken@5154
  1093
    SDL_Texture *texture;
slouken@5154
  1094
slouken@5154
  1095
    CHECK_RENDERER_MAGIC(renderer, NULL);
slouken@5154
  1096
slouken@5413
  1097
    if (!format) {
slouken@5413
  1098
        format = renderer->info.texture_formats[0];
slouken@5413
  1099
    }
icculus@8650
  1100
    if (SDL_BYTESPERPIXEL(format) == 0) {
icculus@8650
  1101
        SDL_SetError("Invalid texture format");
icculus@8650
  1102
        return NULL;
icculus@8650
  1103
    }
slouken@5156
  1104
    if (SDL_ISPIXELFORMAT_INDEXED(format)) {
slouken@5156
  1105
        SDL_SetError("Palettized textures are not supported");
slouken@5156
  1106
        return NULL;
slouken@5156
  1107
    }
slouken@5154
  1108
    if (w <= 0 || h <= 0) {
slouken@5154
  1109
        SDL_SetError("Texture dimensions can't be 0");
slouken@5156
  1110
        return NULL;
slouken@5154
  1111
    }
slouken@7770
  1112
    if ((renderer->info.max_texture_width && w > renderer->info.max_texture_width) ||
slouken@7770
  1113
        (renderer->info.max_texture_height && h > renderer->info.max_texture_height)) {
slouken@7770
  1114
        SDL_SetError("Texture dimensions are limited to %dx%d", renderer->info.max_texture_width, renderer->info.max_texture_height);
slouken@7770
  1115
        return NULL;
slouken@7770
  1116
    }
slouken@5154
  1117
    texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
slouken@5154
  1118
    if (!texture) {
slouken@5154
  1119
        SDL_OutOfMemory();
slouken@5156
  1120
        return NULL;
slouken@5154
  1121
    }
slouken@5154
  1122
    texture->magic = &texture_magic;
slouken@5154
  1123
    texture->format = format;
slouken@5154
  1124
    texture->access = access;
slouken@5154
  1125
    texture->w = w;
slouken@5154
  1126
    texture->h = h;
slouken@5154
  1127
    texture->r = 255;
slouken@5154
  1128
    texture->g = 255;
slouken@5154
  1129
    texture->b = 255;
slouken@5154
  1130
    texture->a = 255;
slouken@11958
  1131
    texture->scaleMode = SDL_GetScaleMode();
slouken@5154
  1132
    texture->renderer = renderer;
slouken@5154
  1133
    texture->next = renderer->textures;
slouken@5154
  1134
    if (renderer->textures) {
slouken@5154
  1135
        renderer->textures->prev = texture;
slouken@5154
  1136
    }
slouken@5154
  1137
    renderer->textures = texture;
slouken@5154
  1138
slouken@5156
  1139
    if (IsSupportedFormat(renderer, format)) {
slouken@5156
  1140
        if (renderer->CreateTexture(renderer, texture) < 0) {
slouken@5156
  1141
            SDL_DestroyTexture(texture);
philipp@9849
  1142
            return NULL;
slouken@5156
  1143
        }
slouken@5156
  1144
    } else {
slouken@5156
  1145
        texture->native = SDL_CreateTexture(renderer,
slouken@5156
  1146
                                GetClosestSupportedFormat(renderer, format),
slouken@5156
  1147
                                access, w, h);
slouken@5156
  1148
        if (!texture->native) {
slouken@5156
  1149
            SDL_DestroyTexture(texture);
slouken@5156
  1150
            return NULL;
slouken@5156
  1151
        }
slouken@5156
  1152
slouken@6497
  1153
        /* Swap textures to have texture before texture->native in the list */
slouken@6497
  1154
        texture->native->next = texture->next;
slouken@6533
  1155
        if (texture->native->next) {
slouken@6533
  1156
            texture->native->next->prev = texture->native;
slouken@6533
  1157
        }
slouken@6497
  1158
        texture->prev = texture->native->prev;
slouken@6533
  1159
        if (texture->prev) {
slouken@6533
  1160
            texture->prev->next = texture;
slouken@6533
  1161
        }
slouken@6497
  1162
        texture->native->prev = texture;
slouken@6497
  1163
        texture->next = texture->native;
slouken@6497
  1164
        renderer->textures = texture;
slouken@6497
  1165
slouken@5156
  1166
        if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
slouken@5156
  1167
            texture->yuv = SDL_SW_CreateYUVTexture(format, w, h);
slouken@5156
  1168
            if (!texture->yuv) {
slouken@5156
  1169
                SDL_DestroyTexture(texture);
slouken@5156
  1170
                return NULL;
slouken@5156
  1171
            }
slouken@5156
  1172
        } else if (access == SDL_TEXTUREACCESS_STREAMING) {
slouken@5156
  1173
            /* The pitch is 4 byte aligned */
slouken@5156
  1174
            texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3);
slouken@5342
  1175
            texture->pixels = SDL_calloc(1, texture->pitch * h);
slouken@5156
  1176
            if (!texture->pixels) {
slouken@5156
  1177
                SDL_DestroyTexture(texture);
slouken@5156
  1178
                return NULL;
slouken@5156
  1179
            }
slouken@5156
  1180
        }
slouken@5154
  1181
    }
slouken@5154
  1182
    return texture;
slouken@5154
  1183
}
slouken@5154
  1184
slouken@5154
  1185
SDL_Texture *
slouken@5158
  1186
SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface)
slouken@5154
  1187
{
slouken@5158
  1188
    const SDL_PixelFormat *fmt;
slouken@5158
  1189
    SDL_bool needAlpha;
slouken@5158
  1190
    Uint32 i;
slouken@5158
  1191
    Uint32 format;
slouken@5158
  1192
    SDL_Texture *texture;
slouken@5154
  1193
slouken@5154
  1194
    CHECK_RENDERER_MAGIC(renderer, NULL);
slouken@5154
  1195
slouken@5154
  1196
    if (!surface) {
slouken@5154
  1197
        SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
slouken@5154
  1198
        return NULL;
slouken@5154
  1199
    }
slouken@5158
  1200
slouken@5158
  1201
    /* See what the best texture format is */
slouken@5154
  1202
    fmt = surface->format;
slouken@12223
  1203
    if (fmt->Amask || SDL_HasColorKey(surface)) {
slouken@5158
  1204
        needAlpha = SDL_TRUE;
slouken@5154
  1205
    } else {
slouken@5158
  1206
        needAlpha = SDL_FALSE;
slouken@5158
  1207
    }
slouken@5158
  1208
    format = renderer->info.texture_formats[0];
slouken@5158
  1209
    for (i = 0; i < renderer->info.num_texture_formats; ++i) {
slouken@5268
  1210
        if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
slouken@5268
  1211
            SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) {
slouken@5158
  1212
            format = renderer->info.texture_formats[i];
slouken@5158
  1213
            break;
slouken@5154
  1214
        }
slouken@5154
  1215
    }
slouken@5154
  1216
slouken@5158
  1217
    texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
slouken@5158
  1218
                                surface->w, surface->h);
slouken@5154
  1219
    if (!texture) {
slouken@5158
  1220
        return NULL;
slouken@5154
  1221
    }
slouken@5158
  1222
slouken@5288
  1223
    if (format == surface->format->format) {
slouken@5154
  1224
        if (SDL_MUSTLOCK(surface)) {
slouken@5154
  1225
            SDL_LockSurface(surface);
slouken@5158
  1226
            SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
slouken@5154
  1227
            SDL_UnlockSurface(surface);
slouken@5154
  1228
        } else {
slouken@5158
  1229
            SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
slouken@5154
  1230
        }
slouken@5154
  1231
    } else {
slouken@5297
  1232
        SDL_PixelFormat *dst_fmt;
slouken@5158
  1233
        SDL_Surface *temp = NULL;
slouken@5154
  1234
slouken@5154
  1235
        /* Set up a destination surface for the texture update */
slouken@5297
  1236
        dst_fmt = SDL_AllocFormat(format);
slouken@9078
  1237
        if (!dst_fmt) {
slouken@9078
  1238
           SDL_DestroyTexture(texture);
slouken@9078
  1239
           return NULL;
slouken@9078
  1240
        }
slouken@5297
  1241
        temp = SDL_ConvertSurface(surface, dst_fmt, 0);
slouken@5297
  1242
        SDL_FreeFormat(dst_fmt);
slouken@5158
  1243
        if (temp) {
slouken@5158
  1244
            SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch);
slouken@5158
  1245
            SDL_FreeSurface(temp);
slouken@5158
  1246
        } else {
slouken@5154
  1247
            SDL_DestroyTexture(texture);
slouken@5158
  1248
            return NULL;
slouken@5154
  1249
        }
slouken@5154
  1250
    }
slouken@5154
  1251
slouken@5154
  1252
    {
slouken@5154
  1253
        Uint8 r, g, b, a;
slouken@5154
  1254
        SDL_BlendMode blendMode;
slouken@5154
  1255
slouken@5154
  1256
        SDL_GetSurfaceColorMod(surface, &r, &g, &b);
slouken@5154
  1257
        SDL_SetTextureColorMod(texture, r, g, b);
slouken@5154
  1258
slouken@5154
  1259
        SDL_GetSurfaceAlphaMod(surface, &a);
slouken@5154
  1260
        SDL_SetTextureAlphaMod(texture, a);
slouken@5154
  1261
slouken@12223
  1262
        if (SDL_HasColorKey(surface)) {
slouken@5154
  1263
            /* We converted to a texture with alpha format */
slouken@5154
  1264
            SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
slouken@5154
  1265
        } else {
slouken@5154
  1266
            SDL_GetSurfaceBlendMode(surface, &blendMode);
slouken@5154
  1267
            SDL_SetTextureBlendMode(texture, blendMode);
slouken@5154
  1268
        }
slouken@5154
  1269
    }
slouken@5154
  1270
    return texture;
slouken@5154
  1271
}
slouken@5154
  1272
slouken@5154
  1273
int
slouken@5154
  1274
SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access,
slouken@5154
  1275
                 int *w, int *h)
slouken@5154
  1276
{
slouken@5154
  1277
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
  1278
slouken@5154
  1279
    if (format) {
slouken@5154
  1280
        *format = texture->format;
slouken@5154
  1281
    }
slouken@5154
  1282
    if (access) {
slouken@5154
  1283
        *access = texture->access;
slouken@5154
  1284
    }
slouken@5154
  1285
    if (w) {
slouken@5154
  1286
        *w = texture->w;
slouken@5154
  1287
    }
slouken@5154
  1288
    if (h) {
slouken@5154
  1289
        *h = texture->h;
slouken@5154
  1290
    }
slouken@5154
  1291
    return 0;
slouken@5154
  1292
}
slouken@5154
  1293
slouken@5154
  1294
int
slouken@5154
  1295
SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
slouken@5154
  1296
{
slouken@5154
  1297
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
  1298
slouken@5154
  1299
    if (r < 255 || g < 255 || b < 255) {
slouken@5154
  1300
        texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
slouken@5154
  1301
    } else {
slouken@5154
  1302
        texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
slouken@5154
  1303
    }
slouken@5154
  1304
    texture->r = r;
slouken@5154
  1305
    texture->g = g;
slouken@5154
  1306
    texture->b = b;
slouken@5156
  1307
    if (texture->native) {
slouken@5156
  1308
        return SDL_SetTextureColorMod(texture->native, r, g, b);
slouken@5154
  1309
    }
icculus@12211
  1310
    return 0;
slouken@5154
  1311
}
slouken@5154
  1312
slouken@5154
  1313
int
slouken@5154
  1314
SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g,
slouken@5154
  1315
                       Uint8 * b)
slouken@5154
  1316
{
slouken@5154
  1317
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
  1318
slouken@5154
  1319
    if (r) {
slouken@5154
  1320
        *r = texture->r;
slouken@5154
  1321
    }
slouken@5154
  1322
    if (g) {
slouken@5154
  1323
        *g = texture->g;
slouken@5154
  1324
    }
slouken@5154
  1325
    if (b) {
slouken@5154
  1326
        *b = texture->b;
slouken@5154
  1327
    }
slouken@5154
  1328
    return 0;
slouken@5154
  1329
}
slouken@5154
  1330
slouken@5154
  1331
int
slouken@5154
  1332
SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
slouken@5154
  1333
{
slouken@5154
  1334
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
  1335
slouken@5154
  1336
    if (alpha < 255) {
slouken@5154
  1337
        texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
slouken@5154
  1338
    } else {
slouken@5154
  1339
        texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA;
slouken@5154
  1340
    }
slouken@5154
  1341
    texture->a = alpha;
slouken@5156
  1342
    if (texture->native) {
slouken@5156
  1343
        return SDL_SetTextureAlphaMod(texture->native, alpha);
slouken@5154
  1344
    }
icculus@12211
  1345
    return 0;
slouken@5154
  1346
}
slouken@5154
  1347
slouken@5154
  1348
int
slouken@5154
  1349
SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha)
slouken@5154
  1350
{
slouken@5154
  1351
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
  1352
slouken@5154
  1353
    if (alpha) {
slouken@5154
  1354
        *alpha = texture->a;
slouken@5154
  1355
    }
slouken@5154
  1356
    return 0;
slouken@5154
  1357
}
slouken@5154
  1358
slouken@5154
  1359
int
slouken@5154
  1360
SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode)
slouken@5154
  1361
{
slouken@5154
  1362
    SDL_Renderer *renderer;
slouken@5154
  1363
slouken@5154
  1364
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
  1365
slouken@5154
  1366
    renderer = texture->renderer;
slouken@11282
  1367
    if (!IsSupportedBlendMode(renderer, blendMode)) {
slouken@11282
  1368
        return SDL_Unsupported();
slouken@11282
  1369
    }
slouken@5154
  1370
    texture->blendMode = blendMode;
slouken@5156
  1371
    if (texture->native) {
slouken@5180
  1372
        return SDL_SetTextureBlendMode(texture->native, blendMode);
slouken@5154
  1373
    }
icculus@12211
  1374
    return 0;
slouken@5154
  1375
}
slouken@5154
  1376
slouken@5154
  1377
int
slouken@5154
  1378
SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode)
slouken@5154
  1379
{
slouken@5154
  1380
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
  1381
slouken@5154
  1382
    if (blendMode) {
slouken@5154
  1383
        *blendMode = texture->blendMode;
slouken@5154
  1384
    }
slouken@5154
  1385
    return 0;
slouken@5154
  1386
}
slouken@5154
  1387
slouken@5156
  1388
static int
slouken@5156
  1389
SDL_UpdateTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5156
  1390
                     const void *pixels, int pitch)
slouken@5156
  1391
{
slouken@5156
  1392
    SDL_Texture *native = texture->native;
slouken@5156
  1393
    SDL_Rect full_rect;
slouken@5156
  1394
slouken@5156
  1395
    if (SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch) < 0) {
slouken@5156
  1396
        return -1;
slouken@5156
  1397
    }
slouken@5156
  1398
slouken@5156
  1399
    full_rect.x = 0;
slouken@5156
  1400
    full_rect.y = 0;
slouken@5156
  1401
    full_rect.w = texture->w;
slouken@5156
  1402
    full_rect.h = texture->h;
slouken@5156
  1403
    rect = &full_rect;
slouken@5156
  1404
slouken@5156
  1405
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@5156
  1406
        /* We can lock the texture and copy to it */
icculus@10650
  1407
        void *native_pixels = NULL;
icculus@10650
  1408
        int native_pitch = 0;
slouken@5156
  1409
slouken@5156
  1410
        if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
slouken@5156
  1411
            return -1;
slouken@5156
  1412
        }
slouken@5156
  1413
        SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
slouken@5156
  1414
                            rect->w, rect->h, native_pixels, native_pitch);
slouken@5156
  1415
        SDL_UnlockTexture(native);
slouken@5156
  1416
    } else {
slouken@5156
  1417
        /* Use a temporary buffer for updating */
icculus@10650
  1418
        const int temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
icculus@10650
  1419
        const size_t alloclen = rect->h * temp_pitch;
icculus@10650
  1420
        if (alloclen > 0) {
icculus@10650
  1421
            void *temp_pixels = SDL_malloc(alloclen);
icculus@10650
  1422
            if (!temp_pixels) {
icculus@10650
  1423
                return SDL_OutOfMemory();
icculus@10650
  1424
            }
icculus@10650
  1425
            SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
icculus@10650
  1426
                                rect->w, rect->h, temp_pixels, temp_pitch);
icculus@10650
  1427
            SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
icculus@10650
  1428
            SDL_free(temp_pixels);
slouken@5156
  1429
        }
slouken@5156
  1430
    }
slouken@5156
  1431
    return 0;
slouken@5156
  1432
}
slouken@5156
  1433
slouken@5156
  1434
static int
slouken@5156
  1435
SDL_UpdateTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5156
  1436
                        const void *pixels, int pitch)
slouken@5156
  1437
{
slouken@5156
  1438
    SDL_Texture *native = texture->native;
slouken@5156
  1439
icculus@10650
  1440
    if (!rect->w || !rect->h) {
icculus@10650
  1441
        return 0;  /* nothing to do. */
icculus@10650
  1442
    }
icculus@10650
  1443
slouken@5156
  1444
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@5156
  1445
        /* We can lock the texture and copy to it */
icculus@10650
  1446
        void *native_pixels = NULL;
icculus@10650
  1447
        int native_pitch = 0;
slouken@5156
  1448
slouken@5156
  1449
        if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
slouken@5156
  1450
            return -1;
slouken@5156
  1451
        }
slouken@5156
  1452
        SDL_ConvertPixels(rect->w, rect->h,
slouken@5156
  1453
                          texture->format, pixels, pitch,
slouken@5156
  1454
                          native->format, native_pixels, native_pitch);
slouken@5156
  1455
        SDL_UnlockTexture(native);
slouken@5156
  1456
    } else {
slouken@5156
  1457
        /* Use a temporary buffer for updating */
icculus@10650
  1458
        const int temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
icculus@10650
  1459
        const size_t alloclen = rect->h * temp_pitch;
icculus@10650
  1460
        if (alloclen > 0) {
icculus@10650
  1461
            void *temp_pixels = SDL_malloc(alloclen);
icculus@10650
  1462
            if (!temp_pixels) {
icculus@10650
  1463
                return SDL_OutOfMemory();
icculus@10650
  1464
            }
icculus@10650
  1465
            SDL_ConvertPixels(rect->w, rect->h,
icculus@10650
  1466
                              texture->format, pixels, pitch,
icculus@10650
  1467
                              native->format, temp_pixels, temp_pitch);
icculus@10650
  1468
            SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
icculus@10650
  1469
            SDL_free(temp_pixels);
slouken@5156
  1470
        }
slouken@5156
  1471
    }
slouken@5156
  1472
    return 0;
slouken@5156
  1473
}
slouken@5156
  1474
slouken@5154
  1475
int
slouken@5154
  1476
SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5154
  1477
                  const void *pixels, int pitch)
slouken@5154
  1478
{
slouken@5154
  1479
    SDL_Rect full_rect;
slouken@5154
  1480
slouken@5154
  1481
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
  1482
slouken@7409
  1483
    if (!pixels) {
slouken@7409
  1484
        return SDL_InvalidParamError("pixels");
slouken@7409
  1485
    }
slouken@7409
  1486
    if (!pitch) {
slouken@7409
  1487
        return SDL_InvalidParamError("pitch");
slouken@7409
  1488
    }
slouken@7409
  1489
slouken@5154
  1490
    if (!rect) {
slouken@5154
  1491
        full_rect.x = 0;
slouken@5154
  1492
        full_rect.y = 0;
slouken@5154
  1493
        full_rect.w = texture->w;
slouken@5154
  1494
        full_rect.h = texture->h;
slouken@5154
  1495
        rect = &full_rect;
slouken@5154
  1496
    }
slouken@5156
  1497
icculus@9636
  1498
    if ((rect->w == 0) || (rect->h == 0)) {
icculus@9636
  1499
        return 0;  /* nothing to do. */
icculus@9636
  1500
    } else if (texture->yuv) {
slouken@5156
  1501
        return SDL_UpdateTextureYUV(texture, rect, pixels, pitch);
slouken@5156
  1502
    } else if (texture->native) {
slouken@5156
  1503
        return SDL_UpdateTextureNative(texture, rect, pixels, pitch);
slouken@5156
  1504
    } else {
icculus@12211
  1505
        SDL_Renderer *renderer = texture->renderer;
icculus@12211
  1506
        if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
icculus@12211
  1507
            return -1;
icculus@12211
  1508
        }
slouken@5156
  1509
        return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
slouken@5156
  1510
    }
slouken@5156
  1511
}
slouken@5156
  1512
slouken@5156
  1513
static int
slouken@7759
  1514
SDL_UpdateTextureYUVPlanar(SDL_Texture * texture, const SDL_Rect * rect,
slouken@7759
  1515
                           const Uint8 *Yplane, int Ypitch,
slouken@7759
  1516
                           const Uint8 *Uplane, int Upitch,
slouken@7759
  1517
                           const Uint8 *Vplane, int Vpitch)
slouken@7759
  1518
{
slouken@7759
  1519
    SDL_Texture *native = texture->native;
slouken@7759
  1520
    SDL_Rect full_rect;
slouken@7759
  1521
slouken@7759
  1522
    if (SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch) < 0) {
slouken@7759
  1523
        return -1;
slouken@7759
  1524
    }
slouken@7759
  1525
slouken@7759
  1526
    full_rect.x = 0;
slouken@7759
  1527
    full_rect.y = 0;
slouken@7759
  1528
    full_rect.w = texture->w;
slouken@7759
  1529
    full_rect.h = texture->h;
slouken@7759
  1530
    rect = &full_rect;
slouken@7759
  1531
icculus@10650
  1532
    if (!rect->w || !rect->h) {
icculus@10650
  1533
        return 0;  /* nothing to do. */
icculus@10650
  1534
    }
icculus@10650
  1535
slouken@7759
  1536
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@7759
  1537
        /* We can lock the texture and copy to it */
icculus@10650
  1538
        void *native_pixels = NULL;
icculus@10650
  1539
        int native_pitch = 0;
slouken@7759
  1540
slouken@7759
  1541
        if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
slouken@7759
  1542
            return -1;
slouken@7759
  1543
        }
slouken@7759
  1544
        SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
slouken@7759
  1545
                            rect->w, rect->h, native_pixels, native_pitch);
slouken@7759
  1546
        SDL_UnlockTexture(native);
slouken@7759
  1547
    } else {
slouken@7759
  1548
        /* Use a temporary buffer for updating */
icculus@10650
  1549
        const int temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
icculus@10650
  1550
        const size_t alloclen = rect->h * temp_pitch;
icculus@10650
  1551
        if (alloclen > 0) {
icculus@10650
  1552
            void *temp_pixels = SDL_malloc(alloclen);
icculus@10650
  1553
            if (!temp_pixels) {
icculus@10650
  1554
                return SDL_OutOfMemory();
icculus@10650
  1555
            }
icculus@10650
  1556
            SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
icculus@10650
  1557
                                rect->w, rect->h, temp_pixels, temp_pitch);
icculus@10650
  1558
            SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
icculus@10650
  1559
            SDL_free(temp_pixels);
slouken@7759
  1560
        }
slouken@7759
  1561
    }
slouken@7759
  1562
    return 0;
slouken@7759
  1563
}
slouken@7759
  1564
slouken@7759
  1565
int SDL_UpdateYUVTexture(SDL_Texture * texture, const SDL_Rect * rect,
slouken@7759
  1566
                         const Uint8 *Yplane, int Ypitch,
slouken@7759
  1567
                         const Uint8 *Uplane, int Upitch,
slouken@7759
  1568
                         const Uint8 *Vplane, int Vpitch)
slouken@7759
  1569
{
slouken@7759
  1570
    SDL_Renderer *renderer;
slouken@7759
  1571
    SDL_Rect full_rect;
slouken@7759
  1572
slouken@7759
  1573
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@7759
  1574
slouken@7759
  1575
    if (!Yplane) {
slouken@7759
  1576
        return SDL_InvalidParamError("Yplane");
slouken@7759
  1577
    }
slouken@7759
  1578
    if (!Ypitch) {
slouken@7759
  1579
        return SDL_InvalidParamError("Ypitch");
slouken@7759
  1580
    }
slouken@7759
  1581
    if (!Uplane) {
slouken@7759
  1582
        return SDL_InvalidParamError("Uplane");
slouken@7759
  1583
    }
slouken@7759
  1584
    if (!Upitch) {
slouken@7759
  1585
        return SDL_InvalidParamError("Upitch");
slouken@7759
  1586
    }
slouken@7759
  1587
    if (!Vplane) {
slouken@7759
  1588
        return SDL_InvalidParamError("Vplane");
slouken@7759
  1589
    }
slouken@7759
  1590
    if (!Vpitch) {
slouken@7759
  1591
        return SDL_InvalidParamError("Vpitch");
slouken@7759
  1592
    }
slouken@7759
  1593
slouken@7759
  1594
    if (texture->format != SDL_PIXELFORMAT_YV12 &&
slouken@7759
  1595
        texture->format != SDL_PIXELFORMAT_IYUV) {
slouken@7759
  1596
        return SDL_SetError("Texture format must by YV12 or IYUV");
slouken@7759
  1597
    }
slouken@7759
  1598
slouken@7759
  1599
    if (!rect) {
slouken@7759
  1600
        full_rect.x = 0;
slouken@7759
  1601
        full_rect.y = 0;
slouken@7759
  1602
        full_rect.w = texture->w;
slouken@7759
  1603
        full_rect.h = texture->h;
slouken@7759
  1604
        rect = &full_rect;
slouken@7759
  1605
    }
slouken@7759
  1606
icculus@10650
  1607
    if (!rect->w || !rect->h) {
icculus@10650
  1608
        return 0;  /* nothing to do. */
icculus@10650
  1609
    }
icculus@10650
  1610
slouken@7759
  1611
    if (texture->yuv) {
slouken@7759
  1612
        return SDL_UpdateTextureYUVPlanar(texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
slouken@7759
  1613
    } else {
slouken@7759
  1614
        SDL_assert(!texture->native);
slouken@7759
  1615
        renderer = texture->renderer;
slouken@7759
  1616
        SDL_assert(renderer->UpdateTextureYUV);
slouken@9084
  1617
        if (renderer->UpdateTextureYUV) {
icculus@12211
  1618
            if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
icculus@12211
  1619
                return -1;
icculus@12211
  1620
            }
slouken@9084
  1621
            return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
slouken@9084
  1622
        } else {
slouken@9084
  1623
            return SDL_Unsupported();
slouken@9084
  1624
        }
slouken@9084
  1625
    }
slouken@7759
  1626
}
slouken@7759
  1627
slouken@7759
  1628
static int
slouken@5156
  1629
SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5156
  1630
                   void **pixels, int *pitch)
slouken@5156
  1631
{
slouken@5156
  1632
    return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch);
slouken@5156
  1633
}
slouken@5156
  1634
slouken@5156
  1635
static int
slouken@5156
  1636
SDL_LockTextureNative(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5156
  1637
                      void **pixels, int *pitch)
slouken@5156
  1638
{
slouken@5156
  1639
    texture->locked_rect = *rect;
slouken@5156
  1640
    *pixels = (void *) ((Uint8 *) texture->pixels +
slouken@5156
  1641
                        rect->y * texture->pitch +
slouken@5156
  1642
                        rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@5156
  1643
    *pitch = texture->pitch;
slouken@5156
  1644
    return 0;
slouken@5154
  1645
}
slouken@5154
  1646
slouken@5154
  1647
int
slouken@5156
  1648
SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect,
slouken@5154
  1649
                void **pixels, int *pitch)
slouken@5154
  1650
{
slouken@5154
  1651
    SDL_Rect full_rect;
slouken@5154
  1652
slouken@5154
  1653
    CHECK_TEXTURE_MAGIC(texture, -1);
slouken@5154
  1654
slouken@5154
  1655
    if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
icculus@7037
  1656
        return SDL_SetError("SDL_LockTexture(): texture must be streaming");
slouken@5154
  1657
    }
slouken@5156
  1658
slouken@5154
  1659
    if (!rect) {
slouken@5154
  1660
        full_rect.x = 0;
slouken@5154
  1661
        full_rect.y = 0;
slouken@5154
  1662
        full_rect.w = texture->w;
slouken@5154
  1663
        full_rect.h = texture->h;
slouken@5154
  1664
        rect = &full_rect;
slouken@5154
  1665
    }
slouken@5156
  1666
slouken@5156
  1667
    if (texture->yuv) {
icculus@12211
  1668
        if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
icculus@12211
  1669
            return -1;
icculus@12211
  1670
        }
slouken@5156
  1671
        return SDL_LockTextureYUV(texture, rect, pixels, pitch);
slouken@5156
  1672
    } else if (texture->native) {
icculus@12211
  1673
        /* Calls a real SDL_LockTexture/SDL_UnlockTexture on unlock, flushing then. */
slouken@5156
  1674
        return SDL_LockTextureNative(texture, rect, pixels, pitch);
slouken@5156
  1675
    } else {
icculus@12211
  1676
        SDL_Renderer *renderer = texture->renderer;
icculus@12211
  1677
        if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
icculus@12211
  1678
            return -1;
icculus@12211
  1679
        }
slouken@5156
  1680
        return renderer->LockTexture(renderer, texture, rect, pixels, pitch);
slouken@5156
  1681
    }
slouken@5156
  1682
}
slouken@5156
  1683
slouken@5156
  1684
static void
slouken@5156
  1685
SDL_UnlockTextureYUV(SDL_Texture * texture)
slouken@5156
  1686
{
slouken@5156
  1687
    SDL_Texture *native = texture->native;
icculus@8649
  1688
    void *native_pixels = NULL;
icculus@8649
  1689
    int native_pitch = 0;
slouken@5156
  1690
    SDL_Rect rect;
slouken@5156
  1691
slouken@5156
  1692
    rect.x = 0;
slouken@5156
  1693
    rect.y = 0;
slouken@5156
  1694
    rect.w = texture->w;
slouken@5156
  1695
    rect.h = texture->h;
slouken@5156
  1696
slouken@5156
  1697
    if (SDL_LockTexture(native, &rect, &native_pixels, &native_pitch) < 0) {
slouken@5156
  1698
        return;
slouken@5156
  1699
    }
slouken@5156
  1700
    SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format,
slouken@5156
  1701
                        rect.w, rect.h, native_pixels, native_pitch);
slouken@5156
  1702
    SDL_UnlockTexture(native);
slouken@5156
  1703
}
slouken@5156
  1704
slouken@6044
  1705
static void
slouken@5156
  1706
SDL_UnlockTextureNative(SDL_Texture * texture)
slouken@5156
  1707
{
slouken@5156
  1708
    SDL_Texture *native = texture->native;
icculus@8649
  1709
    void *native_pixels = NULL;
icculus@8649
  1710
    int native_pitch = 0;
slouken@5156
  1711
    const SDL_Rect *rect = &texture->locked_rect;
slouken@5156
  1712
    const void* pixels = (void *) ((Uint8 *) texture->pixels +
slouken@5156
  1713
                        rect->y * texture->pitch +
slouken@5156
  1714
                        rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@5156
  1715
    int pitch = texture->pitch;
slouken@5156
  1716
slouken@5156
  1717
    if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
slouken@5156
  1718
        return;
slouken@5156
  1719
    }
slouken@5156
  1720
    SDL_ConvertPixels(rect->w, rect->h,
slouken@5156
  1721
                      texture->format, pixels, pitch,
slouken@5156
  1722
                      native->format, native_pixels, native_pitch);
slouken@5156
  1723
    SDL_UnlockTexture(native);
slouken@5154
  1724
}
slouken@5154
  1725
slouken@5154
  1726
void
slouken@5154
  1727
SDL_UnlockTexture(SDL_Texture * texture)
slouken@5154
  1728
{
slouken@5154
  1729
    CHECK_TEXTURE_MAGIC(texture, );
slouken@5154
  1730
slouken@5154
  1731
    if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
slouken@5154
  1732
        return;
slouken@5154
  1733
    }
slouken@5156
  1734
    if (texture->yuv) {
slouken@5156
  1735
        SDL_UnlockTextureYUV(texture);
slouken@5156
  1736
    } else if (texture->native) {
slouken@5156
  1737
        SDL_UnlockTextureNative(texture);
slouken@5156
  1738
    } else {
icculus@12211
  1739
        SDL_Renderer *renderer = texture->renderer;
slouken@5156
  1740
        renderer->UnlockTexture(renderer, texture);
slouken@5154
  1741
    }
slouken@5154
  1742
}
slouken@5154
  1743
slouken@6246
  1744
SDL_bool
slouken@6246
  1745
SDL_RenderTargetSupported(SDL_Renderer *renderer)
slouken@6246
  1746
{
slouken@6247
  1747
    if (!renderer || !renderer->SetRenderTarget) {
slouken@6246
  1748
        return SDL_FALSE;
slouken@6246
  1749
    }
slouken@6246
  1750
    return (renderer->info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
slouken@6246
  1751
}
slouken@6246
  1752
slouken@6246
  1753
int
slouken@6247
  1754
SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
slouken@6246
  1755
{
slouken@6246
  1756
    if (!SDL_RenderTargetSupported(renderer)) {
icculus@7037
  1757
        return SDL_Unsupported();
slouken@6246
  1758
    }
slouken@6246
  1759
    if (texture == renderer->target) {
slouken@6246
  1760
        /* Nothing to do! */
slouken@6246
  1761
        return 0;
slouken@6246
  1762
    }
slouken@6246
  1763
icculus@12211
  1764
    FlushRenderCommands(renderer);  /* time to send everything to the GPU! */
icculus@12211
  1765
slouken@6246
  1766
    /* texture == NULL is valid and means reset the target to the window */
slouken@6246
  1767
    if (texture) {
slouken@6246
  1768
        CHECK_TEXTURE_MAGIC(texture, -1);
slouken@6246
  1769
        if (renderer != texture->renderer) {
icculus@7037
  1770
            return SDL_SetError("Texture was not created with this renderer");
slouken@6246
  1771
        }
gabomdq@6337
  1772
        if (texture->access != SDL_TEXTUREACCESS_TARGET) {
icculus@7037
  1773
            return SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET");
slouken@6246
  1774
        }
slouken@6246
  1775
        if (texture->native) {
slouken@6246
  1776
            /* Always render to the native texture */
slouken@6246
  1777
            texture = texture->native;
slouken@6246
  1778
        }
slouken@6246
  1779
    }
slouken@6246
  1780
slouken@12021
  1781
    SDL_LockMutex(renderer->target_mutex);
slouken@12021
  1782
slouken@6246
  1783
    if (texture && !renderer->target) {
slouken@6246
  1784
        /* Make a backup of the viewport */
slouken@6246
  1785
        renderer->viewport_backup = renderer->viewport;
slouken@7141
  1786
        renderer->clip_rect_backup = renderer->clip_rect;
jorgenpt@8728
  1787
        renderer->clipping_enabled_backup = renderer->clipping_enabled;
slouken@6528
  1788
        renderer->scale_backup = renderer->scale;
slouken@6581
  1789
        renderer->logical_w_backup = renderer->logical_w;
slouken@6581
  1790
        renderer->logical_h_backup = renderer->logical_h;
slouken@6246
  1791
    }
slouken@6246
  1792
    renderer->target = texture;
slouken@6246
  1793
slouken@6247
  1794
    if (renderer->SetRenderTarget(renderer, texture) < 0) {
slouken@12021
  1795
        SDL_UnlockMutex(renderer->target_mutex);
slouken@6246
  1796
        return -1;
slouken@6246
  1797
    }
slouken@6246
  1798
slouken@6246
  1799
    if (texture) {
slouken@6528
  1800
        renderer->viewport.x = 0;
slouken@6528
  1801
        renderer->viewport.y = 0;
slouken@6528
  1802
        renderer->viewport.w = texture->w;
slouken@6528
  1803
        renderer->viewport.h = texture->h;
slouken@10428
  1804
        SDL_zero(renderer->clip_rect);
slouken@10428
  1805
        renderer->clipping_enabled = SDL_FALSE;
slouken@6528
  1806
        renderer->scale.x = 1.0f;
slouken@6528
  1807
        renderer->scale.y = 1.0f;
slouken@7339
  1808
        renderer->logical_w = texture->w;
slouken@7339
  1809
        renderer->logical_h = texture->h;
slouken@6246
  1810
    } else {
slouken@6528
  1811
        renderer->viewport = renderer->viewport_backup;
slouken@7141
  1812
        renderer->clip_rect = renderer->clip_rect_backup;
jorgenpt@8728
  1813
        renderer->clipping_enabled = renderer->clipping_enabled_backup;
slouken@6528
  1814
        renderer->scale = renderer->scale_backup;
slouken@6581
  1815
        renderer->logical_w = renderer->logical_w_backup;
slouken@6581
  1816
        renderer->logical_h = renderer->logical_h_backup;
slouken@6246
  1817
    }
slouken@12021
  1818
slouken@12021
  1819
    SDL_UnlockMutex(renderer->target_mutex);
slouken@12021
  1820
icculus@12214
  1821
    if (QueueCmdSetViewport(renderer) < 0) {
slouken@6246
  1822
        return -1;
slouken@6246
  1823
    }
icculus@12214
  1824
    if (QueueCmdSetClipRect(renderer) < 0) {
slouken@7141
  1825
        return -1;
slouken@7141
  1826
    }
slouken@6246
  1827
slouken@6246
  1828
    /* All set! */
icculus@12236
  1829
    return FlushRenderCommandsIfNotBatching(renderer);
slouken@6246
  1830
}
slouken@6246
  1831
slouken@6578
  1832
SDL_Texture *
slouken@6578
  1833
SDL_GetRenderTarget(SDL_Renderer *renderer)
slouken@6578
  1834
{
slouken@6578
  1835
    return renderer->target;
slouken@6578
  1836
}
slouken@6578
  1837
slouken@6530
  1838
static int
slouken@6530
  1839
UpdateLogicalSize(SDL_Renderer *renderer)
slouken@6530
  1840
{
icculus@8654
  1841
    int w = 1, h = 1;
slouken@6530
  1842
    float want_aspect;
slouken@6530
  1843
    float real_aspect;
slouken@6530
  1844
    float scale;
slouken@6530
  1845
    SDL_Rect viewport;
ewing@11072
  1846
    /* 0 is for letterbox, 1 is for overscan */
ewing@11072
  1847
    int scale_policy = 0;
slouken@11771
  1848
    const char *hint;
slouken@6530
  1849
slouken@10532
  1850
    if (!renderer->logical_w || !renderer->logical_h) {
slouken@10532
  1851
        return 0;
slouken@10532
  1852
    }
slouken@7239
  1853
    if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) {
slouken@7239
  1854
        return -1;
slouken@6530
  1855
    }
slouken@6530
  1856
slouken@11771
  1857
    hint = SDL_GetHint(SDL_HINT_RENDER_LOGICAL_SIZE_MODE);
slouken@11771
  1858
    if (hint && (*hint == '1' || SDL_strcasecmp(hint, "overscan") == 0))  {
sezeroz@11960
  1859
#if SDL_VIDEO_RENDER_D3D
slouken@11771
  1860
        SDL_bool overscan_supported = SDL_TRUE;
slouken@11771
  1861
        /* Unfortunately, Direct3D 9 doesn't support negative viewport numbers
slouken@11771
  1862
           which the overscan implementation relies on.
ewing@11076
  1863
        */
slouken@11771
  1864
        if (SDL_strcasecmp(SDL_GetCurrentVideoDriver(), "direct3d") == 0) {
slouken@11771
  1865
            overscan_supported = SDL_FALSE;
slouken@11771
  1866
        }
slouken@11771
  1867
        if (overscan_supported) {
ewing@11076
  1868
            scale_policy = 1;
ewing@11076
  1869
        }
sezeroz@11960
  1870
#else
sezeroz@11960
  1871
        scale_policy = 1;
sezeroz@11960
  1872
#endif
ewing@11072
  1873
    }
slouken@11771
  1874
slouken@6530
  1875
    want_aspect = (float)renderer->logical_w / renderer->logical_h;
slouken@6530
  1876
    real_aspect = (float)w / h;
slouken@6530
  1877
slouken@6530
  1878
    /* Clear the scale because we're setting viewport in output coordinates */
slouken@6530
  1879
    SDL_RenderSetScale(renderer, 1.0f, 1.0f);
slouken@6530
  1880
flibitijibibo@10039
  1881
    if (renderer->integer_scale) {
flibitijibibo@10039
  1882
        if (want_aspect > real_aspect) {
philipp@10054
  1883
            scale = (float)(w / renderer->logical_w);
flibitijibibo@10039
  1884
        } else {
philipp@10054
  1885
            scale = (float)(h / renderer->logical_h);
flibitijibibo@10039
  1886
        }
flibitijibibo@10039
  1887
        viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
flibitijibibo@10039
  1888
        viewport.x = (w - viewport.w) / 2;
flibitijibibo@10039
  1889
        viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
flibitijibibo@10039
  1890
        viewport.y = (h - viewport.h) / 2;
flibitijibibo@10039
  1891
flibitijibibo@10039
  1892
        SDL_RenderSetViewport(renderer, &viewport);
flibitijibibo@10039
  1893
    } else if (SDL_fabs(want_aspect-real_aspect) < 0.0001) {
slouken@6530
  1894
        /* The aspect ratios are the same, just scale appropriately */
slouken@6530
  1895
        scale = (float)w / renderer->logical_w;
slouken@6530
  1896
        SDL_RenderSetViewport(renderer, NULL);
slouken@6530
  1897
    } else if (want_aspect > real_aspect) {
ewing@11072
  1898
        if (scale_policy == 1) {
ewing@11072
  1899
            /* We want a wider aspect ratio than is available - 
ewing@11072
  1900
             zoom so logical height matches the real height 
ewing@11072
  1901
             and the width will grow off the screen 
ewing@11072
  1902
             */
ewing@11072
  1903
            scale = (float)h / renderer->logical_h;
ewing@11072
  1904
            viewport.y = 0;
ewing@11072
  1905
            viewport.h = h;
ewing@11072
  1906
            viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
ewing@11072
  1907
            viewport.x = (w - viewport.w) / 2;
ewing@11072
  1908
            SDL_RenderSetViewport(renderer, &viewport);
ewing@11072
  1909
        } else {
ewing@11072
  1910
            /* We want a wider aspect ratio than is available - letterbox it */
ewing@11072
  1911
            scale = (float)w / renderer->logical_w;
ewing@11072
  1912
            viewport.x = 0;
ewing@11072
  1913
            viewport.w = w;
ewing@11072
  1914
            viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
ewing@11072
  1915
            viewport.y = (h - viewport.h) / 2;
ewing@11072
  1916
            SDL_RenderSetViewport(renderer, &viewport);
ewing@11072
  1917
        }
slouken@6530
  1918
    } else {
ewing@11072
  1919
        if (scale_policy == 1) {
ewing@11072
  1920
            /* We want a narrower aspect ratio than is available -
ewing@11072
  1921
             zoom so logical width matches the real width
ewing@11072
  1922
             and the height will grow off the screen
ewing@11072
  1923
             */
ewing@11072
  1924
            scale = (float)w / renderer->logical_w;
ewing@11072
  1925
            viewport.x = 0;
ewing@11072
  1926
            viewport.w = w;
ewing@11072
  1927
            viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
ewing@11072
  1928
            viewport.y = (h - viewport.h) / 2;
ewing@11072
  1929
            SDL_RenderSetViewport(renderer, &viewport);
ewing@11072
  1930
        } else {
ewing@11072
  1931
            /* We want a narrower aspect ratio than is available - use side-bars */
ewing@11072
  1932
             scale = (float)h / renderer->logical_h;
ewing@11072
  1933
             viewport.y = 0;
ewing@11072
  1934
             viewport.h = h;
ewing@11072
  1935
             viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
ewing@11072
  1936
             viewport.x = (w - viewport.w) / 2;
ewing@11072
  1937
             SDL_RenderSetViewport(renderer, &viewport);
ewing@11072
  1938
        }
slouken@6530
  1939
    }
slouken@6530
  1940
slouken@6530
  1941
    /* Set the new scale */
slouken@6530
  1942
    SDL_RenderSetScale(renderer, scale, scale);
slouken@6531
  1943
slouken@6531
  1944
    return 0;
slouken@6530
  1945
}
slouken@6530
  1946
slouken@6530
  1947
int
slouken@6530
  1948
SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h)
slouken@6530
  1949
{
slouken@6530
  1950
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@6530
  1951
slouken@6530
  1952
    if (!w || !h) {
slouken@6530
  1953
        /* Clear any previous logical resolution */
slouken@6530
  1954
        renderer->logical_w = 0;
slouken@6530
  1955
        renderer->logical_h = 0;
slouken@6530
  1956
        SDL_RenderSetViewport(renderer, NULL);
slouken@6530
  1957
        SDL_RenderSetScale(renderer, 1.0f, 1.0f);
slouken@6530
  1958
        return 0;
slouken@6530
  1959
    }
slouken@6530
  1960
slouken@6530
  1961
    renderer->logical_w = w;
slouken@6530
  1962
    renderer->logical_h = h;
slouken@6530
  1963
slouken@6530
  1964
    return UpdateLogicalSize(renderer);
slouken@6530
  1965
}
slouken@6530
  1966
slouken@6530
  1967
void
slouken@6530
  1968
SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h)
slouken@6530
  1969
{
slouken@6530
  1970
    CHECK_RENDERER_MAGIC(renderer, );
slouken@6530
  1971
slouken@6530
  1972
    if (w) {
slouken@6530
  1973
        *w = renderer->logical_w;
slouken@6530
  1974
    }
slouken@6530
  1975
    if (h) {
slouken@6530
  1976
        *h = renderer->logical_h;
slouken@6530
  1977
    }
slouken@6530
  1978
}
slouken@6530
  1979
slouken@5297
  1980
int
flibitijibibo@10039
  1981
SDL_RenderSetIntegerScale(SDL_Renderer * renderer, SDL_bool enable)
flibitijibibo@10039
  1982
{
flibitijibibo@10039
  1983
    CHECK_RENDERER_MAGIC(renderer, -1);
flibitijibibo@10039
  1984
flibitijibibo@10039
  1985
    renderer->integer_scale = enable;
flibitijibibo@10039
  1986
flibitijibibo@10039
  1987
    return UpdateLogicalSize(renderer);
flibitijibibo@10039
  1988
}
flibitijibibo@10039
  1989
flibitijibibo@10039
  1990
SDL_bool
flibitijibibo@10039
  1991
SDLCALL SDL_RenderGetIntegerScale(SDL_Renderer * renderer)
flibitijibibo@10039
  1992
{
flibitijibibo@10039
  1993
    CHECK_RENDERER_MAGIC(renderer, SDL_FALSE);
flibitijibibo@10039
  1994
flibitijibibo@10039
  1995
    return renderer->integer_scale;
flibitijibibo@10039
  1996
}
flibitijibibo@10039
  1997
flibitijibibo@10039
  1998
int
slouken@5297
  1999
SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
slouken@5297
  2000
{
icculus@12236
  2001
    int retval;
slouken@5297
  2002
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5297
  2003
slouken@5297
  2004
    if (rect) {
slouken@6528
  2005
        renderer->viewport.x = (int)SDL_floor(rect->x * renderer->scale.x);
slouken@6528
  2006
        renderer->viewport.y = (int)SDL_floor(rect->y * renderer->scale.y);
slouken@6528
  2007
        renderer->viewport.w = (int)SDL_ceil(rect->w * renderer->scale.x);
slouken@6528
  2008
        renderer->viewport.h = (int)SDL_ceil(rect->h * renderer->scale.y);
slouken@5297
  2009
    } else {
slouken@5297
  2010
        renderer->viewport.x = 0;
slouken@5297
  2011
        renderer->viewport.y = 0;
slouken@7239
  2012
        if (SDL_GetRendererOutputSize(renderer, &renderer->viewport.w, &renderer->viewport.h) < 0) {
slouken@7239
  2013
            return -1;
slouken@5297
  2014
        }
slouken@5297
  2015
    }
icculus@12236
  2016
    retval = QueueCmdSetViewport(renderer);
icculus@12236
  2017
    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
slouken@5297
  2018
}
slouken@5297
  2019
slouken@5224
  2020
void
slouken@5297
  2021
SDL_RenderGetViewport(SDL_Renderer * renderer, SDL_Rect * rect)
slouken@5224
  2022
{
slouken@5224
  2023
    CHECK_RENDERER_MAGIC(renderer, );
slouken@5224
  2024
slouken@6528
  2025
    if (rect) {
slouken@6528
  2026
        rect->x = (int)(renderer->viewport.x / renderer->scale.x);
slouken@6528
  2027
        rect->y = (int)(renderer->viewport.y / renderer->scale.y);
slouken@6528
  2028
        rect->w = (int)(renderer->viewport.w / renderer->scale.x);
slouken@6528
  2029
        rect->h = (int)(renderer->viewport.h / renderer->scale.y);
slouken@6528
  2030
    }
slouken@6528
  2031
}
slouken@6528
  2032
slouken@6528
  2033
int
slouken@7141
  2034
SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
slouken@7141
  2035
{
icculus@12236
  2036
    int retval;
philipp@7143
  2037
    CHECK_RENDERER_MAGIC(renderer, -1)
slouken@7141
  2038
slouken@7141
  2039
    if (rect) {
jorgenpt@8728
  2040
        renderer->clipping_enabled = SDL_TRUE;
slouken@7141
  2041
        renderer->clip_rect.x = (int)SDL_floor(rect->x * renderer->scale.x);
slouken@7141
  2042
        renderer->clip_rect.y = (int)SDL_floor(rect->y * renderer->scale.y);
slouken@7141
  2043
        renderer->clip_rect.w = (int)SDL_ceil(rect->w * renderer->scale.x);
slouken@7141
  2044
        renderer->clip_rect.h = (int)SDL_ceil(rect->h * renderer->scale.y);
slouken@7141
  2045
    } else {
jorgenpt@8728
  2046
        renderer->clipping_enabled = SDL_FALSE;
slouken@7141
  2047
        SDL_zero(renderer->clip_rect);
slouken@7141
  2048
    }
icculus@12236
  2049
icculus@12236
  2050
    retval = QueueCmdSetClipRect(renderer);
icculus@12236
  2051
    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
slouken@7141
  2052
}
slouken@7141
  2053
slouken@7141
  2054
void
slouken@7141
  2055
SDL_RenderGetClipRect(SDL_Renderer * renderer, SDL_Rect * rect)
slouken@7141
  2056
{
slouken@7141
  2057
    CHECK_RENDERER_MAGIC(renderer, )
slouken@7141
  2058
slouken@7141
  2059
    if (rect) {
slouken@7141
  2060
        rect->x = (int)(renderer->clip_rect.x / renderer->scale.x);
slouken@7141
  2061
        rect->y = (int)(renderer->clip_rect.y / renderer->scale.y);
slouken@7141
  2062
        rect->w = (int)(renderer->clip_rect.w / renderer->scale.x);
slouken@7141
  2063
        rect->h = (int)(renderer->clip_rect.h / renderer->scale.y);
slouken@7141
  2064
    }
slouken@7141
  2065
}
slouken@7141
  2066
jorgenpt@8728
  2067
SDL_bool
jorgenpt@8728
  2068
SDL_RenderIsClipEnabled(SDL_Renderer * renderer)
jorgenpt@8728
  2069
{
jorgenpt@8728
  2070
    CHECK_RENDERER_MAGIC(renderer, SDL_FALSE)
jorgenpt@8728
  2071
    return renderer->clipping_enabled;
jorgenpt@8728
  2072
}
jorgenpt@8728
  2073
slouken@7141
  2074
int
slouken@6528
  2075
SDL_RenderSetScale(SDL_Renderer * renderer, float scaleX, float scaleY)
slouken@6528
  2076
{
slouken@6528
  2077
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@6528
  2078
slouken@6528
  2079
    renderer->scale.x = scaleX;
slouken@6528
  2080
    renderer->scale.y = scaleY;
slouken@6528
  2081
    return 0;
slouken@6528
  2082
}
slouken@6528
  2083
slouken@6528
  2084
void
slouken@6528
  2085
SDL_RenderGetScale(SDL_Renderer * renderer, float *scaleX, float *scaleY)
slouken@6528
  2086
{
slouken@6528
  2087
    CHECK_RENDERER_MAGIC(renderer, );
slouken@6528
  2088
slouken@6528
  2089
    if (scaleX) {
slouken@6528
  2090
        *scaleX = renderer->scale.x;
slouken@6528
  2091
    }
slouken@6528
  2092
    if (scaleY) {
slouken@6528
  2093
        *scaleY = renderer->scale.y;
slouken@6528
  2094
    }
slouken@5224
  2095
}
slouken@5224
  2096
slouken@5154
  2097
int
slouken@5154
  2098
SDL_SetRenderDrawColor(SDL_Renderer * renderer,
slouken@5154
  2099
                       Uint8 r, Uint8 g, Uint8 b, Uint8 a)
slouken@5154
  2100
{
slouken@5154
  2101
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  2102
slouken@5154
  2103
    renderer->r = r;
slouken@5154
  2104
    renderer->g = g;
slouken@5154
  2105
    renderer->b = b;
slouken@5154
  2106
    renderer->a = a;
slouken@5154
  2107
    return 0;
slouken@5154
  2108
}
slouken@5154
  2109
slouken@5154
  2110
int
slouken@5154
  2111
SDL_GetRenderDrawColor(SDL_Renderer * renderer,
slouken@5154
  2112
                       Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
slouken@5154
  2113
{
slouken@5154
  2114
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  2115
slouken@5154
  2116
    if (r) {
slouken@5154
  2117
        *r = renderer->r;
slouken@5154
  2118
    }
slouken@5154
  2119
    if (g) {
slouken@5154
  2120
        *g = renderer->g;
slouken@5154
  2121
    }
slouken@5154
  2122
    if (b) {
slouken@5154
  2123
        *b = renderer->b;
slouken@5154
  2124
    }
slouken@5154
  2125
    if (a) {
slouken@5154
  2126
        *a = renderer->a;
slouken@5154
  2127
    }
slouken@5154
  2128
    return 0;
slouken@5154
  2129
}
slouken@5154
  2130
slouken@5154
  2131
int
slouken@5154
  2132
SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
slouken@5154
  2133
{
slouken@5154
  2134
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  2135
slouken@11282
  2136
    if (!IsSupportedBlendMode(renderer, blendMode)) {
slouken@11282
  2137
        return SDL_Unsupported();
slouken@11282
  2138
    }
slouken@5154
  2139
    renderer->blendMode = blendMode;
slouken@5154
  2140
    return 0;
slouken@5154
  2141
}
slouken@5154
  2142
slouken@5154
  2143
int
slouken@5154
  2144
SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
slouken@5154
  2145
{
slouken@5154
  2146
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  2147
slouken@5154
  2148
    *blendMode = renderer->blendMode;
slouken@5154
  2149
    return 0;
slouken@5154
  2150
}
slouken@5154
  2151
slouken@5154
  2152
int
slouken@5154
  2153
SDL_RenderClear(SDL_Renderer * renderer)
slouken@5154
  2154
{
icculus@12236
  2155
    int retval;
slouken@5154
  2156
    CHECK_RENDERER_MAGIC(renderer, -1);
icculus@12236
  2157
    retval = QueueCmdClear(renderer);
icculus@12236
  2158
    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
slouken@5154
  2159
}
slouken@5154
  2160
icculus@12352
  2161
icculus@12352
  2162
/* !!! FIXME: delete all the duplicate code for the integer versions in 2.1,
icculus@12352
  2163
   !!! FIXME:  making the floating point versions the only available APIs. */
icculus@12352
  2164
slouken@5154
  2165
int
slouken@5154
  2166
SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
slouken@5154
  2167
{
sezeroz@12383
  2168
    SDL_FPoint fpoint;
sezeroz@12383
  2169
    fpoint.x = (float) x;
sezeroz@12383
  2170
    fpoint.y = (float) y;
icculus@12352
  2171
    return SDL_RenderDrawPointsF(renderer, &fpoint, 1);
icculus@12352
  2172
}
icculus@12352
  2173
icculus@12352
  2174
int
icculus@12352
  2175
SDL_RenderDrawPointF(SDL_Renderer * renderer, float x, float y)
icculus@12352
  2176
{
sezeroz@12383
  2177
    SDL_FPoint fpoint;
sezeroz@12383
  2178
    fpoint.x = x;
sezeroz@12383
  2179
    fpoint.y = y;
icculus@12352
  2180
    return SDL_RenderDrawPointsF(renderer, &fpoint, 1);
slouken@5154
  2181
}
slouken@5154
  2182
slouken@6528
  2183
static int
slouken@6528
  2184
RenderDrawPointsWithRects(SDL_Renderer * renderer,
icculus@12352
  2185
                          const SDL_Point * points, const int count)
slouken@6528
  2186
{
icculus@12236
  2187
    int retval = -1;
icculus@12349
  2188
    SDL_bool isstack;
icculus@12352
  2189
    SDL_FRect *frects = SDL_small_alloc(SDL_FRect, count, &isstack);
icculus@12352
  2190
    int i;
icculus@12352
  2191
slouken@6528
  2192
    if (!frects) {
icculus@7037
  2193
        return SDL_OutOfMemory();
slouken@6528
  2194
    }
icculus@12352
  2195
slouken@6528
  2196
    for (i = 0; i < count; ++i) {
slouken@6528
  2197
        frects[i].x = points[i].x * renderer->scale.x;
slouken@6528
  2198
        frects[i].y = points[i].y * renderer->scale.y;
slouken@6528
  2199
        frects[i].w = renderer->scale.x;
slouken@6528
  2200
        frects[i].h = renderer->scale.y;
slouken@6528
  2201
    }
slouken@6528
  2202
icculus@12236
  2203
    retval = QueueCmdFillRects(renderer, frects, count);
slouken@6528
  2204
icculus@12349
  2205
    SDL_small_free(frects, isstack);
slouken@6528
  2206
icculus@12236
  2207
    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
slouken@6528
  2208
}
slouken@6528
  2209
slouken@5154
  2210
int
slouken@5154
  2211
SDL_RenderDrawPoints(SDL_Renderer * renderer,
slouken@5154
  2212
                     const SDL_Point * points, int count)
slouken@5154
  2213
{
slouken@6528
  2214
    SDL_FPoint *fpoints;
slouken@6528
  2215
    int i;
icculus@12236
  2216
    int retval;
icculus@12349
  2217
    SDL_bool isstack;
slouken@6528
  2218
slouken@5154
  2219
    CHECK_RENDERER_MAGIC(renderer, -1);
slouken@5154
  2220
slouken@5154
  2221
    if (!points) {
icculus@7037
  2222
        return SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
slouken@5154
  2223
    }
slouken@5154
  2224
    if (count < 1) {
slouken@5154
  2225
        return 0;
slouken@5154
  2226
    }
slouken@10440
  2227
slouken@6260
  2228
    /* Don't draw while we're hidden */
slouken@6260
  2229
    if (renderer->hidden) {
slouken@6060
  2230
        return 0;
slouken@6060
  2231
    }
slouken@6528
  2232
slouken@6528
  2233
    if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
slouken@6528
  2234
        return RenderDrawPointsWithRects(renderer, points, count);
slouken@6528
  2235
    }
slouken@6528
  2236
icculus@12349
  2237
    fpoints = SDL_small_alloc(SDL_FPoint, count, &isstack);
slouken@6528
  2238
    if (!fpoints) {
icculus@7037
  2239
        return SDL_OutOfMemory();
slouken@6528
  2240
    }
slouken@6528
  2241
    for (i = 0; i < count; ++i) {
slouken@6528
  2242
        fpoints[i].x = points[i].x * renderer->scale.x;
slouken@6528
  2243
        fpoints[i].y = points[i].y * renderer->scale.y;
slouken@6528
  2244
    }
slouken@6528
  2245
icculus@12236
  2246
    retval = QueueCmdDrawPoints(renderer, fpoints, count);
slouken@6528
  2247
icculus@12349
  2248
    SDL_small_free(fpoints, isstack);
slouken@6528
  2249
icculus@12236
  2250
    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
slouken@5154
  2251
}
slouken@5154
  2252
icculus@12352
  2253
static int
icculus@12352
  2254
RenderDrawPointsWithRectsF(SDL_Renderer * renderer,
icculus@12352
  2255
                           const SDL_FPoint * fpoints, const int count)
icculus@12352
  2256
{
icculus@12352
  2257
    int retval = -1;
icculus@12352
  2258
    SDL_bool isstack;
icculus@12352
  2259
    SDL_FRect *frects = SDL_small_alloc(SDL_FRect, count, &isstack);
icculus@12352
  2260
    int i;
icculus@12352
  2261
icculus@12352
  2262
    if (!frects) {
icculus@12352
  2263
        return SDL_OutOfMemory();
icculus@12352
  2264
    }
icculus@12352
  2265
icculus@12352
  2266
    for (i = 0; i < count; ++i) {
icculus@12352
  2267
        frects[i].x = fpoints[i].x * renderer->scale.x;
icculus@12352
  2268
        frects[i].y = fpoints[i].y * renderer->scale.y;
icculus@12352
  2269
        frects[i].w = renderer->scale.x;
icculus@12352
  2270
        frects[i].h = renderer->scale.y;
icculus@12352
  2271
    }
icculus@12352
  2272
icculus@12352
  2273
    retval = QueueCmdFillRects(renderer, frects, count);
icculus@12352
  2274
icculus@12352
  2275
    SDL_small_free(frects, isstack);
icculus@12352
  2276
icculus@12352
  2277
    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
icculus@12352
  2278
}
icculus@12352
  2279
icculus@12352
  2280
int
icculus@12352
  2281
SDL_RenderDrawPointsF(SDL_Renderer * renderer,
icculus@12352
  2282
                      const SDL_FPoint * points, int count)
icculus@12352
  2283
{
icculus@12352
  2284
    SDL_FPoint *fpoints;
icculus@12352
  2285
    int i;
icculus@12352
  2286
    int retval;
icculus@12352
  2287
    SDL_bool isstack;
icculus@12352
  2288
icculus@12352
  2289
    CHECK_RENDERER_MAGIC(renderer, -1);
icculus@12352
  2290
icculus@12352
  2291
    if (!points) {
icculus@12352
  2292
        return SDL_SetError("SDL_RenderDrawFPoints(): Passed NULL points");
icculus@12352
  2293
    }
icculus@12352
  2294
    if (count < 1) {
icculus@12352
  2295
        return 0;
icculus@12352
  2296
    }
icculus@12352
  2297
icculus@12352
  2298
    /* Don't draw while we're hidden */
icculus@12352
  2299
    if (renderer->hidden) {
icculus@12352
  2300
        return 0;
icculus@12352
  2301
    }
icculus@12352
  2302
icculus@12352
  2303
    if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
icculus@12352
  2304
        return RenderDrawPointsWithRectsF(renderer, points, count);
icculus@12352
  2305
    }
icculus@12352
  2306
icculus@12352
  2307
    fpoints = SDL_small_alloc(SDL_FPoint, count, &isstack);
icculus@12352
  2308
    if (!fpoints) {
icculus@12352
  2309
        return SDL_OutOfMemory();
icculus@12352
  2310
    }
icculus@12352
  2311
    for (i = 0; i < count; ++i) {
icculus@12352
  2312
        fpoints[i].x = points[i].x * renderer->scale.x;
icculus@12352
  2313
        fpoints[i].y = points[i].y * renderer->scale.y;
icculus@12352
  2314
    }
icculus@12352
  2315
icculus@12352
  2316
    retval = QueueCmdDrawPoints(renderer, fpoints, count);
icculus@12352
  2317
icculus@12352
  2318
    SDL_small_free(fpoints, isstack);
icculus@12352
  2319
icculus@12352
  2320
    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
icculus@12352
  2321
}
icculus@12352
  2322
slouken@5154
  2323
int
slouken@5154
  2324
SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
slouken@5154
  2325
{
sezeroz@12383
  2326
    SDL_FPoint points[2];
sezeroz@12383
  2327
    points[0].x = (float) x1;
sezeroz@12383
  2328
    points[0].y = (float) y1;
sezeroz@12383
  2329
    points[1].x = (float) x2;
sezeroz@12383
  2330
    points[1].y = (float) y2;
icculus@12352
  2331
    return SDL_RenderDrawLinesF(renderer, points, 2);
icculus@12352
  2332
}
icculus@12352
  2333
icculus@12352
  2334
int
icculus@12352
  2335
SDL_RenderDrawLineF(SDL_Renderer * renderer, float x1, float y1, float x2, float y2)
icculus@12352
  2336
{
sezeroz@12383
  2337
    SDL_FPoint points[2];
sezeroz@12383
  2338
    points[0].x = x1;
sezeroz@12383
  2339
    points[0].y = y1;
sezeroz@12383
  2340
    points[1].x = x2;
sezeroz@12383
  2341
    points[1].y = y2;
icculus@12352
  2342
    return SDL_RenderDrawLinesF(renderer, points, 2);
slouken@5154
  2343
}
slouken@5154
  2344
slouken@6528
  2345
static int
slouken@6528
  2346
RenderDrawLinesWithRects(SDL_Renderer * renderer,
icculus@12352
  2347
                     const SDL_Point * points, const int count)
slouken@6528
  2348
{
slouken@6528
  2349
    SDL_FRect *frect;
slouken@6528
  2350
    SDL_FRect *frects;
slouken@6528
  2351
    SDL_FPoint fpoints[2];
icculus@12211
  2352
    int i, nrects = 0;
icculus@12236
  2353
    int retval = 0;
icculus@12349
  2354
    SDL_bool isstack;
icculus@12349
  2355
icculus@12349
  2356
    frects = SDL_small_alloc(SDL_FRect, count-1, &isstack);
slouken@6528
  2357
    if (!frects) {
icculus@7037
  2358
        return SDL_OutOfMemory();
slouken@6528
  2359
    }
slouken@6528
  2360
slouken@6528
  2361
    for (i = 0; i < count-1; ++i) {
slouken@6528
  2362
        if (points[i].x == points[i+1].x) {
icculus@12211
  2363
            const int minY = SDL_min(points[i].y, points[i+1].y);
icculus@12211
  2364
            const int maxY = SDL_max(points[i].y, points[i+1].y);
slouken@6528
  2365
slouken@6528
  2366
            frect = &frects[nrects++];
slouken@6528
  2367
            frect->x = points[i].x * renderer->scale.x;
slouken@6528
  2368
            frect->y = minY * renderer->scale.y;
slouken@6528
  2369
            frect->w = renderer->scale.x;
slouken@6528
  2370
            frect->h = (maxY - minY + 1) * renderer->scale.y;
slouken@6528
  2371
        } else if (points[i].y == points[i+1].y) {
icculus@12211
  2372
            const int minX = SDL_min(points[i].x, points[i+1].x);
icculus@12211
  2373
            const int maxX = SDL_max(points[i].x, points[i+1].x);
slouken@6528
  2374
slouken@6528
  2375
            frect = &frects[nrects++];
slouken@6528
  2376
            frect->x = minX * renderer->scale.x;
slouken@6528
  2377
            frect->y = points[i].y * renderer->scale.y;
slouken@6528
  2378
            frect->w = (maxX - minX + 1) * renderer->scale.x;
slouken@6528
  2379
            frect->h = renderer->scale.y;
slouken@6528
  2380
        } else {
slouken@6528
  2381
            /* FIXME: We can't use a rect for this line... */
aschiffler@7073
  2382
            fpoints[0].x = points[i].x * renderer->scale.x;
aschiffler@7073
  2383
            fpoints[0].y = points[i].y * renderer->scale.y;
aschiffler@7073
  2384
            fpoints[1].x = points[i+1].x * renderer->scale.x;
aschiffler@7073
  2385
            fpoints[1].y = points[i+1].y * renderer->scale.y;
icculus@12236
  2386
            retval += QueueCmdDrawLines(renderer, fpoints, 2);
slouken@6528
  2387
        }
slouken@6528
  2388
    }
slouken@6528
  2389
icculus@12236
  2390
    retval += QueueCmdFillRects(renderer, frects, nrects);
slouken@6528
  2391
icculus@12349
  2392
    SDL_small_free(frects, isstack);
slouken@6528
  2393
icculus@12236
  2394
    if (retval < 0) {
icculus@12236
  2395
        retval = -1;
slouken@6528
  2396
    }
icculus@12236
  2397
    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
slouken@6528
  2398
}
slouken@6528
  2399
icculus@12352
  2400
static int
icculus@12352
  2401
RenderDrawLinesWithRectsF(SDL_Renderer * renderer,
icculus@12352
  2402
                          const SDL_FPoint * points, const int count)
icculus@12352
  2403
{
icculus@12352
  2404
    SDL_FRect *frect;
icculus@12352
  2405
    SDL_FRect *frects;
icculus@12352
  2406
    SDL_FPoint fpoints[2];
icculus@12352
  2407
    int i, nrects = 0;
icculus@12352
  2408
    int retval = 0;
icculus@12352
  2409
    SDL_bool isstack;
icculus@12352
  2410
icculus@12352
  2411
    frects = SDL_small_alloc(SDL_FRect, count-1, &isstack);
icculus@12352
  2412
    if (!frects) {
icculus@12352
  2413
        return SDL_OutOfMemory();
icculus@12352
  2414
    }
icculus@12352
  2415