ScrapExplorer - cursor.c
Home / ext / glfw / tests Lines: 26 | Size: 14433 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1//======================================================================== 2// Cursor & input mode tests 3// Copyright (c) Camilla Löwy <[email protected]> 4// 5// This software is provided 'as-is', without any express or implied 6// warranty. In no event will the authors be held liable for any damages 7// arising from the use of this software. 8// 9// Permission is granted to anyone to use this software for any purpose, 10// including commercial applications, and to alter it and redistribute it 11// freely, subject to the following restrictions: 12// 13// 1. The origin of this software must not be misrepresented; you must not 14// claim that you wrote the original software. If you use this software 15// in a product, an acknowledgment in the product documentation would 16// be appreciated but is not required. 17// 18// 2. Altered source versions must be plainly marked as such, and must not 19// be misrepresented as being the original software. 20// 21// 3. This notice may not be removed or altered from any source 22// distribution. 23// 24//======================================================================== 25// 26// This test provides an interface to the cursor image and cursor mode 27// parts of the API. 28// 29// Custom cursor image generation by urraka. 30// 31//======================================================================== 32 33#define GLAD_GL_IMPLEMENTATION 34#include <glad/gl.h> 35#define GLFW_INCLUDE_NONE 36#include <GLFW/glfw3.h> 37 38#if defined(_MSC_VER) 39 // Make MS math.h define M_PI 40 #define _USE_MATH_DEFINES 41#endif 42 43#include <math.h> 44#include <stdio.h> 45#include <stdlib.h> 46 47#include "linmath.h" 48 49#define CURSOR_FRAME_COUNT 60 50 51static const char* vertex_shader_text = 52"#version 110\n" 53"uniform mat4 MVP;\n" 54"attribute vec2 vPos;\n" 55"void main()\n" 56"{\n" 57" gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n" 58"}\n"; 59 60static const char* fragment_shader_text = 61"#version 110\n" 62"void main()\n" 63"{\n" 64" gl_FragColor = vec4(1.0);\n" 65"}\n"; 66 67static double cursor_x; 68static double cursor_y; 69static int swap_interval = 1; 70static int wait_events = GLFW_TRUE; 71static int animate_cursor = GLFW_FALSE; 72static int track_cursor = GLFW_FALSE; 73static GLFWcursor* standard_cursors[10]; 74static GLFWcursor* tracking_cursor = NULL; 75 76static void error_callback(int error, const char* description) 77{ 78 fprintf(stderr, "Error: %s\n", description); 79} 80 81static float star(int x, int y, float t) 82{ 83 const float c = 64 / 2.f; 84 85 const float i = (0.25f * (float) sin(2.f * M_PI * t) + 0.75f); 86 const float k = 64 * 0.046875f * i; 87 88 const float dist = (float) sqrt((x - c) * (x - c) + (y - c) * (y - c)); 89 90 const float salpha = 1.f - dist / c; 91 const float xalpha = (float) x == c ? c : k / (float) fabs(x - c); 92 const float yalpha = (float) y == c ? c : k / (float) fabs(y - c); 93 94 return (float) fmax(0.f, fmin(1.f, i * salpha * 0.2f + salpha * xalpha * yalpha)); 95} 96 97static GLFWcursor* create_cursor_frame(float t) 98{ 99 int i = 0, x, y; 100 unsigned char buffer[64 * 64 * 4]; 101 const GLFWimage image = { 64, 64, buffer }; 102 103 for (y = 0; y < image.width; y++) 104 { 105 for (x = 0; x < image.height; x++) 106 { 107 buffer[i++] = 255; 108 buffer[i++] = 255; 109 buffer[i++] = 255; 110 buffer[i++] = (unsigned char) (255 * star(x, y, t)); 111 } 112 } 113 114 return glfwCreateCursor(&image, image.width / 2, image.height / 2); 115} 116 117static GLFWcursor* create_tracking_cursor(void) 118{ 119 int i = 0, x, y; 120 unsigned char buffer[32 * 32 * 4]; 121 const GLFWimage image = { 32, 32, buffer }; 122 123 for (y = 0; y < image.width; y++) 124 { 125 for (x = 0; x < image.height; x++) 126 { 127 if (x == 7 || y == 7) 128 { 129 buffer[i++] = 255; 130 buffer[i++] = 0; 131 buffer[i++] = 0; 132 buffer[i++] = 255; 133 } 134 else 135 { 136 buffer[i++] = 0; 137 buffer[i++] = 0; 138 buffer[i++] = 0; 139 buffer[i++] = 0; 140 } 141 } 142 } 143 144 return glfwCreateCursor(&image, 7, 7); 145} 146 147static void cursor_position_callback(GLFWwindow* window, double x, double y) 148{ 149 printf("%0.3f: Cursor position: %f %f (%+f %+f)\n", 150 glfwGetTime(), 151 x, y, x - cursor_x, y - cursor_y); 152 153 cursor_x = x; 154 cursor_y = y; 155} 156 157static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) 158{ 159 if (action != GLFW_PRESS) 160 return; 161 162 switch (key) 163 { 164 case GLFW_KEY_A: 165 { 166 animate_cursor = !animate_cursor; 167 if (!animate_cursor) 168 glfwSetCursor(window, NULL); 169 170 break; 171 } 172 173 case GLFW_KEY_ESCAPE: 174 { 175 const int mode = glfwGetInputMode(window, GLFW_CURSOR); 176 if (mode != GLFW_CURSOR_DISABLED && mode != GLFW_CURSOR_CAPTURED) 177 { 178 glfwSetWindowShouldClose(window, GLFW_TRUE); 179 break; 180 } 181 182 /* FALLTHROUGH */ 183 } 184 185 case GLFW_KEY_N: 186 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); 187 glfwGetCursorPos(window, &cursor_x, &cursor_y); 188 printf("(( cursor is normal ))\n"); 189 break; 190 191 case GLFW_KEY_D: 192 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); 193 printf("(( cursor is disabled ))\n"); 194 break; 195 196 case GLFW_KEY_H: 197 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); 198 printf("(( cursor is hidden ))\n"); 199 break; 200 201 case GLFW_KEY_C: 202 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_CAPTURED); 203 printf("(( cursor is captured ))\n"); 204 break; 205 206 case GLFW_KEY_R: 207 if (!glfwRawMouseMotionSupported()) 208 break; 209 210 if (glfwGetInputMode(window, GLFW_RAW_MOUSE_MOTION)) 211 { 212 glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE); 213 printf("(( raw input is disabled ))\n"); 214 } 215 else 216 { 217 glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); 218 printf("(( raw input is enabled ))\n"); 219 } 220 break; 221 222 case GLFW_KEY_SPACE: 223 swap_interval = 1 - swap_interval; 224 printf("(( swap interval: %i ))\n", swap_interval); 225 glfwSwapInterval(swap_interval); 226 break; 227 228 case GLFW_KEY_W: 229 wait_events = !wait_events; 230 printf("(( %sing for events ))\n", wait_events ? "wait" : "poll"); 231 break; 232 233 case GLFW_KEY_T: 234 track_cursor = !track_cursor; 235 if (track_cursor) 236 glfwSetCursor(window, tracking_cursor); 237 else 238 glfwSetCursor(window, NULL); 239 240 break; 241 242 case GLFW_KEY_P: 243 { 244 double x, y; 245 glfwGetCursorPos(window, &x, &y); 246 247 printf("Query before set: %f %f (%+f %+f)\n", 248 x, y, x - cursor_x, y - cursor_y); 249 cursor_x = x; 250 cursor_y = y; 251 252 glfwSetCursorPos(window, cursor_x, cursor_y); 253 glfwGetCursorPos(window, &x, &y); 254 255 printf("Query after set: %f %f (%+f %+f)\n", 256 x, y, x - cursor_x, y - cursor_y); 257 cursor_x = x; 258 cursor_y = y; 259 break; 260 } 261 262 case GLFW_KEY_UP: 263 glfwSetCursorPos(window, 0, 0); 264 glfwGetCursorPos(window, &cursor_x, &cursor_y); 265 break; 266 267 case GLFW_KEY_DOWN: 268 { 269 int width, height; 270 glfwGetWindowSize(window, &width, &height); 271 glfwSetCursorPos(window, width - 1, height - 1); 272 glfwGetCursorPos(window, &cursor_x, &cursor_y); 273 break; 274 } 275 276 case GLFW_KEY_0: 277 glfwSetCursor(window, NULL); 278 break; 279 280 case GLFW_KEY_1: 281 case GLFW_KEY_2: 282 case GLFW_KEY_3: 283 case GLFW_KEY_4: 284 case GLFW_KEY_5: 285 case GLFW_KEY_6: 286 case GLFW_KEY_7: 287 case GLFW_KEY_8: 288 case GLFW_KEY_9: 289 { 290 int index = key - GLFW_KEY_1; 291 if (mods & GLFW_MOD_SHIFT) 292 index += 9; 293 294 if (index < sizeof(standard_cursors) / sizeof(standard_cursors[0])) 295 glfwSetCursor(window, standard_cursors[index]); 296 297 break; 298 } 299 300 case GLFW_KEY_F11: 301 case GLFW_KEY_ENTER: 302 { 303 static int x, y, width, height; 304 305 if (mods != GLFW_MOD_ALT) 306 return; 307 308 if (glfwGetWindowMonitor(window)) 309 glfwSetWindowMonitor(window, NULL, x, y, width, height, 0); 310 else 311 { 312 GLFWmonitor* monitor = glfwGetPrimaryMonitor(); 313 const GLFWvidmode* mode = glfwGetVideoMode(monitor); 314 glfwGetWindowPos(window, &x, &y); 315 glfwGetWindowSize(window, &width, &height); 316 glfwSetWindowMonitor(window, monitor, 317 0, 0, mode->width, mode->height, 318 mode->refreshRate); 319 } 320 321 glfwGetCursorPos(window, &cursor_x, &cursor_y); 322 break; 323 } 324 } 325} 326 327int main(void) 328{ 329 int i; 330 GLFWwindow* window; 331 GLFWcursor* star_cursors[CURSOR_FRAME_COUNT]; 332 GLFWcursor* current_frame = NULL; 333 GLuint vertex_buffer, vertex_shader, fragment_shader, program; 334 GLint mvp_location, vpos_location; 335 336 glfwSetErrorCallback(error_callback); 337 338 if (!glfwInit()) 339 exit(EXIT_FAILURE); 340 341 tracking_cursor = create_tracking_cursor(); 342 if (!tracking_cursor) 343 { 344 glfwTerminate(); 345 exit(EXIT_FAILURE); 346 } 347 348 for (i = 0; i < CURSOR_FRAME_COUNT; i++) 349 { 350 star_cursors[i] = create_cursor_frame(i / (float) CURSOR_FRAME_COUNT); 351 if (!star_cursors[i]) 352 { 353 glfwTerminate(); 354 exit(EXIT_FAILURE); 355 } 356 } 357 358 for (i = 0; i < sizeof(standard_cursors) / sizeof(standard_cursors[0]); i++) 359 { 360 const int shapes[] = { 361 GLFW_ARROW_CURSOR, 362 GLFW_IBEAM_CURSOR, 363 GLFW_CROSSHAIR_CURSOR, 364 GLFW_POINTING_HAND_CURSOR, 365 GLFW_RESIZE_EW_CURSOR, 366 GLFW_RESIZE_NS_CURSOR, 367 GLFW_RESIZE_NWSE_CURSOR, 368 GLFW_RESIZE_NESW_CURSOR, 369 GLFW_RESIZE_ALL_CURSOR, 370 GLFW_NOT_ALLOWED_CURSOR 371 }; 372 373 standard_cursors[i] = glfwCreateStandardCursor(shapes[i]); 374 } 375 376 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); 377 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); 378 379 window = glfwCreateWindow(640, 480, "Cursor Test", NULL, NULL); 380 if (!window) 381 { 382 glfwTerminate(); 383 exit(EXIT_FAILURE); 384 } 385 386 glfwMakeContextCurrent(window); 387 gladLoadGL(glfwGetProcAddress); 388 389 glGenBuffers(1, &vertex_buffer); 390 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); 391 392 vertex_shader = glCreateShader(GL_VERTEX_SHADER); 393 glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL); 394 glCompileShader(vertex_shader); 395 396 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 397 glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL); 398 glCompileShader(fragment_shader); 399 400 program = glCreateProgram(); 401 glAttachShader(program, vertex_shader); 402 glAttachShader(program, fragment_shader); 403 glLinkProgram(program); 404 405 mvp_location = glGetUniformLocation(program, "MVP"); 406 vpos_location = glGetAttribLocation(program, "vPos"); 407 408 glEnableVertexAttribArray(vpos_location); 409 glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE, 410 sizeof(vec2), (void*) 0); 411 glUseProgram(program); 412 413 glfwGetCursorPos(window, &cursor_x, &cursor_y); 414 printf("Cursor position: %f %f\n", cursor_x, cursor_y); 415 416 glfwSetCursorPosCallback(window, cursor_position_callback); 417 glfwSetKeyCallback(window, key_callback); 418 419 while (!glfwWindowShouldClose(window)) 420 { 421 glClear(GL_COLOR_BUFFER_BIT); 422 423 if (track_cursor) 424 { 425 int wnd_width, wnd_height, fb_width, fb_height; 426 float scale; 427 vec2 vertices[4]; 428 mat4x4 mvp; 429 430 glfwGetWindowSize(window, &wnd_width, &wnd_height); 431 glfwGetFramebufferSize(window, &fb_width, &fb_height); 432 433 glViewport(0, 0, fb_width, fb_height); 434 435 scale = (float) fb_width / (float) wnd_width; 436 vertices[0][0] = 0.5f; 437 vertices[0][1] = (float) (fb_height - floor(cursor_y * scale) - 1.f + 0.5f); 438 vertices[1][0] = (float) fb_width + 0.5f; 439 vertices[1][1] = (float) (fb_height - floor(cursor_y * scale) - 1.f + 0.5f); 440 vertices[2][0] = (float) floor(cursor_x * scale) + 0.5f; 441 vertices[2][1] = 0.5f; 442 vertices[3][0] = (float) floor(cursor_x * scale) + 0.5f; 443 vertices[3][1] = (float) fb_height + 0.5f; 444 445 glBufferData(GL_ARRAY_BUFFER, 446 sizeof(vertices), 447 vertices, 448 GL_STREAM_DRAW); 449 450 mat4x4_ortho(mvp, 0.f, (float) fb_width, 0.f, (float) fb_height, 0.f, 1.f); 451 glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp); 452 453 glDrawArrays(GL_LINES, 0, 4); 454 } 455 456 glfwSwapBuffers(window); 457 458 if (animate_cursor) 459 { 460 const int i = (int) (glfwGetTime() * 30.0) % CURSOR_FRAME_COUNT; 461 if (current_frame != star_cursors[i]) 462 { 463 glfwSetCursor(window, star_cursors[i]); 464 current_frame = star_cursors[i]; 465 } 466 } 467 else 468 current_frame = NULL; 469 470 if (wait_events) 471 { 472 if (animate_cursor) 473 glfwWaitEventsTimeout(1.0 / 30.0); 474 else 475 glfwWaitEvents(); 476 } 477 else 478 glfwPollEvents(); 479 480 // Workaround for an issue with msvcrt and mintty 481 fflush(stdout); 482 } 483 484 glfwDestroyWindow(window); 485 486 for (i = 0; i < CURSOR_FRAME_COUNT; i++) 487 glfwDestroyCursor(star_cursors[i]); 488 489 for (i = 0; i < sizeof(standard_cursors) / sizeof(standard_cursors[0]); i++) 490 glfwDestroyCursor(standard_cursors[i]); 491 492 glfwTerminate(); 493 exit(EXIT_SUCCESS); 494} 495 496[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.