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