test/testrendertarget.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 07 Dec 2017 16:08:09 -0800
changeset 11730 ac6c607e065c
parent 10737 3406a0f8b041
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Enable building the Metal renderer by default, and weak link the Metal framework so the SDL library is safe to use on older Macs
Also generate iOS versions of the Metal shaders
slouken@6232
     1
/*
slouken@10737
     2
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@6232
     3
slouken@6232
     4
  This software is provided 'as-is', without any express or implied
slouken@6232
     5
  warranty.  In no event will the authors be held liable for any damages
slouken@6232
     6
  arising from the use of this software.
slouken@6232
     7
slouken@6232
     8
  Permission is granted to anyone to use this software for any purpose,
slouken@6232
     9
  including commercial applications, and to alter it and redistribute it
slouken@6232
    10
  freely.
slouken@6232
    11
*/
slouken@6232
    12
/* Simple program:  Move N sprites around on the screen as fast as possible */
slouken@6232
    13
slouken@6232
    14
#include <stdlib.h>
slouken@6232
    15
#include <stdio.h>
slouken@6232
    16
#include <time.h>
slouken@6232
    17
icculus@9278
    18
#ifdef __EMSCRIPTEN__
icculus@9278
    19
#include <emscripten/emscripten.h>
icculus@9278
    20
#endif
icculus@9278
    21
slouken@6785
    22
#include "SDL_test_common.h"
slouken@6232
    23
slouken@6232
    24
slouken@6785
    25
static SDLTest_CommonState *state;
slouken@6232
    26
slouken@6232
    27
typedef struct {
slouken@6232
    28
    SDL_Window *window;
slouken@6232
    29
    SDL_Renderer *renderer;
slouken@6232
    30
    SDL_Texture *background;
slouken@6232
    31
    SDL_Texture *sprite;
slouken@6232
    32
    SDL_Rect sprite_rect;
slouken@6232
    33
    int scale_direction;
slouken@6232
    34
} DrawState;
slouken@6232
    35
icculus@9278
    36
DrawState *drawstates;
icculus@9278
    37
int done;
icculus@9278
    38
SDL_bool test_composite = SDL_FALSE;
icculus@9278
    39
slouken@6232
    40
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
slouken@6232
    41
static void
slouken@6232
    42
quit(int rc)
slouken@6232
    43
{
slouken@6785
    44
    SDLTest_CommonQuit(state);
slouken@6232
    45
    exit(rc);
slouken@6232
    46
}
slouken@6232
    47
slouken@6232
    48
SDL_Texture *
slouken@6232
    49
LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent)
slouken@6232
    50
{
slouken@6232
    51
    SDL_Surface *temp;
slouken@6232
    52
    SDL_Texture *texture;
slouken@6232
    53
slouken@6232
    54
    /* Load the sprite image */
slouken@6232
    55
    temp = SDL_LoadBMP(file);
slouken@6232
    56
    if (temp == NULL) {
aschiffler@7639
    57
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
slouken@6232
    58
        return NULL;
slouken@6232
    59
    }
slouken@6232
    60
slouken@6232
    61
    /* Set transparent pixel as the pixel at (0,0) */
slouken@6232
    62
    if (transparent) {
slouken@6232
    63
        if (temp->format->palette) {
slouken@6232
    64
            SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *) temp->pixels);
slouken@6232
    65
        } else {
slouken@6232
    66
            switch (temp->format->BitsPerPixel) {
slouken@6232
    67
            case 15:
slouken@6232
    68
                SDL_SetColorKey(temp, SDL_TRUE,
slouken@6232
    69
                                (*(Uint16 *) temp->pixels) & 0x00007FFF);
slouken@6232
    70
                break;
slouken@6232
    71
            case 16:
slouken@6232
    72
                SDL_SetColorKey(temp, SDL_TRUE, *(Uint16 *) temp->pixels);
slouken@6232
    73
                break;
slouken@6232
    74
            case 24:
slouken@6232
    75
                SDL_SetColorKey(temp, SDL_TRUE,
slouken@6232
    76
                                (*(Uint32 *) temp->pixels) & 0x00FFFFFF);
slouken@6232
    77
                break;
slouken@6232
    78
            case 32:
slouken@6232
    79
                SDL_SetColorKey(temp, SDL_TRUE, *(Uint32 *) temp->pixels);
slouken@6232
    80
                break;
slouken@6232
    81
            }
slouken@6232
    82
        }
slouken@6232
    83
    }
slouken@6232
    84
slouken@6232
    85
    /* Create textures from the image */
slouken@6232
    86
    texture = SDL_CreateTextureFromSurface(renderer, temp);
slouken@6232
    87
    if (!texture) {
aschiffler@7639
    88
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
slouken@6232
    89
        SDL_FreeSurface(temp);
slouken@6232
    90
        return NULL;
slouken@6232
    91
    }
