Atlas - testgdk.cpp

Home / ext / SDL / VisualC-GDK / tests / testgdk / src Lines: 1 | Size: 15851 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 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/* testgdk: Basic tests of using task queue/xbl (with simple drawing) in GDK. 13 * NOTE: As of June 2022 GDK, login will only work if MicrosoftGame.config is 14 * configured properly. See README-gdk.md. 15 */ 16 17#include <stdlib.h> 18#include <stdio.h> 19#include <time.h> 20 21#include <SDL3/SDL_test.h> 22#include <SDL3/SDL_test_common.h> 23#include "../src/core/windows/SDL_windows.h" 24#include <SDL3/SDL_main.h> 25 26extern "C" { 27#include "../test/testutils.h" 28} 29 30#include <XGameRuntime.h> 31 32#define NUM_SPRITES 100 33#define MAX_SPEED 1 34#define SUSPEND_CODE 0 35#define RESUME_CODE 1 36 37static SDLTest_CommonState *state; 38static int num_sprites; 39static SDL_Texture **sprites; 40static bool cycle_color; 41static bool cycle_alpha; 42static int cycle_direction = 1; 43static int current_alpha = 0; 44static int current_color = 0; 45static int sprite_w, sprite_h; 46static SDL_BlendMode blendMode = SDL_BLENDMODE_BLEND; 47 48int done; 49 50static struct 51{ 52 SDL_AudioSpec spec; 53 Uint8 *sound; /* Pointer to wave data */ 54 Uint32 soundlen; /* Length of wave data */ 55 int soundpos; /* Current play position */ 56} wave; 57 58static SDL_AudioStream *stream; 59 60/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ 61static void quit(int rc) 62{ 63 SDL_free(sprites); 64 SDL_DestroyAudioStream(stream); 65 SDL_free(wave.sound); 66 SDLTest_CommonQuit(state); 67 /* If rc is 0, just let main return normally rather than calling exit. 68 * This allows testing of platforms where SDL_main is required and does meaningful cleanup. 69 */ 70 if (rc != 0) { 71 exit(rc); 72 } 73} 74 75static int fillerup(void) 76{ 77 const int minimum = (wave.soundlen / SDL_AUDIO_FRAMESIZE(wave.spec)) / 2; 78 if (SDL_GetAudioStreamQueued(stream) < minimum) { 79 SDL_PutAudioStreamData(stream, wave.sound, wave.soundlen); 80 } 81 return 0; 82} 83 84static void UserLoggedIn(XUserHandle user) 85{ 86 HRESULT hr; 87 char gamertag[128]; 88 hr = XUserGetGamertag(user, XUserGamertagComponent::UniqueModern, sizeof(gamertag), gamertag, NULL); 89 90 if (SUCCEEDED(hr)) { 91 SDL_Log("User logged in: %s", gamertag); 92 } else { 93 SDL_Log("[GDK] UserLoggedIn -- XUserGetGamertag failed: 0x%08x.", hr); 94 } 95 96 XUserCloseHandle(user); 97} 98 99static void AddUserUICallback(XAsyncBlock *asyncBlock) 100{ 101 HRESULT hr; 102 XUserHandle user = NULL; 103 104 hr = XUserAddResult(asyncBlock, &user); 105 if (SUCCEEDED(hr)) { 106 uint64_t userId; 107 108 hr = XUserGetId(user, &userId); 109 if (FAILED(hr)) { 110 /* If unable to get the user ID, it means the account is banned, etc. */ 111 SDL_Log("[GDK] AddUserSilentCallback -- XUserGetId failed: 0x%08x.", hr); 112 XUserCloseHandle(user); 113 114 /* Per the docs, likely should call XUserResolveIssueWithUiAsync here. */ 115 } else { 116 UserLoggedIn(user); 117 } 118 } else { 119 SDL_Log("[GDK] AddUserUICallback -- XUserAddAsync failed: 0x%08x.", hr); 120 } 121 122 delete asyncBlock; 123} 124 125static void AddUserUI() 126{ 127 HRESULT hr; 128 XAsyncBlock *asyncBlock = new XAsyncBlock; 129 130 asyncBlock->context = NULL; 131 asyncBlock->queue = NULL; /* A null queue will use the global process task queue */ 132 asyncBlock->callback = &AddUserUICallback; 133 134 hr = XUserAddAsync(XUserAddOptions::None, asyncBlock); 135 136 if (FAILED(hr)) { 137 delete asyncBlock; 138 SDL_Log("[GDK] AddUserSilent -- failed: 0x%08x", hr); 139 } 140} 141 142static void AddUserSilentCallback(XAsyncBlock *asyncBlock) 143{ 144 HRESULT hr; 145 XUserHandle user = NULL; 146 147 hr = XUserAddResult(asyncBlock, &user); 148 if (SUCCEEDED(hr)) { 149 uint64_t userId; 150 151 hr = XUserGetId(user, &userId); 152 if (FAILED(hr)) { 153 /* If unable to get the user ID, it means the account is banned, etc. */ 154 SDL_Log("[GDK] AddUserSilentCallback -- XUserGetId failed: 0x%08x. Trying with UI.", hr); 155 XUserCloseHandle(user); 156 AddUserUI(); 157 } else { 158 UserLoggedIn(user); 159 } 160 } else { 161 SDL_Log("[GDK] AddUserSilentCallback -- XUserAddAsync failed: 0x%08x. Trying with UI.", hr); 162 AddUserUI(); 163 } 164 165 delete asyncBlock; 166} 167 168static void AddUserSilent() 169{ 170 HRESULT hr; 171 XAsyncBlock *asyncBlock = new XAsyncBlock; 172 173 asyncBlock->context = NULL; 174 asyncBlock->queue = NULL; /* A null queue will use the global process task queue */ 175 asyncBlock->callback = &AddUserSilentCallback; 176 177 hr = XUserAddAsync(XUserAddOptions::AddDefaultUserSilently, asyncBlock); 178 179 if (FAILED(hr)) { 180 delete asyncBlock; 181 SDL_Log("[GDK] AddUserSilent -- failed: 0x%08x", hr); 182 } 183} 184 185static bool LoadSprite(const char *file) 186{ 187 int i; 188 189 for (i = 0; i < state->num_windows; ++i) { 190 /* This does the SDL_LoadBMP step repeatedly, but that's OK for test code. */ 191 sprites[i] = LoadTexture(state->renderers[i], file, true); 192 if (!sprites[i]) { 193 return false; 194 } 195 sprite_w = sprites[i]->w; 196 sprite_h = sprites[i]->h; 197 198 SDL_SetTextureBlendMode(sprites[i], blendMode); 199 } 200 201 /* We're ready to roll. :) */ 202 return true; 203} 204 205static void DrawSprites(SDL_Renderer * renderer, SDL_Texture * sprite) 206{ 207 SDL_Rect viewport; 208 SDL_FRect temp; 209 210 /* Query the sizes */ 211 SDL_GetRenderViewport(renderer, &viewport); 212 213 /* Cycle the color and alpha, if desired */ 214 if (cycle_color) { 215 current_color += cycle_direction; 216 if (current_color < 0) { 217 current_color = 0; 218 cycle_direction = -cycle_direction; 219 } 220 if (current_color > 255) { 221 current_color = 255; 222 cycle_direction = -cycle_direction; 223 } 224 SDL_SetTextureColorMod(sprite, 255, (Uint8) current_color, 225 (Uint8) current_color); 226 } 227 if (cycle_alpha) { 228 current_alpha += cycle_direction; 229 if (current_alpha < 0) { 230 current_alpha = 0; 231 cycle_direction = -cycle_direction; 232 } 233 if (current_alpha > 255) { 234 current_alpha = 255; 235 cycle_direction = -cycle_direction; 236 } 237 SDL_SetTextureAlphaMod(sprite, (Uint8) current_alpha); 238 } 239 240 /* Draw a gray background */ 241 SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); 242 SDL_RenderClear(renderer); 243 244 /* Test points */ 245 SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF); 246 SDL_RenderPoint(renderer, 0.0f, 0.0f); 247 SDL_RenderPoint(renderer, (float)(viewport.w - 1), 0.0f); 248 SDL_RenderPoint(renderer, 0.0f, (float)(viewport.h - 1)); 249 SDL_RenderPoint(renderer, (float)(viewport.w - 1), (float)(viewport.h - 1)); 250 251 /* Test horizontal and vertical lines */ 252 SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF); 253 SDL_RenderLine(renderer, 1.0f, 0.0f, (float)(viewport.w - 2), 0.0f); 254 SDL_RenderLine(renderer, 1.0f, (float)(viewport.h - 1), (float)(viewport.w - 2), (float)(viewport.h - 1)); 255 SDL_RenderLine(renderer, 0.0f, 1.0f, 0.0f, (float)(viewport.h - 2)); 256 SDL_RenderLine(renderer, (float)(viewport.w - 1), 1, (float)(viewport.w - 1), (float)(viewport.h - 2)); 257 258 /* Test fill and copy */ 259 SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); 260 temp.x = 1.0f; 261 temp.y = 1.0f; 262 temp.w = (float)sprite_w; 263 temp.h = (float)sprite_h; 264 SDL_RenderFillRect(renderer, &temp); 265 SDL_RenderTexture(renderer, sprite, NULL, &temp); 266 temp.x = (float)(viewport.w-sprite_w-1); 267 temp.y = 1.0f; 268 temp.w = (float)sprite_w; 269 temp.h = (float)sprite_h; 270 SDL_RenderFillRect(renderer, &temp); 271 SDL_RenderTexture(renderer, sprite, NULL, &temp); 272 temp.x = 1.0f; 273 temp.y = (float)(viewport.h-sprite_h-1); 274 temp.w = (float)sprite_w; 275 temp.h = (float)sprite_h; 276 SDL_RenderFillRect(renderer, &temp); 277 SDL_RenderTexture(renderer, sprite, NULL, &temp); 278 temp.x = (float)(viewport.w-sprite_w-1); 279 temp.y = (float)(viewport.h-sprite_h-1); 280 temp.w = (float)(sprite_w); 281 temp.h = (float)(sprite_h); 282 SDL_RenderFillRect(renderer, &temp); 283 SDL_RenderTexture(renderer, sprite, NULL, &temp); 284 285 /* Test diagonal lines */ 286 SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF); 287 SDL_RenderLine(renderer, (float)sprite_w, (float)sprite_h, 288 (float)(viewport.w-sprite_w-2), (float)(viewport.h-sprite_h-2)); 289 SDL_RenderLine(renderer, (float)(viewport.w-sprite_w-2), (float)sprite_h, 290 (float)sprite_w, (float)(viewport.h-sprite_h-2)); 291 292 /* Update the screen! */ 293 SDL_RenderPresent(renderer); 294} 295 296static void update(bool *suppressdraw) 297{ 298 SDL_Event event; 299 300 /* Check for events */ 301 while (SDL_PollEvent(&event)) { 302 if (event.type == SDL_EVENT_KEY_DOWN && !event.key.repeat) { 303 SDL_Log("Initial SDL_EVENT_KEY_DOWN: %s", SDL_GetScancodeName(event.key.scancode)); 304 } 305#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) 306 /* On Xbox, ignore the keydown event because the features aren't supported */ 307 if (event.type != SDL_EVENT_KEY_DOWN) { 308 SDLTest_CommonEvent(state, &event, &done); 309 } 310 311 if (event.type == SDL_EVENT_USER) { 312 if (event.user.code == SUSPEND_CODE) { 313 for (int i = 0; i < state->num_windows; ++i) { 314 if (state->windows[i] != NULL) { 315 SDL_GDKSuspendRenderer(state->renderers[i]); 316 } 317 } 318 *suppressdraw = true; 319 SDL_GDKSuspendComplete(); 320 } else if (event.user.code == RESUME_CODE) { 321 for (int i = 0; i < state->num_windows; ++i) { 322 if (state->windows[i] != NULL) { 323 SDL_GDKResumeRenderer(state->renderers[i]); 324 } 325 } 326 *suppressdraw = false; 327 } 328 } 329#else 330 SDLTest_CommonEvent(state, &event, &done); 331#endif 332 } 333 fillerup(); 334} 335 336static void draw() 337{ 338 int i; 339 for (i = 0; i < state->num_windows; ++i) { 340 if (state->windows[i] != NULL) { 341 DrawSprites(state->renderers[i], sprites[i]); 342 } 343 } 344} 345 346static bool SDLCALL GDKEventWatch(void* userdata, SDL_Event* event) 347{ 348 /* This callback may be on a different thread, so we'll 349 * push these events as USER events so they appear 350 * in the main thread's event loop. 351 * 352 * That allows us to cancel drawing before/after we finish 353 * drawing a frame, rather than mid-draw (which can crash). 354 */ 355 if (event->type == SDL_EVENT_DID_ENTER_BACKGROUND) { 356 SDL_Event evt; 357 evt.type = SDL_EVENT_USER; 358 evt.user.code = 0; 359 SDL_PushEvent(&evt); 360 } else if (event->type == SDL_EVENT_WILL_ENTER_FOREGROUND) { 361 SDL_Event evt; 362 evt.type = SDL_EVENT_USER; 363 evt.user.code = 1; 364 SDL_PushEvent(&evt); 365 } 366 return false; 367} 368 369int main(int argc, char *argv[]) 370{ 371 int i; 372 const char *icon = "icon.png"; 373 char *soundname = NULL; 374 bool suppressdraw = false; 375 376 /* Initialize parameters */ 377 num_sprites = NUM_SPRITES; 378 379 /* Initialize test framework */ 380 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO | SDL_INIT_AUDIO); 381 if (!state) { 382 return 1; 383 } 384 385 for (i = 1; i < argc;) { 386 int consumed; 387 388 consumed = SDLTest_CommonArg(state, i); 389 if (consumed == 0) { 390 consumed = -1; 391 if (SDL_strcasecmp(argv[i], "--blend") == 0) { 392 if (argv[i + 1]) { 393 if (SDL_strcasecmp(argv[i + 1], "none") == 0) { 394 blendMode = SDL_BLENDMODE_NONE; 395 consumed = 2; 396 } else if (SDL_strcasecmp(argv[i + 1], "blend") == 0) { 397 blendMode = SDL_BLENDMODE_BLEND; 398 consumed = 2; 399 } else if (SDL_strcasecmp(argv[i + 1], "add") == 0) { 400 blendMode = SDL_BLENDMODE_ADD; 401 consumed = 2; 402 } else if (SDL_strcasecmp(argv[i + 1], "mod") == 0) { 403 blendMode = SDL_BLENDMODE_MOD; 404 consumed = 2; 405 } else if (SDL_strcasecmp(argv[i + 1], "sub") == 0) { 406 blendMode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_SUBTRACT, SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_SUBTRACT); 407 consumed = 2; 408 } 409 } 410 } else if (SDL_strcasecmp(argv[i], "--cyclecolor") == 0) { 411 cycle_color = true; 412 consumed = 1; 413 } else if (SDL_strcasecmp(argv[i], "--cyclealpha") == 0) { 414 cycle_alpha = true; 415 consumed = 1; 416 } else if (SDL_isdigit(*argv[i])) { 417 num_sprites = SDL_atoi(argv[i]); 418 consumed = 1; 419 } else if (argv[i][0] != '-') { 420 icon = argv[i]; 421 consumed = 1; 422 } 423 } 424 if (consumed < 0) { 425 static const char *options[] = { 426 "[--blend none|blend|add|mod]", 427 "[--cyclecolor]", 428 "[--cyclealpha]", 429 "[num_sprites]", 430 "[icon.bmp]", 431 NULL }; 432 SDLTest_CommonLogUsage(state, argv[0], options); 433 quit(1); 434 } 435 i += consumed; 436 } 437 if (!SDLTest_CommonInit(state)) { 438 quit(2); 439 } 440 441 /* Set up the lifecycle event watcher */ 442 SDL_AddEventWatch(GDKEventWatch, NULL); 443 444 /* Create the windows, initialize the renderers, and load the textures */ 445 sprites = 446 (SDL_Texture **) SDL_malloc(state->num_windows * sizeof(*sprites)); 447 if (!sprites) { 448 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); 449 quit(2); 450 } 451 for (i = 0; i < state->num_windows; ++i) { 452 SDL_Renderer *renderer = state->renderers[i]; 453 SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); 454 SDL_RenderClear(renderer); 455 } 456 if (!LoadSprite(icon)) { 457 quit(2); 458 } 459 460 soundname = GetResourceFilename(argc > 1 ? argv[1] : NULL, "sample.wav"); 461 462 if (!soundname) { 463 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", SDL_GetError()); 464 quit(1); 465 } 466 467 /* Load the wave file into memory */ 468 if (!SDL_LoadWAV(soundname, &wave.spec, &wave.sound, &wave.soundlen)) { 469 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", soundname, SDL_GetError()); 470 quit(1); 471 } 472 473 /* Show the list of available drivers */ 474 SDL_Log("Available audio drivers:"); 475 for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) { 476 SDL_Log("%i: %s", i, SDL_GetAudioDriver(i)); 477 } 478 479 SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver()); 480 481 stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &wave.spec, NULL, NULL); 482 if (!stream) { 483 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create audio stream: %s", SDL_GetError()); 484 return -1; 485 } 486 SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream)); 487 488 /* Main render loop */ 489 done = 0; 490 491 /* Try to add the default user silently */ 492 AddUserSilent(); 493 494 while (!done) { 495 update(&suppressdraw); 496 if (!suppressdraw) { 497 draw(); 498 } 499 } 500 501 quit(0); 502 503 SDL_free(soundname); 504 return 0; 505} 506
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.