Simple Directmedia Layer
at main 9.5 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.h> 14#include <SDL3/SDL_main.h> 15#include <SDL3/SDL_test.h> 16 17#ifdef SDL_PLATFORM_EMSCRIPTEN 18#include <emscripten/emscripten.h> 19#endif 20 21#include <stdlib.h> /* exit() */ 22 23#ifdef SDL_PLATFORM_3DS 24/* For mouse-based tests, we want to have the window on the touch screen */ 25#define SCREEN_X 40 26#define SCREEN_Y 240 27#define SCREEN_WIDTH 320 28#define SCREEN_HEIGHT 240 29#elif defined(SDL_PLATFORM_IOS) 30#define SCREEN_WIDTH 320 31#define SCREEN_HEIGHT 480 32#else 33#define SCREEN_WIDTH 640 34#define SCREEN_HEIGHT 480 35#endif 36 37static SDL_Window *window; 38 39typedef struct _Object 40{ 41 struct _Object *next; 42 43 float x1, y1, x2, y2; 44 Uint8 r, g, b; 45 46 bool isRect; 47} Object; 48 49static Object *active = NULL; 50static Object *objects = NULL; 51static int buttons = 0; 52static bool isRect = false; 53 54static bool wheel_x_active = false; 55static bool wheel_y_active = false; 56static float wheel_x = SCREEN_WIDTH * 0.5f; 57static float wheel_y = SCREEN_HEIGHT * 0.5f; 58 59struct mouse_loop_data { 60 bool done; 61 SDL_Renderer *renderer; 62}; 63 64static void DrawObject(SDL_Renderer *renderer, Object *object) 65{ 66 SDL_SetRenderDrawColor(renderer, object->r, object->g, object->b, 255); 67 68 if (object->isRect) { 69 SDL_FRect rect; 70 71 if (object->x1 > object->x2) { 72 rect.x = object->x2; 73 rect.w = object->x1 - object->x2; 74 } else { 75 rect.x = object->x1; 76 rect.w = object->x2 - object->x1; 77 } 78 79 if (object->y1 > object->y2) { 80 rect.y = object->y2; 81 rect.h = object->y1 - object->y2; 82 } else { 83 rect.y = object->y1; 84 rect.h = object->y2 - object->y1; 85 } 86 87 SDL_RenderFillRect(renderer, &rect); 88 } else { 89 SDL_RenderLine(renderer, object->x1, object->y1, object->x2, object->y2); 90 } 91} 92 93static void DrawObjects(SDL_Renderer *renderer) 94{ 95 Object *next = objects; 96 while (next) { 97 DrawObject(renderer, next); 98 next = next->next; 99 } 100} 101 102static void AppendObject(Object *object) 103{ 104 if (objects) { 105 Object *next = objects; 106 while (next->next) { 107 next = next->next; 108 } 109 next->next = object; 110 } else { 111 objects = object; 112 } 113} 114 115static void loop(void *arg) 116{ 117 struct mouse_loop_data *loop_data = (struct mouse_loop_data *)arg; 118 SDL_Event event; 119 SDL_Renderer *renderer = loop_data->renderer; 120 121 /* Check for events */ 122 while (SDL_PollEvent(&event)) { 123 switch (event.type) { 124 case SDL_EVENT_MOUSE_WHEEL: 125 if (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED) { 126 event.wheel.x *= -1; 127 event.wheel.y *= -1; 128 } 129 if (event.wheel.x != 0.0f) { 130 wheel_x_active = true; 131 /* "positive to the right and negative to the left" */ 132 wheel_x += event.wheel.x * 10.0f; 133 } 134 if (event.wheel.y != 0.0f) { 135 wheel_y_active = true; 136 /* "positive away from the user and negative towards the user" */ 137 wheel_y -= event.wheel.y * 10.0f; 138 } 139 break; 140 141 case SDL_EVENT_MOUSE_MOTION: 142 if (!active) { 143 break; 144 } 145 146 active->x2 = event.motion.x; 147 active->y2 = event.motion.y; 148 break; 149 150 case SDL_EVENT_MOUSE_BUTTON_DOWN: 151 if (!active) { 152 active = SDL_calloc(1, sizeof(*active)); 153 active->x1 = active->x2 = event.button.x; 154 active->y1 = active->y2 = event.button.y; 155 active->isRect = isRect; 156 } 157 158 switch (event.button.button) { 159 case SDL_BUTTON_LEFT: 160 active->r = 255; 161 buttons |= SDL_BUTTON_LMASK; 162 break; 163 case SDL_BUTTON_MIDDLE: 164 active->g = 255; 165 buttons |= SDL_BUTTON_MMASK; 166 break; 167 case SDL_BUTTON_RIGHT: 168 active->b = 255; 169 buttons |= SDL_BUTTON_RMASK; 170 break; 171 case SDL_BUTTON_X1: 172 active->r = 255; 173 active->b = 255; 174 buttons |= SDL_BUTTON_X1MASK; 175 break; 176 case SDL_BUTTON_X2: 177 active->g = 255; 178 active->b = 255; 179 buttons |= SDL_BUTTON_X2MASK; 180 break; 181 } 182 break; 183 184 case SDL_EVENT_MOUSE_BUTTON_UP: 185 if (!active) { 186 break; 187 } 188 189 switch (event.button.button) { 190 case SDL_BUTTON_LEFT: 191 buttons &= ~SDL_BUTTON_LMASK; 192 break; 193 case SDL_BUTTON_MIDDLE: 194 buttons &= ~SDL_BUTTON_MMASK; 195 break; 196 case SDL_BUTTON_RIGHT: 197 buttons &= ~SDL_BUTTON_RMASK; 198 break; 199 case SDL_BUTTON_X1: 200 buttons &= ~SDL_BUTTON_X1MASK; 201 break; 202 case SDL_BUTTON_X2: 203 buttons &= ~SDL_BUTTON_X2MASK; 204 break; 205 } 206 207 if (buttons == 0) { 208 AppendObject(active); 209 active = NULL; 210 } 211 break; 212 213 case SDL_EVENT_KEY_DOWN: 214 if (event.key.key == SDLK_C) { 215 int x, y, w, h; 216 SDL_GetWindowPosition(window, &x, &y); 217 SDL_GetWindowSize(window, &w, &h); 218 w /= 2; 219 h /= 2; 220 221 if (event.key.mod & SDL_KMOD_ALT) { 222 SDL_WarpMouseGlobal((float)(x + w), (float)(y + h)); 223 } else { 224 SDL_WarpMouseInWindow(window, (float)w, (float)h); 225 } 226 } 227 SDL_FALLTHROUGH; 228 case SDL_EVENT_KEY_UP: 229 switch (event.key.key) { 230 case SDLK_LSHIFT: 231 isRect = event.key.down; 232 if (active) { 233 active->isRect = isRect; 234 } 235 break; 236 default: 237 break; 238 } 239 break; 240 241 case SDL_EVENT_QUIT: 242 loop_data->done = true; 243 break; 244 245 default: 246 break; 247 } 248 } 249 250 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); 251 SDL_RenderClear(renderer); 252 253 /* Mouse wheel */ 254 SDL_SetRenderDrawColor(renderer, 0, 255, 128, 255); 255 if (wheel_x_active) { 256 SDL_RenderLine(renderer, wheel_x, 0.0f, wheel_x, (float)SCREEN_HEIGHT); 257 } 258 if (wheel_y_active) { 259 SDL_RenderLine(renderer, 0.0f, wheel_y, (float)SCREEN_WIDTH, wheel_y); 260 } 261 262 /* Objects from mouse clicks */ 263 DrawObjects(renderer); 264 if (active) { 265 DrawObject(renderer, active); 266 } 267 268 SDL_RenderPresent(renderer); 269 270#ifdef SDL_PLATFORM_EMSCRIPTEN 271 if (loop_data->done) { 272 emscripten_cancel_main_loop(); 273 } 274#endif 275} 276 277int main(int argc, char *argv[]) 278{ 279 struct mouse_loop_data loop_data; 280 SDLTest_CommonState *state; 281#ifdef SDL_PLATFORM_3DS 282 SDL_PropertiesID props; 283#endif 284 285 /* Initialize test framework */ 286 state = SDLTest_CommonCreateState(argv, 0); 287 if (!state) { 288 return 1; 289 } 290 291 /* Parse commandline */ 292 if (!SDLTest_CommonDefaultArgs(state, argc, argv)) { 293 return 1; 294 } 295 296 /* Initialize SDL (Note: video is required to start event loop) */ 297 if (!SDL_Init(SDL_INIT_VIDEO)) { 298 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); 299 exit(1); 300 } 301 302 /* Create a window to display joystick axis position */ 303#ifdef SDL_PLATFORM_3DS 304 props = SDL_CreateProperties(); 305 SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, "Mouse Test"); 306 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SCREEN_X); 307 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SCREEN_Y); 308 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, SCREEN_WIDTH); 309 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, SCREEN_HEIGHT); 310 SDL_SetNumberProperty(props, "flags", 0); 311 window = SDL_CreateWindowWithProperties(props); 312#else 313 window = SDL_CreateWindow("Mouse Test", SCREEN_WIDTH, SCREEN_HEIGHT, 0); 314#endif 315 if (!window) { 316 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError()); 317 return 0; 318 } 319 320 loop_data.done = false; 321 322 loop_data.renderer = SDL_CreateRenderer(window, NULL); 323 if (!loop_data.renderer) { 324 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError()); 325 SDL_DestroyWindow(window); 326 return 0; 327 } 328 329 /* Main render loop */ 330#ifdef SDL_PLATFORM_EMSCRIPTEN 331 emscripten_set_main_loop_arg(loop, &loop_data, 0, 1); 332#else 333 while (loop_data.done == false) { 334 loop(&loop_data); 335 } 336#endif 337 338 SDL_DestroyRenderer(loop_data.renderer); 339 SDL_DestroyWindow(window); 340 341 SDL_Quit(); 342 SDLTest_CommonDestroyState(state); 343 344 return 0; 345}