slouken@6232
    92
    SDL_FreeSurface(temp);
slouken@6232
    93
slouken@6232
    94
    /* We're ready to roll. :) */
slouken@6232
    95
    return texture;
slouken@6232
    96
}
slouken@6232
    97
slouken@7781
    98
SDL_bool
slouken@7502
    99
DrawComposite(DrawState *s)
slouken@7502
   100
{
slouken@7502
   101
    SDL_Rect viewport, R;
philipp@7513
   102
    SDL_Texture *target;
slouken@7502
   103
slouken@7502
   104
    static SDL_bool blend_tested = SDL_FALSE;
slouken@7502
   105
    if (!blend_tested) {
slouken@7502
   106
        SDL_Texture *A, *B;
slouken@7502
   107
        Uint32 P;
slouken@7502
   108
slouken@7502
   109
        A = SDL_CreateTexture(s->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 1, 1);
slouken@7502
   110
        SDL_SetTextureBlendMode(A, SDL_BLENDMODE_BLEND);
slouken@7502
   111
slouken@7502
   112
        B = SDL_CreateTexture(s->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 1, 1);
slouken@7502
   113
        SDL_SetTextureBlendMode(B, SDL_BLENDMODE_BLEND);
slouken@7502
   114
slouken@7502
   115
        SDL_SetRenderTarget(s->renderer, A);
slouken@7502
   116
        SDL_SetRenderDrawColor(s->renderer, 0x00, 0x00, 0x00, 0x80);
slouken@7502
   117
        SDL_RenderFillRect(s->renderer, NULL);
slouken@7502
   118
slouken@7502
   119
        SDL_SetRenderTarget(s->renderer, B);
slouken@7502
   120
        SDL_SetRenderDrawColor(s->renderer, 0x00, 0x00, 0x00, 0x00);
slouken@7502
   121
        SDL_RenderFillRect(s->renderer, NULL);
slouken@7502
   122
        SDL_RenderCopy(s->renderer, A, NULL, NULL);
slouken@7502
   123
        SDL_RenderReadPixels(s->renderer, NULL, SDL_PIXELFORMAT_ARGB8888, &P, sizeof(P));
slouken@7502
   124
aschiffler@7639
   125
        SDL_Log("Blended pixel: 0x%8.8X\n", P);
slouken@7502
   126
slouken@7502
   127
        SDL_DestroyTexture(A);
slouken@7502
   128
        SDL_DestroyTexture(B);
slouken@7502
   129
        blend_tested = SDL_TRUE;
slouken@7502
   130
    }
slouken@7502
   131
slouken@7502
   132
    SDL_RenderGetViewport(s->renderer, &viewport);
slouken@7502
   133
slouken@7502
   134
    target = SDL_CreateTexture(s->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, viewport.w, viewport.h);
slouken@7502
   135
    SDL_SetTextureBlendMode(target, SDL_BLENDMODE_BLEND);
slouken@7502
   136
    SDL_SetRenderTarget(s->renderer, target);
slouken@7502
   137
slouken@7502
   138
    /* Draw the background.
slouken@7502
   139
       This is solid black so when the sprite is copied to it, any per-pixel alpha will be blended through.
slouken@7502
   140
     */
slouken@7502
   141
    SDL_SetRenderDrawColor(s->renderer, 0x00, 0x00, 0x00, 0x00);
slouken@7502
   142
    SDL_RenderFillRect(s->renderer, NULL);
slouken@7502
   143
slouken@7502
   144
    /* Scale and draw the sprite */
slouken@7502
   145
    s->sprite_rect.w += s->scale_direction;
slouken@7502
   146
    s->sprite_rect.h += s->scale_direction;
slouken@7502
   147
    if (s->scale_direction > 0) {
slouken@7502
   148
        if (s->sprite_rect.w >= viewport.w || s->sprite_rect.h >= viewport.h) {
slouken@7502
   149
            s->scale_direction = -1;
slouken@7502
   150
        }
slouken@7502
   151
    } else {
slouken@7502
   152
        if (s->sprite_rect.w <= 1 || s->sprite_rect.h <= 1) {
slouken@7502
   153
            s->scale_direction = 1;
slouken@7502
   154
        }
slouken@7502
   155
    }
slouken@7502
   156
    s->sprite_rect.x = (viewport.w - s->sprite_rect.w) / 2;
slouken@7502
   157
    s->sprite_rect.y = (viewport.h - s->sprite_rect.h) / 2;
slouken@7502
   158
slouken@7502
   159
    SDL_RenderCopy(s->renderer, s->sprite, NULL, &s->sprite_rect);
slouken@7502
   160
slouken@7502
   161
    SDL_SetRenderTarget(s->renderer, NULL);
slouken@7502
   162
    SDL_RenderCopy(s->renderer, s->background, NULL, NULL);
slouken@7502
   163
slouken@7502
   164
    SDL_SetRenderDrawBlendMode(s->renderer, SDL_BLENDMODE_BLEND);
slouken@7502
   165
    SDL_SetRenderDrawColor(s->renderer, 0xff, 0x00, 0x00, 0x80);
slouken@7502
   166
    R.x = 0;
slouken@7502
   167
    R.y = 0;
slouken@7502
   168
    R.w = 100;
slouken@7502
   169
    R.h = 100;
slouken@7502
   170
    SDL_RenderFillRect(s->renderer, &R);
slouken@7502
   171
    SDL_SetRenderDrawBlendMode(s->renderer, SDL_BLENDMODE_NONE);
slouken@7502
   172
slouken@7502
   173
    SDL_RenderCopy(s->renderer, target, NULL, NULL);
slouken@7502
   174
    SDL_DestroyTexture(target);
slouken@7502
   175
slouken@7502
   176
    /* Update the screen! */
slouken@7502
   177
    SDL_RenderPresent(s->renderer);
slouken@7781
   178
    return SDL_TRUE;
slouken@7502
   179
}
slouken@7502
   180
