diff options
Diffstat (limited to 'contrib/SDL-3.2.8/test/testpen.c')
| -rw-r--r-- | contrib/SDL-3.2.8/test/testpen.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/test/testpen.c b/contrib/SDL-3.2.8/test/testpen.c new file mode 100644 index 0000000..bb6e7d2 --- /dev/null +++ b/contrib/SDL-3.2.8/test/testpen.c | |||
| @@ -0,0 +1,287 @@ | |||
| 1 | /* | ||
| 2 | Copyright (C) 1997-2025 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 | #define SDL_MAIN_USE_CALLBACKS 1 | ||
| 14 | #include <SDL3/SDL_main.h> | ||
| 15 | #include <SDL3/SDL_test.h> | ||
| 16 | #include <SDL3/SDL_test_common.h> | ||
| 17 | |||
| 18 | typedef struct Pen | ||
| 19 | { | ||
| 20 | SDL_PenID pen; | ||
| 21 | Uint8 r, g, b; | ||
| 22 | float axes[SDL_PEN_AXIS_COUNT]; | ||
| 23 | float x; | ||
| 24 | float y; | ||
| 25 | Uint32 buttons; | ||
| 26 | bool eraser; | ||
| 27 | bool touching; | ||
| 28 | struct Pen *next; | ||
| 29 | } Pen; | ||
| 30 | |||
| 31 | static SDL_Renderer *renderer = NULL; | ||
| 32 | static SDLTest_CommonState *state = NULL; | ||
| 33 | static SDL_Texture *white_pixel = NULL; | ||
| 34 | static Pen pens; | ||
| 35 | |||
| 36 | |||
| 37 | SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) | ||
| 38 | { | ||
| 39 | int i; | ||
| 40 | |||
| 41 | SDL_srand(0); | ||
| 42 | |||
| 43 | /* Initialize test framework */ | ||
| 44 | state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); | ||
| 45 | if (!state) { | ||
| 46 | return SDL_APP_FAILURE; | ||
| 47 | } | ||
| 48 | |||
| 49 | /* Parse commandline */ | ||
| 50 | for (i = 1; i < argc;) { | ||
| 51 | int consumed = SDLTest_CommonArg(state, i); | ||
| 52 | if (consumed <= 0) { | ||
| 53 | static const char *options[] = { | ||
| 54 | NULL, | ||
| 55 | }; | ||
| 56 | SDLTest_CommonLogUsage(state, argv[0], options); | ||
| 57 | SDL_Quit(); | ||
| 58 | SDLTest_CommonDestroyState(state); | ||
| 59 | return 1; | ||
| 60 | } | ||
| 61 | i += consumed; | ||
| 62 | } | ||
| 63 | |||
| 64 | state->num_windows = 1; | ||
| 65 | |||
| 66 | /* Load the SDL library */ | ||
| 67 | if (!SDLTest_CommonInit(state)) { | ||
| 68 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); | ||
| 69 | return SDL_APP_FAILURE; | ||
| 70 | } | ||
| 71 | |||
| 72 | SDL_SetLogPriorities(SDL_LOG_PRIORITY_VERBOSE); | ||
| 73 | |||
| 74 | renderer = state->renderers[0]; | ||
| 75 | if (!renderer) { | ||
| 76 | /* SDL_Log("Couldn't create renderer: %s", SDL_GetError()); */ | ||
| 77 | return SDL_APP_FAILURE; | ||
| 78 | } | ||
| 79 | |||
| 80 | white_pixel = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, 16, 16); | ||
| 81 | if (!white_pixel) { | ||
| 82 | SDL_Log("Couldn't create white_pixel texture: %s", SDL_GetError()); | ||
| 83 | return SDL_APP_FAILURE; | ||
| 84 | } else { | ||
| 85 | const SDL_Rect rect = { 0, 0, 16, 16 }; | ||
| 86 | Uint32 pixels[16 * 16]; | ||
| 87 | SDL_memset(pixels, 0xFF, sizeof (pixels)); | ||
| 88 | SDL_UpdateTexture(white_pixel, &rect, pixels, 16 * sizeof (Uint32)); | ||
| 89 | } | ||
| 90 | |||
| 91 | SDL_HideCursor(); | ||
| 92 | |||
| 93 | return SDL_APP_CONTINUE; | ||
| 94 | } | ||
| 95 | |||
| 96 | static Pen *FindPen(SDL_PenID which) | ||
| 97 | { | ||
| 98 | Pen *i; | ||
| 99 | for (i = pens.next; i != NULL; i = i->next) { | ||
| 100 | if (i->pen == which) { | ||
| 101 | return i; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | return NULL; | ||
| 105 | } | ||
| 106 | |||
| 107 | SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) | ||
| 108 | { | ||
| 109 | Pen *pen = NULL; | ||
| 110 | |||
| 111 | switch (event->type) { | ||
| 112 | case SDL_EVENT_PEN_PROXIMITY_IN: { | ||
| 113 | pen = (Pen *) SDL_calloc(1, sizeof (*pen)); | ||
| 114 | if (!pen) { | ||
| 115 | SDL_Log("Out of memory!"); | ||
| 116 | return SDL_APP_FAILURE; | ||
| 117 | } | ||
| 118 | |||
| 119 | SDL_Log("Pen %" SDL_PRIu32 " enters proximity!", event->pproximity.which); | ||
| 120 | pen->pen = event->pproximity.which; | ||
| 121 | pen->r = (Uint8) SDL_rand(256); | ||
| 122 | pen->g = (Uint8) SDL_rand(256); | ||
| 123 | pen->b = (Uint8) SDL_rand(256); | ||
| 124 | pen->x = 320.0f; | ||
| 125 | pen->y = 240.0f; | ||
| 126 | pen->next = pens.next; | ||
| 127 | pens.next = pen; | ||
| 128 | |||
| 129 | return SDL_APP_CONTINUE; | ||
| 130 | } | ||
| 131 | |||
| 132 | case SDL_EVENT_PEN_PROXIMITY_OUT: { | ||
| 133 | Pen *prev = &pens; | ||
| 134 | Pen *i; | ||
| 135 | |||
| 136 | SDL_Log("Pen %" SDL_PRIu32 " leaves proximity!", event->pproximity.which); | ||
| 137 | for (i = pens.next; i != NULL; i = i->next) { | ||
| 138 | if (i->pen == event->pproximity.which) { | ||
| 139 | prev->next = i->next; | ||
| 140 | SDL_free(i); | ||
| 141 | break; | ||
| 142 | } | ||
| 143 | prev = i; | ||
| 144 | } | ||
| 145 | |||
| 146 | return SDL_APP_CONTINUE; | ||
| 147 | } | ||
| 148 | |||
| 149 | case SDL_EVENT_PEN_DOWN: | ||
| 150 | /*SDL_Log("Pen %" SDL_PRIu32 " down!", event->ptouch.which);*/ | ||
| 151 | pen = FindPen(event->ptouch.which); | ||
| 152 | if (pen) { | ||
| 153 | pen->touching = true; | ||
| 154 | pen->eraser = (event->ptouch.eraser != 0); | ||
| 155 | } | ||
| 156 | return SDL_APP_CONTINUE; | ||
| 157 | |||
| 158 | case SDL_EVENT_PEN_UP: | ||
| 159 | /*SDL_Log("Pen %" SDL_PRIu32 " up!", event->ptouch.which);*/ | ||
| 160 | pen = FindPen(event->ptouch.which); | ||
| 161 | if (pen) { | ||
| 162 | pen->touching = false; | ||
| 163 | pen->axes[SDL_PEN_AXIS_PRESSURE] = 0.0f; | ||
| 164 | } | ||
| 165 | return SDL_APP_CONTINUE; | ||
| 166 | |||
| 167 | case SDL_EVENT_PEN_BUTTON_DOWN: | ||
| 168 | /*SDL_Log("Pen %" SDL_PRIu32 " button %d down!", event->pbutton.which, (int) event->pbutton.button);*/ | ||
| 169 | pen = FindPen(event->ptouch.which); | ||
| 170 | if (pen) { | ||
| 171 | pen->buttons |= (1 << (event->pbutton.button-1)); | ||
| 172 | } | ||
| 173 | return SDL_APP_CONTINUE; | ||
| 174 | |||
| 175 | case SDL_EVENT_PEN_BUTTON_UP: | ||
| 176 | /*SDL_Log("Pen %" SDL_PRIu32 " button %d up!", event->pbutton.which, (int) event->pbutton.button);*/ | ||
| 177 | pen = FindPen(event->ptouch.which); | ||
| 178 | if (pen) { | ||
| 179 | pen->buttons &= ~(1 << (event->pbutton.button-1)); | ||
| 180 | } | ||
| 181 | return SDL_APP_CONTINUE; | ||
| 182 | |||
| 183 | case SDL_EVENT_PEN_MOTION: | ||
| 184 | /*SDL_Log("Pen %" SDL_PRIu32 " moved to (%f,%f)!", event->pmotion.which, event->pmotion.x, event->pmotion.y);*/ | ||
| 185 | pen = FindPen(event->ptouch.which); | ||
| 186 | if (pen) { | ||
| 187 | pen->x = event->pmotion.x; | ||
| 188 | pen->y = event->pmotion.y; | ||
| 189 | } | ||
| 190 | return SDL_APP_CONTINUE; | ||
| 191 | |||
| 192 | case SDL_EVENT_PEN_AXIS: | ||
| 193 | /*SDL_Log("Pen %" SDL_PRIu32 " axis %d is now %f!", event->paxis.which, (int) event->paxis.axis, event->paxis.value);*/ | ||
| 194 | pen = FindPen(event->ptouch.which); | ||
| 195 | if (pen && (event->paxis.axis < SDL_arraysize(pen->axes))) { | ||
| 196 | pen->axes[event->paxis.axis] = event->paxis.value; | ||
| 197 | } | ||
| 198 | return SDL_APP_CONTINUE; | ||
| 199 | |||
| 200 | case SDL_EVENT_KEY_DOWN: { | ||
| 201 | const SDL_Keycode sym = event->key.key; | ||
| 202 | if (sym == SDLK_ESCAPE || sym == SDLK_AC_BACK) { | ||
| 203 | SDL_Log("Key : Escape!"); | ||
| 204 | return SDL_APP_SUCCESS; | ||
| 205 | } | ||
| 206 | break; | ||
| 207 | } | ||
| 208 | |||
| 209 | case SDL_EVENT_QUIT: | ||
| 210 | return SDL_APP_SUCCESS; | ||
| 211 | |||
| 212 | default: | ||
| 213 | break; | ||
| 214 | } | ||
| 215 | |||
| 216 | return SDLTest_CommonEventMainCallbacks(state, event); | ||
| 217 | } | ||
| 218 | |||
| 219 | static void DrawOnePen(Pen *pen, int num) | ||
| 220 | { | ||
| 221 | int i; | ||
| 222 | |||
| 223 | /* draw button presses for this pen. A square for each in the pen's color, offset down the screen so they don't overlap. */ | ||
| 224 | SDL_SetRenderDrawColor(renderer, pen->r, pen->g, pen->b, 255); | ||
| 225 | for (i = 0; i < 8; i++) { /* we assume you don't have more than 8 buttons atm... */ | ||
| 226 | if (pen->buttons & (1 << i)) { | ||
| 227 | const SDL_FRect rect = { 30.0f * ((float) i), ((float) num) * 30.0f, 30.0f, 30.0f }; | ||
| 228 | SDL_RenderFillRect(renderer, &rect); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | /* draw a square to represent pressure. Always green for eraser and blue for pen */ | ||
| 233 | /* we do this with a texture, so we can trivially rotate it, which SDL_RenderFillRect doesn't offer. */ | ||
| 234 | if (pen->axes[SDL_PEN_AXIS_PRESSURE] > 0.0f) { | ||
| 235 | const float size = (150.0f * pen->axes[SDL_PEN_AXIS_PRESSURE]) + 20.0f; | ||
| 236 | const float halfsize = size / 2.0f; | ||
| 237 | const SDL_FRect rect = { pen->x - halfsize, pen->y - halfsize, size, size }; | ||
| 238 | const SDL_FPoint center = { halfsize, halfsize }; | ||
| 239 | if (pen->eraser) { | ||
| 240 | SDL_SetTextureColorMod(white_pixel, 0, 255, 0); | ||
| 241 | } else { | ||
| 242 | SDL_SetTextureColorMod(white_pixel, 0, 0, 255); | ||
| 243 | } | ||
| 244 | SDL_RenderTextureRotated(renderer, white_pixel, NULL, &rect, pen->axes[SDL_PEN_AXIS_ROTATION], ¢er, SDL_FLIP_NONE); | ||
| 245 | } | ||
| 246 | |||
| 247 | /* draw a little square for position in the center of the pressure, with the pen-specific color. */ | ||
| 248 | { | ||
| 249 | const float distance = pen->touching ? 0.0f : SDL_clamp(pen->axes[SDL_PEN_AXIS_DISTANCE], 0.0f, 1.0f); | ||
| 250 | const float size = 10 + (30.0f * (1.0f - distance)); | ||
| 251 | const float halfsize = size / 2.0f; | ||
| 252 | const SDL_FRect rect = { pen->x - halfsize, pen->y - halfsize, size, size }; | ||
| 253 | const SDL_FPoint center = { halfsize, halfsize }; | ||
| 254 | SDL_SetTextureColorMod(white_pixel, pen->r, pen->g, pen->b); | ||
| 255 | SDL_RenderTextureRotated(renderer, white_pixel, NULL, &rect, pen->axes[SDL_PEN_AXIS_ROTATION], ¢er, SDL_FLIP_NONE); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | SDL_AppResult SDL_AppIterate(void *appstate) | ||
| 260 | { | ||
| 261 | int num = 0; | ||
| 262 | Pen *pen; | ||
| 263 | |||
| 264 | SDL_SetRenderDrawColor(renderer, 0x99, 0x99, 0x99, 255); | ||
| 265 | SDL_RenderClear(renderer); | ||
| 266 | |||
| 267 | for (pen = pens.next; pen != NULL; pen = pen->next, num++) { | ||
| 268 | DrawOnePen(pen, num); | ||
| 269 | } | ||
| 270 | |||
| 271 | SDL_RenderPresent(renderer); | ||
| 272 | |||
| 273 | return SDL_APP_CONTINUE; | ||
| 274 | } | ||
| 275 | |||
| 276 | void SDL_AppQuit(void *appstate, SDL_AppResult result) | ||
| 277 | { | ||
| 278 | Pen *i, *next; | ||
| 279 | for (i = pens.next; i != NULL; i = next) { | ||
| 280 | next = i->next; | ||
| 281 | SDL_free(i); | ||
| 282 | } | ||
| 283 | pens.next = NULL; | ||
| 284 | SDL_DestroyTexture(white_pixel); | ||
| 285 | SDLTest_CommonQuit(state); | ||
| 286 | } | ||
| 287 | |||
