test/testsprite2.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 23 Jul 2013 08:06:49 -0700
changeset 7502 6ff02ff3cf06
parent 7315 417fa81cf17e
child 7517 965d57022c01
permissions -rw-r--r--
Updated blend semantics so blending uses the following formula:
dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
dstA = srcA + (dstA * (1-srcA))
This allows proper compositing semantics without requiring premultiplied alpha.

Needs full unit test coverage and bug fixes!
     1 /*
     2   Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
     3 
     4   This software is provided 'as-is', without any express or implied
     5   warranty.  In no event will the authors be held liable for any damages
     6   arising from the use of this software.
     7 
     8   Permission is granted to anyone to use this software for any purpose,
     9   including commercial applications, and to alter it and redistribute it
    10   freely.
    11 */
    12 /* Simple program:  Move N sprites around on the screen as fast as possible */
    13 
    14 #include <stdlib.h>
    15 #include <stdio.h>
    16 #include <time.h>
    17 
    18 #include "SDL_test.h"
    19 #include "SDL_test_common.h"
    20 
    21 #define NUM_SPRITES    100
    22 #define MAX_SPEED     1
    23 
    24 static SDLTest_CommonState *state;
    25 static int num_sprites;
    26 static SDL_Texture **sprites;
    27 static SDL_bool cycle_color;
    28 static SDL_bool cycle_alpha;
    29 static int cycle_direction = 1;
    30 static int current_alpha = 0;
    31 static int current_color = 0;
    32 static SDL_Rect *positions;
    33 static SDL_Rect *velocities;
    34 static int sprite_w, sprite_h;
    35 static SDL_BlendMode blendMode = SDL_BLENDMODE_BLEND;
    36 
    37 /* Number of iterations to move sprites - used for visual tests. */
    38 /* -1: infinite random moves (default); >=0: enables N deterministic moves */
    39 static int iterations = -1;
    40 
    41 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
    42 static void
    43 quit(int rc)
    44 {
    45     if (sprites) {
    46         SDL_free(sprites);
    47     }
    48     if (positions) {
    49         SDL_free(positions);
    50     }
    51     if (velocities) {
    52         SDL_free(velocities);
    53     }
    54     SDLTest_CommonQuit(state);
    55     exit(rc);
    56 }
    57 
    58 int
    59 LoadSprite(const char *file)
    60 {
    61     int i;
    62     SDL_Surface *temp;
    63 
    64     /* Load the sprite image */
    65     temp = SDL_LoadBMP(file);
    66     if (temp == NULL) {
    67         fprintf(stderr, "Couldn't load %s: %s", file, SDL_GetError());
    68         return (-1);
    69     }
    70     sprite_w = temp->w;
    71     sprite_h = temp->h;
    72 
    73     /* Set transparent pixel as the pixel at (0,0) */
    74     if (temp->format->palette) {
    75         SDL_SetColorKey(temp, 1, *(Uint8 *) temp->pixels);
    76     } else {
    77         switch (temp->format->BitsPerPixel) {
    78         case 15:
    79             SDL_SetColorKey(temp, 1, (*(Uint16 *) temp->pixels) & 0x00007FFF);
    80             break;
    81         case 16:
    82             SDL_SetColorKey(temp, 1, *(Uint16 *) temp->pixels);
    83             break;
    84         case 24:
    85             SDL_SetColorKey(temp, 1, (*(Uint32 *) temp->pixels) & 0x00FFFFFF);
    86             break;
    87         case 32:
    88             SDL_SetColorKey(temp, 1, *(Uint32 *) temp->pixels);
    89             break;
    90         }
    91     }
    92 
    93     /* Create textures from the image */
    94     for (i = 0; i < state->num_windows; ++i) {
    95         SDL_Renderer *renderer = state->renderers[i];
    96         sprites[i] = SDL_CreateTextureFromSurface(renderer, temp);
    97         if (!sprites[i]) {
    98             fprintf(stderr, "Couldn't create texture: %s\n", SDL_GetError());
    99             SDL_FreeSurface(temp);
   100             return (-1);
   101         }
   102         SDL_SetTextureBlendMode(sprites[i], blendMode);
   103     }
   104     SDL_FreeSurface(temp);
   105 
   106     /* We're ready to roll. :) */
   107     return (0);
   108 }
   109 
   110 void
   111 MoveSprites(SDL_Renderer * renderer, SDL_Texture * sprite)
   112 {
   113     int i;
   114     SDL_Rect viewport, temp;
   115     SDL_Rect *position, *velocity;
   116 
   117     /* Query the sizes */
   118     SDL_RenderGetViewport(renderer, &viewport);
   119 
   120     /* Cycle the color and alpha, if desired */
   121     if (cycle_color) {
   122         current_color += cycle_direction;
   123         if (current_color < 0) {
   124             current_color = 0;
   125             cycle_direction = -cycle_direction;
   126         }
   127         if (current_color > 255) {
   128             current_color = 255;
   129             cycle_direction = -cycle_direction;
   130         }
   131         SDL_SetTextureColorMod(sprite, 255, (Uint8) current_color,
   132                                (Uint8) current_color);
   133     }
   134     if (cycle_alpha) {
   135         current_alpha += cycle_direction;
   136         if (current_alpha < 0) {
   137             current_alpha = 0;
   138             cycle_direction = -cycle_direction;
   139         }
   140         if (current_alpha > 255) {
   141             current_alpha = 255;
   142             cycle_direction = -cycle_direction;
   143         }
   144         SDL_SetTextureAlphaMod(sprite, (Uint8) current_alpha);
   145     }
   146 
   147     /* Draw a gray background */
   148     SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
   149     SDL_RenderClear(renderer);
   150 
   151     /* Test points */
   152     SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF);
   153     SDL_RenderDrawPoint(renderer, 0, 0);
   154     SDL_RenderDrawPoint(renderer, viewport.w-1, 0);
   155     SDL_RenderDrawPoint(renderer, 0, viewport.h-1);
   156     SDL_RenderDrawPoint(renderer, viewport.w-1, viewport.h-1);
   157 
   158     /* Test horizontal and vertical lines */
   159     SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF);
   160     SDL_RenderDrawLine(renderer, 1, 0, viewport.w-2, 0);
   161     SDL_RenderDrawLine(renderer, 1, viewport.h-1, viewport.w-2, viewport.h-1);
   162     SDL_RenderDrawLine(renderer, 0, 1, 0, viewport.h-2);
   163     SDL_RenderDrawLine(renderer, viewport.w-1, 1, viewport.w-1, viewport.h-2);
   164 
   165     /* Test fill and copy */
   166     SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
   167     temp.x = 1;
   168     temp.y = 1;
   169     temp.w = sprite_w;
   170     temp.h = sprite_h;
   171     SDL_RenderFillRect(renderer, &temp);
   172     SDL_RenderCopy(renderer, sprite, NULL, &temp);
   173     temp.x = viewport.w-sprite_w-1;
   174     temp.y = 1;
   175     temp.w = sprite_w;
   176     temp.h = sprite_h;
   177     SDL_RenderFillRect(renderer, &temp);
   178     SDL_RenderCopy(renderer, sprite, NULL, &temp);
   179     temp.x = 1;
   180     temp.y = viewport.h-sprite_h-1;
   181     temp.w = sprite_w;
   182     temp.h = sprite_h;
   183     SDL_RenderFillRect(renderer, &temp);
   184     SDL_RenderCopy(renderer, sprite, NULL, &temp);
   185     temp.x = viewport.w-sprite_w-1;
   186     temp.y = viewport.h-sprite_h-1;
   187     temp.w = sprite_w;
   188     temp.h = sprite_h;
   189     SDL_RenderFillRect(renderer, &temp);
   190     SDL_RenderCopy(renderer, sprite, NULL, &temp);
   191 
   192     /* Test diagonal lines */
   193     SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF);
   194     SDL_RenderDrawLine(renderer, sprite_w, sprite_h,
   195                        viewport.w-sprite_w-2, viewport.h-sprite_h-2);
   196     SDL_RenderDrawLine(renderer, viewport.w-sprite_w-2, sprite_h,
   197                        sprite_w, viewport.h-sprite_h-2);
   198 
   199     /* Conditionally move the sprites, bounce at the wall */
   200     if (iterations == -1 || iterations > 0) {
   201         for (i = 0; i < num_sprites; ++i) {
   202             position = &positions[i];
   203             velocity = &velocities[i];
   204             position->x += velocity->x;
   205             if ((position->x < 0) || (position->x >= (viewport.w - sprite_w))) {
   206             	velocity->x = -velocity->x;
   207             	position->x += velocity->x;
   208             }
   209             position->y += velocity->y;
   210             if ((position->y < 0) || (position->y >= (viewport.h - sprite_h))) {
   211             	velocity->y = -velocity->y;
   212             	position->y += velocity->y;
   213             }
   214 
   215         }
   216         
   217         /* Countdown sprite-move iterations and disable color changes at iteration end - used for visual tests. */
   218         if (iterations > 0) {
   219             iterations--;
   220             if (iterations == 0) {
   221                 cycle_alpha = SDL_FALSE;
   222                 cycle_color = SDL_FALSE;
   223             }
   224         }
   225     }
   226 
   227     /* Draw sprites */
   228     for (i = 0; i < num_sprites; ++i) {
   229         position = &positions[i];
   230 		
   231         /* Blit the sprite onto the screen */
   232         SDL_RenderCopy(renderer, sprite, NULL, position);
   233     }
   234 
   235     /* Update the screen! */
   236     SDL_RenderPresent(renderer);
   237 }
   238 
   239 int
   240 main(int argc, char *argv[])
   241 {
   242     int i, done;
   243     SDL_Event event;
   244     Uint32 then, now, frames;
   245 	Uint64 seed;
   246     const char *icon = "icon.bmp";
   247 
   248     /* Initialize parameters */
   249     num_sprites = NUM_SPRITES;
   250 
   251     /* Initialize test framework */
   252     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
   253     if (!state) {
   254         return 1;
   255     }
   256 
   257     state->window_flags |= SDL_WINDOW_RESIZABLE;
   258 
   259     for (i = 1; i < argc;) {
   260         int consumed;
   261 
   262         consumed = SDLTest_CommonArg(state, i);
   263         if (consumed == 0) {
   264             consumed = -1;
   265             if (SDL_strcasecmp(argv[i], "--blend") == 0) {
   266                 if (argv[i + 1]) {
   267                     if (SDL_strcasecmp(argv[i + 1], "none") == 0) {
   268                         blendMode = SDL_BLENDMODE_NONE;
   269                         consumed = 2;
   270                     } else if (SDL_strcasecmp(argv[i + 1], "blend") == 0) {
   271                         blendMode = SDL_BLENDMODE_BLEND;
   272                         consumed = 2;
   273                     } else if (SDL_strcasecmp(argv[i + 1], "add") == 0) {
   274                         blendMode = SDL_BLENDMODE_ADD;
   275                         consumed = 2;
   276                     } else if (SDL_strcasecmp(argv[i + 1], "mod") == 0) {
   277                         blendMode = SDL_BLENDMODE_MOD;
   278                         consumed = 2;
   279                     }
   280                 }
   281             } else if (SDL_strcasecmp(argv[i], "--iterations") == 0) {
   282                 if (argv[i + 1]) {
   283                     iterations = SDL_atoi(argv[i + 1]);
   284                     if (iterations < -1) iterations = -1;
   285                     consumed = 2;
   286                 }
   287             } else if (SDL_strcasecmp(argv[i], "--cyclecolor") == 0) {
   288                 cycle_color = SDL_TRUE;
   289                 consumed = 1;
   290             } else if (SDL_strcasecmp(argv[i], "--cyclealpha") == 0) {
   291                 cycle_alpha = SDL_TRUE;
   292                 consumed = 1;
   293             } else if (SDL_isdigit(*argv[i])) {
   294                 num_sprites = SDL_atoi(argv[i]);
   295                 consumed = 1;
   296             } else if (argv[i][0] != '-') {
   297                 icon = argv[i];
   298                 consumed = 1;
   299             }
   300         }
   301         if (consumed < 0) {
   302             fprintf(stderr,
   303                     "Usage: %s %s [--blend none|blend|add|mod] [--cyclecolor] [--cyclealpha] [--iterations N] [num_sprites] [icon.bmp]\n",
   304                     argv[0], SDLTest_CommonUsage(state));
   305             quit(1);
   306         }
   307         i += consumed;
   308     }
   309     if (!SDLTest_CommonInit(state)) {
   310         quit(2);
   311     }
   312 
   313     /* Create the windows, initialize the renderers, and load the textures */
   314     sprites =
   315         (SDL_Texture **) SDL_malloc(state->num_windows * sizeof(*sprites));
   316     if (!sprites) {
   317         fprintf(stderr, "Out of memory!\n");
   318         quit(2);
   319     }
   320     for (i = 0; i < state->num_windows; ++i) {
   321         SDL_Renderer *renderer = state->renderers[i];
   322         SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
   323         SDL_RenderClear(renderer);
   324     }
   325     if (LoadSprite(icon) < 0) {
   326         quit(2);
   327     }
   328 
   329     /* Allocate memory for the sprite info */
   330     positions = (SDL_Rect *) SDL_malloc(num_sprites * sizeof(SDL_Rect));
   331     velocities = (SDL_Rect *) SDL_malloc(num_sprites * sizeof(SDL_Rect));
   332     if (!positions || !velocities) {
   333         fprintf(stderr, "Out of memory!\n");
   334         quit(2);
   335     }
   336 
   337     /* Position sprites and set their velocities using the fuzzer */ 
   338     if (iterations >= 0) {
   339         /* Deterministic seed - used for visual tests */
   340         seed = (Uint64)iterations;
   341     } else {
   342         /* Pseudo-random seed generated from the time */
   343         seed = (Uint64)time(NULL);
   344     }
   345     SDLTest_FuzzerInit(seed);
   346     for (i = 0; i < num_sprites; ++i) {
   347         positions[i].x = SDLTest_RandomIntegerInRange(0, state->window_w - sprite_w);
   348         positions[i].y = SDLTest_RandomIntegerInRange(0, state->window_h - sprite_h);
   349         positions[i].w = sprite_w;
   350         positions[i].h = sprite_h;
   351         velocities[i].x = 0;
   352         velocities[i].y = 0;
   353         while (!velocities[i].x && !velocities[i].y) {
   354             velocities[i].x = SDLTest_RandomIntegerInRange(-MAX_SPEED, MAX_SPEED);
   355             velocities[i].y = SDLTest_RandomIntegerInRange(-MAX_SPEED, MAX_SPEED);
   356         }
   357     }
   358 
   359     /* Main render loop */
   360     frames = 0;
   361     then = SDL_GetTicks();
   362     done = 0;
   363     while (!done) {
   364         /* Check for events */
   365         ++frames;
   366         while (SDL_PollEvent(&event)) {
   367             SDLTest_CommonEvent(state, &event, &done);
   368         }
   369         for (i = 0; i < state->num_windows; ++i) {
   370             MoveSprites(state->renderers[i], sprites[i]);
   371         }
   372     }
   373 
   374     /* Print out some timing information */
   375     now = SDL_GetTicks();
   376     if (now > then) {
   377         double fps = ((double) frames * 1000) / (now - then);
   378         printf("%2.2f frames per second\n", fps);
   379     }
   380     quit(0);
   381     return 0;
   382 }
   383 
   384 /* vi: set ts=4 sw=4 expandtab: */