slouken@7781
   181
SDL_bool
slouken@6232
   182
Draw(DrawState *s)
slouken@6232
   183
{
slouken@6232
   184
    SDL_Rect viewport;
slouken@6232
   185
    SDL_Texture *target;
slouken@6232
   186
slouken@6232
   187
    SDL_RenderGetViewport(s->renderer, &viewport);
slouken@6232
   188
slouken@6232
   189
    target = SDL_CreateTexture(s->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, viewport.w, viewport.h);
slouken@7781
   190
    if (!target) {
slouken@7781
   191
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create render target texture: %s\n", SDL_GetError());
slouken@7781
   192
        return SDL_FALSE;
slouken@7781
   193
    }
slouken@6247
   194
    SDL_SetRenderTarget(s->renderer, target);
slouken@6232
   195
slouken@6232
   196
    /* Draw the background */
slouken@6232
   197
    SDL_RenderCopy(s->renderer, s->background, NULL, NULL);
slouken@6232
   198
slouken@6232
   199
    /* Scale and draw the sprite */
slouken@6232
   200
    s->sprite_rect.w += s->scale_direction;
slouken@6232
   201
    s->sprite_rect.h += s->scale_direction;
slouken@6232
   202
    if (s->scale_direction > 0) {
slouken@6232
   203
        if (s->sprite_rect.w >= viewport.w || s->sprite_rect.h >= viewport.h) {
slouken@6232
   204
            s->scale_direction = -1;
slouken@6232
   205
        }
slouken@6232
   206
    } else {
slouken@6232
   207
        if (s->sprite_rect.w <= 1 || s->sprite_rect.h <= 1) {
slouken@6232
   208
            s->scale_direction = 1;
slouken@6232
   209
        }
slouken@6232
   210
    }
slouken@6232
   211
    s->sprite_rect.x = (viewport.w - s->sprite_rect.w) / 2;
slouken@6232
   212
    s->sprite_rect.y = (viewport.h - s->sprite_rect.h) / 2;
slouken@6232
   213
slouken@6232
   214
    SDL_RenderCopy(s->renderer, s->sprite, NULL, &s->sprite_rect);
slouken@6232
   215
slouken@6247
   216
    SDL_SetRenderTarget(s->renderer, NULL);
slouken@6232
   217
    SDL_RenderCopy(s->renderer, target, NULL, NULL);
slouken@6232
   218
    SDL_DestroyTexture(target);
slouken@6232
   219
slouken@6232
   220
    /* Update the screen! */
slouken@6232
   221
    SDL_RenderPresent(s->renderer);
slouken@7781
   222
    return SDL_TRUE;
slouken@6232
   223
}
slouken@6232
   224
icculus@9278
   225
void
icculus@9278
   226
loop()
icculus@9278
   227
{
icculus@9278
   228
    int i;
icculus@9278
   229
    SDL_Event event;
icculus@9278
   230
icculus@9278
   231
    /* Check for events */
icculus@9278
   232
    while (SDL_PollEvent(&event)) {
icculus@9278
   233
        SDLTest_CommonEvent(state, &event, &done);
icculus@9278
   234
    }
icculus@9278
   235
    for (i = 0; i < state->num_windows; ++i) {
icculus@9278
   236
        if (state->windows[i] == NULL)
icculus@9278
   237
            continue;
icculus@9278
   238
        if (test_composite) {
icculus@9278
   239
            if (!DrawComposite(&drawstates[i])) done = 1;
icculus@9278
   240
        } else {
icculus@9278
   241
            if (!Draw(&drawstates[i])) done = 1;
icculus@9278
   242
        }
icculus@9278
   243
    }
philipp@9607
   244
#ifdef __EMSCRIPTEN__
philipp@9607
   245
    if (done) {
philipp@9607
   246
        emscripten_cancel_main_loop();
philipp@9607
   247
    }
philipp@9607
   248
#endif
icculus@9278
   249
}
icculus@9278
   250
