Simple Directmedia Layer
at main 15 kB view raw
1/* 2 Copyright (C) 1997-2024 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 13#include <SDL3/SDL_test_common.h> 14#include <SDL3/SDL_main.h> 15 16#ifdef SDL_PLATFORM_EMSCRIPTEN 17#include <emscripten/emscripten.h> 18#endif 19 20#include <stdlib.h> 21 22/* Stolen from the mailing list */ 23/* Creates a new mouse cursor from an XPM */ 24 25/* XPM */ 26static const char *arrow[] = { 27 /* width height num_colors chars_per_pixel */ 28 " 32 32 3 1", 29 /* colors */ 30 "X c #000000", 31 ". c #ffffff", 32 " c None", 33 /* pixels */ 34 "X ", 35 "XX ", 36 "X.X ", 37 "X..X ", 38 "X...X ", 39 "X....X ", 40 "X.....X ", 41 "X......X ", 42 "X.......X ", 43 "X........X ", 44 "X.....XXXXX ", 45 "X..X..X ", 46 "X.X X..X ", 47 "XX X..X ", 48 "X X..X ", 49 " X..X ", 50 " X..X ", 51 " X..X ", 52 " XX ", 53 " ", 54 " ", 55 " ", 56 " ", 57 " ", 58 " ", 59 " ", 60 " ", 61 " ", 62 " ", 63 " ", 64 " ", 65 " ", 66 "0,0" 67}; 68 69static const char *cross[] = { 70 /* width height num_colors chars_per_pixel */ 71 " 32 32 3 1", 72 /* colors */ 73 "o c #000000", 74 ". c #ffffff", 75 " c None", 76 /* pixels */ 77 " ", 78 " ", 79 " ", 80 " ", 81 " oo ", 82 " oo ", 83 " oo ", 84 " oo ", 85 " oo ", 86 " oo ", 87 " oo ", 88 " oo ", 89 " oo ", 90 " oo ", 91 " oo ", 92 " oooooooooooooooooooooooo ", 93 " oooooooooooooooooooooooo ", 94 " oo ", 95 " oo ", 96 " oo ", 97 " oo ", 98 " oo ", 99 " oo ", 100 " oo ", 101 " oo ", 102 " oo ", 103 " oo ", 104 " oo ", 105 " ", 106 " ", 107 " ", 108 " ", 109 "0,0" 110}; 111 112static SDL_Surface *load_image_file(const char *file) 113{ 114 SDL_Surface *surface = SDL_LoadBMP(file); 115 if (surface) { 116 if (SDL_GetSurfacePalette(surface)) { 117 const Uint8 bpp = SDL_BITSPERPIXEL(surface->format); 118 const Uint8 mask = (1 << bpp) - 1; 119 if (SDL_PIXELORDER(surface->format) == SDL_BITMAPORDER_4321) 120 SDL_SetSurfaceColorKey(surface, 1, (*(Uint8 *)surface->pixels) & mask); 121 else 122 SDL_SetSurfaceColorKey(surface, 1, ((*(Uint8 *)surface->pixels) >> (8 - bpp)) & mask); 123 } else { 124 switch (SDL_BITSPERPIXEL(surface->format)) { 125 case 15: 126 SDL_SetSurfaceColorKey(surface, 1, (*(Uint16 *)surface->pixels) & 0x00007FFF); 127 break; 128 case 16: 129 SDL_SetSurfaceColorKey(surface, 1, *(Uint16 *)surface->pixels); 130 break; 131 case 24: 132 SDL_SetSurfaceColorKey(surface, 1, (*(Uint32 *)surface->pixels) & 0x00FFFFFF); 133 break; 134 case 32: 135 SDL_SetSurfaceColorKey(surface, 1, *(Uint32 *)surface->pixels); 136 break; 137 } 138 } 139 } 140 return surface; 141} 142 143static SDL_Surface *load_image(const char *file) 144{ 145 SDL_Surface *surface = load_image_file(file); 146 if (surface) { 147 /* Add a 2x version of this image, if available */ 148 SDL_Surface *surface2x = NULL; 149 const char *ext = SDL_strrchr(file, '.'); 150 size_t len = SDL_strlen(file) + 2 + 1; 151 char *file2x = (char *)SDL_malloc(len); 152 if (file2x) { 153 SDL_strlcpy(file2x, file, len); 154 if (ext) { 155 SDL_memcpy(file2x + (ext - file), "2x", 3); 156 SDL_strlcat(file2x, ext, len); 157 } else { 158 SDL_strlcat(file2x, "2x", len); 159 } 160 surface2x = load_image_file(file2x); 161 SDL_free(file2x); 162 } 163 if (surface2x) { 164 SDL_AddSurfaceAlternateImage(surface, surface2x); 165 SDL_DestroySurface(surface2x); 166 } 167 } 168 return surface; 169} 170 171static SDL_Cursor *init_color_cursor(const char *file) 172{ 173 SDL_Cursor *cursor = NULL; 174 SDL_Surface *surface = load_image(file); 175 if (surface) { 176 cursor = SDL_CreateColorCursor(surface, 0, 0); 177 SDL_DestroySurface(surface); 178 } 179 return cursor; 180} 181 182static SDL_Cursor *init_system_cursor(const char *image[]) 183{ 184 int i, row, col; 185 Uint8 data[4 * 32]; 186 Uint8 mask[4 * 32]; 187 int hot_x = 0; 188 int hot_y = 0; 189 190 i = -1; 191 for (row = 0; row < 32; ++row) { 192 for (col = 0; col < 32; ++col) { 193 if (col % 8) { 194 data[i] <<= 1; 195 mask[i] <<= 1; 196 } else { 197 ++i; 198 data[i] = mask[i] = 0; 199 } 200 switch (image[4 + row][col]) { 201 case 'X': 202 data[i] |= 0x01; 203 mask[i] |= 0x01; 204 break; 205 case '.': 206 mask[i] |= 0x01; 207 break; 208 case 'o': 209 data[i] |= 0x01; 210 break; 211 case ' ': 212 break; 213 } 214 } 215 } 216 (void)SDL_sscanf(image[4 + row], "%d,%d", &hot_x, &hot_y); 217 return SDL_CreateCursor(data, mask, 32, 32, hot_x, hot_y); 218} 219 220static SDLTest_CommonState *state; 221static int done; 222static SDL_Cursor *cursors[3 + SDL_SYSTEM_CURSOR_COUNT]; 223static SDL_SystemCursor cursor_types[3 + SDL_SYSTEM_CURSOR_COUNT]; 224static int num_cursors; 225static int current_cursor; 226static bool show_cursor; 227 228/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ 229static void 230quit(int rc) 231{ 232 SDLTest_CommonQuit(state); 233 /* Let 'main()' return normally */ 234 if (rc != 0) { 235 exit(rc); 236 } 237} 238 239static void loop(void) 240{ 241 int i; 242 SDL_Event event; 243 /* Check for events */ 244 while (SDL_PollEvent(&event)) { 245 SDLTest_CommonEvent(state, &event, &done); 246 if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { 247 if (event.button.button == SDL_BUTTON_LEFT) { 248 if (num_cursors == 0) { 249 continue; 250 } 251 252 ++current_cursor; 253 if (current_cursor == num_cursors) { 254 current_cursor = 0; 255 } 256 257 SDL_SetCursor(cursors[current_cursor]); 258 259 switch ((int)cursor_types[current_cursor]) { 260 case (SDL_SystemCursor)-1: 261 SDL_Log("Custom cursor"); 262 break; 263 case SDL_SYSTEM_CURSOR_DEFAULT: 264 SDL_Log("Default"); 265 break; 266 case SDL_SYSTEM_CURSOR_TEXT: 267 SDL_Log("Text"); 268 break; 269 case SDL_SYSTEM_CURSOR_WAIT: 270 SDL_Log("Wait"); 271 break; 272 case SDL_SYSTEM_CURSOR_CROSSHAIR: 273 SDL_Log("Crosshair"); 274 break; 275 case SDL_SYSTEM_CURSOR_PROGRESS: 276 SDL_Log("Progress: Small wait cursor (or Wait if not available)"); 277 break; 278 case SDL_SYSTEM_CURSOR_NWSE_RESIZE: 279 SDL_Log("Double arrow pointing northwest and southeast"); 280 break; 281 case SDL_SYSTEM_CURSOR_NESW_RESIZE: 282 SDL_Log("Double arrow pointing northeast and southwest"); 283 break; 284 case SDL_SYSTEM_CURSOR_EW_RESIZE: 285 SDL_Log("Double arrow pointing west and east"); 286 break; 287 case SDL_SYSTEM_CURSOR_NS_RESIZE: 288 SDL_Log("Double arrow pointing north and south"); 289 break; 290 case SDL_SYSTEM_CURSOR_MOVE: 291 SDL_Log("Move: Four pointed arrow pointing north, south, east, and west"); 292 break; 293 case SDL_SYSTEM_CURSOR_NOT_ALLOWED: 294 SDL_Log("Not Allowed: Slashed circle or crossbones"); 295 break; 296 case SDL_SYSTEM_CURSOR_POINTER: 297 SDL_Log("Pointer: Hand"); 298 break; 299 case SDL_SYSTEM_CURSOR_NW_RESIZE: 300 SDL_Log("Window resize top-left"); 301 break; 302 case SDL_SYSTEM_CURSOR_N_RESIZE: 303 SDL_Log("Window resize top"); 304 break; 305 case SDL_SYSTEM_CURSOR_NE_RESIZE: 306 SDL_Log("Window resize top-right"); 307 break; 308 case SDL_SYSTEM_CURSOR_E_RESIZE: 309 SDL_Log("Window resize right"); 310 break; 311 case SDL_SYSTEM_CURSOR_SE_RESIZE: 312 SDL_Log("Window resize bottom-right"); 313 break; 314 case SDL_SYSTEM_CURSOR_S_RESIZE: 315 SDL_Log("Window resize bottom"); 316 break; 317 case SDL_SYSTEM_CURSOR_SW_RESIZE: 318 SDL_Log("Window resize bottom-left"); 319 break; 320 case SDL_SYSTEM_CURSOR_W_RESIZE: 321 SDL_Log("Window resize left"); 322 break; 323 default: 324 SDL_Log("UNKNOWN CURSOR TYPE, FIX THIS PROGRAM."); 325 break; 326 } 327 328 } else { 329 show_cursor = !show_cursor; 330 if (show_cursor) { 331 SDL_ShowCursor(); 332 } else { 333 SDL_HideCursor(); 334 } 335 } 336 } 337 } 338 339 for (i = 0; i < state->num_windows; ++i) { 340 SDL_Renderer *renderer = state->renderers[i]; 341 SDL_FRect rect; 342 int x, y, row; 343 int window_w = 0, window_h = 0; 344 const float scale = SDL_GetWindowPixelDensity(state->windows[i]); 345 346 SDL_GetWindowSizeInPixels(state->windows[i], &window_w, &window_h); 347 rect.w = 128.0f * scale; 348 rect.h = 128.0f * scale; 349 for (y = 0, row = 0; y < window_h; y += (int)rect.h, ++row) { 350 bool black = ((row % 2) == 0) ? true : false; 351 for (x = 0; x < window_w; x += (int)rect.w) { 352 rect.x = (float)x; 353 rect.y = (float)y; 354 355 if (black) { 356 SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF); 357 } else { 358 SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); 359 } 360 SDL_RenderFillRect(renderer, &rect); 361 362 black = !black; 363 } 364 } 365 SDL_RenderPresent(renderer); 366 } 367#ifdef SDL_PLATFORM_EMSCRIPTEN 368 if (done) { 369 emscripten_cancel_main_loop(); 370 } 371#endif 372} 373 374int main(int argc, char *argv[]) 375{ 376 int i; 377 const char *color_cursor = NULL; 378 SDL_Cursor *cursor; 379 380 /* Initialize test framework */ 381 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); 382 if (!state) { 383 return 1; 384 } 385 386 for (i = 1; i < argc;) { 387 int consumed; 388 389 consumed = SDLTest_CommonArg(state, i); 390 if (consumed == 0) { 391 color_cursor = argv[i]; 392 break; 393 } 394 if (consumed < 0) { 395 SDLTest_CommonLogUsage(state, argv[0], NULL); 396 quit(1); 397 } 398 i += consumed; 399 } 400 401 if (!SDLTest_CommonInit(state)) { 402 quit(2); 403 } 404 405 num_cursors = 0; 406 407 if (color_cursor) { 408 SDL_Surface *icon = load_image(color_cursor); 409 if (icon) { 410 for (i = 0; i < state->num_windows; ++i) { 411 SDL_SetWindowIcon(state->windows[i], icon); 412 } 413 SDL_DestroySurface(icon); 414 } 415 416 cursor = init_color_cursor(color_cursor); 417 if (cursor) { 418 cursors[num_cursors] = cursor; 419 cursor_types[num_cursors] = (SDL_SystemCursor)-1; 420 num_cursors++; 421 } 422 } 423 424 cursor = init_system_cursor(arrow); 425 if (cursor) { 426 cursors[num_cursors] = cursor; 427 cursor_types[num_cursors] = (SDL_SystemCursor)-1; 428 num_cursors++; 429 } 430 431 cursor = init_system_cursor(cross); 432 if (cursor) { 433 cursors[num_cursors] = cursor; 434 cursor_types[num_cursors] = (SDL_SystemCursor)-1; 435 num_cursors++; 436 } 437 438 for (i = 0; i < SDL_SYSTEM_CURSOR_COUNT; ++i) { 439 cursor = SDL_CreateSystemCursor((SDL_SystemCursor)i); 440 if (cursor) { 441 cursors[num_cursors] = cursor; 442 cursor_types[num_cursors] = i; 443 num_cursors++; 444 } 445 } 446 447 if (num_cursors > 0) { 448 SDL_SetCursor(cursors[0]); 449 } 450 451 show_cursor = SDL_CursorVisible(); 452 453 /* Main render loop */ 454 done = 0; 455#ifdef SDL_PLATFORM_EMSCRIPTEN 456 emscripten_set_main_loop(loop, 0, 1); 457#else 458 while (!done) { 459 loop(); 460 } 461#endif 462 463 for (i = 0; i < num_cursors; ++i) { 464 SDL_DestroyCursor(cursors[i]); 465 } 466 quit(0); 467 468 /* keep the compiler happy ... */ 469 return 0; 470}