slouken@6232
   251
int
slouken@6232
   252
main(int argc, char *argv[])
slouken@6232
   253
{
icculus@9278
   254
    int i;
slouken@6232
   255
    int frames;
slouken@6232
   256
    Uint32 then, now;
slouken@6232
   257
aschiffler@7639
   258
    /* Enable standard application logging */
aschiffler@7639
   259
    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
aschiffler@7639
   260
slouken@6232
   261
    /* Initialize test framework */
slouken@6785
   262
    state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
slouken@6232
   263
    if (!state) {
slouken@6232
   264
        return 1;
slouken@6232
   265
    }
slouken@6232
   266
    for (i = 1; i < argc;) {
slouken@6232
   267
        int consumed;
slouken@6232
   268
slouken@6785
   269
        consumed = SDLTest_CommonArg(state, i);
slouken@6232
   270
        if (consumed == 0) {
slouken@7502
   271
            consumed = -1;
slouken@7502
   272
            if (SDL_strcasecmp(argv[i], "--composite") == 0) {
slouken@7502
   273
                test_composite = SDL_TRUE;
slouken@7502
   274
                consumed = 1;
slouken@7502
   275
            }
slouken@7502
   276
        }
slouken@7502
   277
        if (consumed < 0) {
aschiffler@7639
   278
            SDL_Log("Usage: %s %s [--composite]\n",
slouken@7502
   279
                    argv[0], SDLTest_CommonUsage(state));
slouken@7502
   280
            quit(1);
slouken@6232
   281
        }
slouken@6232
   282
        i += consumed;
slouken@6232
   283
    }
slouken@6785
   284
    if (!SDLTest_CommonInit(state)) {
slouken@6232
   285
        quit(2);
slouken@6232
   286
    }
slouken@6232
   287
slouken@6232
   288
    drawstates = SDL_stack_alloc(DrawState, state->num_windows);
slouken@6232
   289
    for (i = 0; i < state->num_windows; ++i) {
slouken@6232
   290
        DrawState *drawstate = &drawstates[i];
slouken@6232
   291
slouken@6232
   292
        drawstate->window = state->windows[i];
slouken@6232
   293
        drawstate->renderer = state->renderers[i];
slouken@7502
   294
        if (test_composite) {
slouken@7502
   295
            drawstate->sprite = LoadTexture(drawstate->renderer, "icon-alpha.bmp", SDL_TRUE);
slouken@7502
   296
        } else {
slouken@7502
   297
            drawstate->sprite = LoadTexture(drawstate->renderer, "icon.bmp", SDL_TRUE);
slouken@7502
   298
        }
slouken@6232
   299
        drawstate->background = LoadTexture(drawstate->renderer, "sample.bmp", SDL_FALSE);
slouken@6232
   300
        if (!drawstate->sprite || !drawstate->background) {
slouken@6232
   301
            quit(2);
slouken@6232
   302
        }
slouken@6232
   303
        SDL_QueryTexture(drawstate->sprite, NULL, NULL,
slouken@6232
   304
                         &drawstate->sprite_rect.w, &drawstate->sprite_rect.h);
slouken@6232
   305
        drawstate->scale_direction = 1;
slouken@6232
   306
    }
slouken@6232
   307
slouken@6232
   308
    /* Main render loop */
slouken@6232
   309
    frames = 0;
slouken@6232
   310
    then = SDL_GetTicks();
slouken@6232
   311
    done = 0;
icculus@9278
   312
icculus@9278
   313
#ifdef __EMSCRIPTEN__
icculus@9278
   314
    emscripten_set_main_loop(loop, 0, 1);
icculus@9278
   315
#else
slouken@6232
   316
    while (!done) {
slouken@6232
   317
        ++frames;
icculus@9278
   318
        loop();
slouken@6232
   319
    }
icculus@9278
   320
#endif
slouken@6232
   321
slouken@6232
   322
    /* Print out some timing information */
slouken@6232
   323
    now = SDL_GetTicks();
slouken@6232
   324
    if (now > then) {
slouken@6232
   325
        double fps = ((double) frames * 1000) / (now - then);
aschiffler@7639
   326
        SDL_Log("%2.2f frames per second\n", fps);
slouken@6232
   327
    }
slouken@6232
   328
slouken@6232
   329
    SDL_stack_free(drawstates);
slouken@6232
   330
slouken@6232
   331
    quit(0);
slouken@6232
   332
    return 0;
slouken@6232
   333
}
slouken@6232
   334
slouken@6232
   335
/* vi: set ts=4 sw=4 expandtab: */