cursor.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. //========================================================================
  2. // Cursor & input mode tests
  3. // Copyright (c) Camilla Löwy <elmindreda@glfw.org>
  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. #include <glad/gl.h>
  33. #define GLFW_INCLUDE_NONE
  34. #include <GLFW/glfw3.h>
  35. #if defined(_MSC_VER)
  36. // Make MS math.h define M_PI
  37. #define _USE_MATH_DEFINES
  38. #endif
  39. #include <math.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include "linmath.h"
  43. #define CURSOR_FRAME_COUNT 60
  44. static const char* vertex_shader_text =
  45. "#version 110\n"
  46. "uniform mat4 MVP;\n"
  47. "attribute vec2 vPos;\n"
  48. "void main()\n"
  49. "{\n"
  50. " gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n"
  51. "}\n";
  52. static const char* fragment_shader_text =
  53. "#version 110\n"
  54. "void main()\n"
  55. "{\n"
  56. " gl_FragColor = vec4(1.0);\n"
  57. "}\n";
  58. static double cursor_x;
  59. static double cursor_y;
  60. static int swap_interval = 1;
  61. static int wait_events = GLFW_TRUE;
  62. static int animate_cursor = GLFW_FALSE;
  63. static int track_cursor = GLFW_FALSE;
  64. static GLFWcursor* standard_cursors[6];
  65. static GLFWcursor* tracking_cursor = NULL;
  66. static void error_callback(int error, const char* description)
  67. {
  68. fprintf(stderr, "Error: %s\n", description);
  69. }
  70. static float star(int x, int y, float t)
  71. {
  72. const float c = 64 / 2.f;
  73. const float i = (0.25f * (float) sin(2.f * M_PI * t) + 0.75f);
  74. const float k = 64 * 0.046875f * i;
  75. const float dist = (float) sqrt((x - c) * (x - c) + (y - c) * (y - c));
  76. const float salpha = 1.f - dist / c;
  77. const float xalpha = (float) x == c ? c : k / (float) fabs(x - c);
  78. const float yalpha = (float) y == c ? c : k / (float) fabs(y - c);
  79. return (float) fmax(0.f, fmin(1.f, i * salpha * 0.2f + salpha * xalpha * yalpha));
  80. }
  81. static GLFWcursor* create_cursor_frame(float t)
  82. {
  83. int i = 0, x, y;
  84. unsigned char buffer[64 * 64 * 4];
  85. const GLFWimage image = { 64, 64, buffer };
  86. for (y = 0; y < image.width; y++)
  87. {
  88. for (x = 0; x < image.height; x++)
  89. {
  90. buffer[i++] = 255;
  91. buffer[i++] = 255;
  92. buffer[i++] = 255;
  93. buffer[i++] = (unsigned char) (255 * star(x, y, t));
  94. }
  95. }
  96. return glfwCreateCursor(&image, image.width / 2, image.height / 2);
  97. }
  98. static GLFWcursor* create_tracking_cursor(void)
  99. {
  100. int i = 0, x, y;
  101. unsigned char buffer[32 * 32 * 4];
  102. const GLFWimage image = { 32, 32, buffer };
  103. for (y = 0; y < image.width; y++)
  104. {
  105. for (x = 0; x < image.height; x++)
  106. {
  107. if (x == 7 || y == 7)
  108. {
  109. buffer[i++] = 255;
  110. buffer[i++] = 0;
  111. buffer[i++] = 0;
  112. buffer[i++] = 255;
  113. }
  114. else
  115. {
  116. buffer[i++] = 0;
  117. buffer[i++] = 0;
  118. buffer[i++] = 0;
  119. buffer[i++] = 0;
  120. }
  121. }
  122. }
  123. return glfwCreateCursor(&image, 7, 7);
  124. }
  125. static void cursor_position_callback(GLFWwindow* window, double x, double y)
  126. {
  127. printf("%0.3f: Cursor position: %f %f (%+f %+f)\n",
  128. glfwGetTime(),
  129. x, y, x - cursor_x, y - cursor_y);
  130. cursor_x = x;
  131. cursor_y = y;
  132. }
  133. static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
  134. {
  135. if (action != GLFW_PRESS)
  136. return;
  137. switch (key)
  138. {
  139. case GLFW_KEY_A:
  140. {
  141. animate_cursor = !animate_cursor;
  142. if (!animate_cursor)
  143. glfwSetCursor(window, NULL);
  144. break;
  145. }
  146. case GLFW_KEY_ESCAPE:
  147. {
  148. if (glfwGetInputMode(window, GLFW_CURSOR) != GLFW_CURSOR_DISABLED)
  149. {
  150. glfwSetWindowShouldClose(window, GLFW_TRUE);
  151. break;
  152. }
  153. /* FALLTHROUGH */
  154. }
  155. case GLFW_KEY_N:
  156. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
  157. glfwGetCursorPos(window, &cursor_x, &cursor_y);
  158. printf("(( cursor is normal ))\n");
  159. break;
  160. case GLFW_KEY_D:
  161. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
  162. printf("(( cursor is disabled ))\n");
  163. break;
  164. case GLFW_KEY_H:
  165. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
  166. printf("(( cursor is hidden ))\n");
  167. break;
  168. case GLFW_KEY_R:
  169. if (!glfwRawMouseMotionSupported())
  170. break;
  171. if (glfwGetInputMode(window, GLFW_RAW_MOUSE_MOTION))
  172. {
  173. glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE);
  174. printf("(( raw input is disabled ))\n");
  175. }
  176. else
  177. {
  178. glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
  179. printf("(( raw input is enabled ))\n");
  180. }
  181. break;
  182. case GLFW_KEY_SPACE:
  183. swap_interval = 1 - swap_interval;
  184. printf("(( swap interval: %i ))\n", swap_interval);
  185. glfwSwapInterval(swap_interval);
  186. break;
  187. case GLFW_KEY_W:
  188. wait_events = !wait_events;
  189. printf("(( %sing for events ))\n", wait_events ? "wait" : "poll");
  190. break;
  191. case GLFW_KEY_T:
  192. track_cursor = !track_cursor;
  193. if (track_cursor)
  194. glfwSetCursor(window, tracking_cursor);
  195. else
  196. glfwSetCursor(window, NULL);
  197. break;
  198. case GLFW_KEY_P:
  199. {
  200. double x, y;
  201. glfwGetCursorPos(window, &x, &y);
  202. printf("Query before set: %f %f (%+f %+f)\n",
  203. x, y, x - cursor_x, y - cursor_y);
  204. cursor_x = x;
  205. cursor_y = y;
  206. glfwSetCursorPos(window, cursor_x, cursor_y);
  207. glfwGetCursorPos(window, &x, &y);
  208. printf("Query after set: %f %f (%+f %+f)\n",
  209. x, y, x - cursor_x, y - cursor_y);
  210. cursor_x = x;
  211. cursor_y = y;
  212. break;
  213. }
  214. case GLFW_KEY_UP:
  215. glfwSetCursorPos(window, 0, 0);
  216. glfwGetCursorPos(window, &cursor_x, &cursor_y);
  217. break;
  218. case GLFW_KEY_DOWN:
  219. {
  220. int width, height;
  221. glfwGetWindowSize(window, &width, &height);
  222. glfwSetCursorPos(window, width - 1, height - 1);
  223. glfwGetCursorPos(window, &cursor_x, &cursor_y);
  224. break;
  225. }
  226. case GLFW_KEY_0:
  227. glfwSetCursor(window, NULL);
  228. break;
  229. case GLFW_KEY_1:
  230. glfwSetCursor(window, standard_cursors[0]);
  231. break;
  232. case GLFW_KEY_2:
  233. glfwSetCursor(window, standard_cursors[1]);
  234. break;
  235. case GLFW_KEY_3:
  236. glfwSetCursor(window, standard_cursors[2]);
  237. break;
  238. case GLFW_KEY_4:
  239. glfwSetCursor(window, standard_cursors[3]);
  240. break;
  241. case GLFW_KEY_5:
  242. glfwSetCursor(window, standard_cursors[4]);
  243. break;
  244. case GLFW_KEY_6:
  245. glfwSetCursor(window, standard_cursors[5]);
  246. break;
  247. case GLFW_KEY_F11:
  248. case GLFW_KEY_ENTER:
  249. {
  250. static int x, y, width, height;
  251. if (mods != GLFW_MOD_ALT)
  252. return;
  253. if (glfwGetWindowMonitor(window))
  254. glfwSetWindowMonitor(window, NULL, x, y, width, height, 0);
  255. else
  256. {
  257. GLFWmonitor* monitor = glfwGetPrimaryMonitor();
  258. const GLFWvidmode* mode = glfwGetVideoMode(monitor);
  259. glfwGetWindowPos(window, &x, &y);
  260. glfwGetWindowSize(window, &width, &height);
  261. glfwSetWindowMonitor(window, monitor,
  262. 0, 0, mode->width, mode->height,
  263. mode->refreshRate);
  264. }
  265. glfwGetCursorPos(window, &cursor_x, &cursor_y);
  266. break;
  267. }
  268. }
  269. }
  270. int main(void)
  271. {
  272. int i;
  273. GLFWwindow* window;
  274. GLFWcursor* star_cursors[CURSOR_FRAME_COUNT];
  275. GLFWcursor* current_frame = NULL;
  276. GLuint vertex_buffer, vertex_shader, fragment_shader, program;
  277. GLint mvp_location, vpos_location;
  278. glfwSetErrorCallback(error_callback);
  279. if (!glfwInit())
  280. exit(EXIT_FAILURE);
  281. tracking_cursor = create_tracking_cursor();
  282. if (!tracking_cursor)
  283. {
  284. glfwTerminate();
  285. exit(EXIT_FAILURE);
  286. }
  287. for (i = 0; i < CURSOR_FRAME_COUNT; i++)
  288. {
  289. star_cursors[i] = create_cursor_frame(i / (float) CURSOR_FRAME_COUNT);
  290. if (!star_cursors[i])
  291. {
  292. glfwTerminate();
  293. exit(EXIT_FAILURE);
  294. }
  295. }
  296. for (i = 0; i < sizeof(standard_cursors) / sizeof(standard_cursors[0]); i++)
  297. {
  298. const int shapes[] = {
  299. GLFW_ARROW_CURSOR,
  300. GLFW_IBEAM_CURSOR,
  301. GLFW_CROSSHAIR_CURSOR,
  302. GLFW_HAND_CURSOR,
  303. GLFW_HRESIZE_CURSOR,
  304. GLFW_VRESIZE_CURSOR
  305. };
  306. standard_cursors[i] = glfwCreateStandardCursor(shapes[i]);
  307. if (!standard_cursors[i])
  308. {
  309. glfwTerminate();
  310. exit(EXIT_FAILURE);
  311. }
  312. }
  313. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
  314. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
  315. window = glfwCreateWindow(640, 480, "Cursor Test", NULL, NULL);
  316. if (!window)
  317. {
  318. glfwTerminate();
  319. exit(EXIT_FAILURE);
  320. }
  321. glfwMakeContextCurrent(window);
  322. gladLoadGL(glfwGetProcAddress);
  323. glGenBuffers(1, &vertex_buffer);
  324. glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
  325. vertex_shader = glCreateShader(GL_VERTEX_SHADER);
  326. glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
  327. glCompileShader(vertex_shader);
  328. fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
  329. glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
  330. glCompileShader(fragment_shader);
  331. program = glCreateProgram();
  332. glAttachShader(program, vertex_shader);
  333. glAttachShader(program, fragment_shader);
  334. glLinkProgram(program);
  335. mvp_location = glGetUniformLocation(program, "MVP");
  336. vpos_location = glGetAttribLocation(program, "vPos");
  337. glEnableVertexAttribArray(vpos_location);
  338. glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,
  339. sizeof(vec2), (void*) 0);
  340. glUseProgram(program);
  341. glfwGetCursorPos(window, &cursor_x, &cursor_y);
  342. printf("Cursor position: %f %f\n", cursor_x, cursor_y);
  343. glfwSetCursorPosCallback(window, cursor_position_callback);
  344. glfwSetKeyCallback(window, key_callback);
  345. while (!glfwWindowShouldClose(window))
  346. {
  347. glClear(GL_COLOR_BUFFER_BIT);
  348. if (track_cursor)
  349. {
  350. int wnd_width, wnd_height, fb_width, fb_height;
  351. float scale;
  352. vec2 vertices[4];
  353. mat4x4 mvp;
  354. glfwGetWindowSize(window, &wnd_width, &wnd_height);
  355. glfwGetFramebufferSize(window, &fb_width, &fb_height);
  356. glViewport(0, 0, fb_width, fb_height);
  357. scale = (float) fb_width / (float) wnd_width;
  358. vertices[0][0] = 0.5f;
  359. vertices[0][1] = (float) (fb_height - floor(cursor_y * scale) - 1.f + 0.5f);
  360. vertices[1][0] = (float) fb_width + 0.5f;
  361. vertices[1][1] = (float) (fb_height - floor(cursor_y * scale) - 1.f + 0.5f);
  362. vertices[2][0] = (float) floor(cursor_x * scale) + 0.5f;
  363. vertices[2][1] = 0.5f;
  364. vertices[3][0] = (float) floor(cursor_x * scale) + 0.5f;
  365. vertices[3][1] = (float) fb_height + 0.5f;
  366. glBufferData(GL_ARRAY_BUFFER,
  367. sizeof(vertices),
  368. vertices,
  369. GL_STREAM_DRAW);
  370. mat4x4_ortho(mvp, 0.f, (float) fb_width, 0.f, (float) fb_height, 0.f, 1.f);
  371. glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp);
  372. glDrawArrays(GL_LINES, 0, 4);
  373. }
  374. glfwSwapBuffers(window);
  375. if (animate_cursor)
  376. {
  377. const int i = (int) (glfwGetTime() * 30.0) % CURSOR_FRAME_COUNT;
  378. if (current_frame != star_cursors[i])
  379. {
  380. glfwSetCursor(window, star_cursors[i]);
  381. current_frame = star_cursors[i];
  382. }
  383. }
  384. else
  385. current_frame = NULL;
  386. if (wait_events)
  387. {
  388. if (animate_cursor)
  389. glfwWaitEventsTimeout(1.0 / 30.0);
  390. else
  391. glfwWaitEvents();
  392. }
  393. else
  394. glfwPollEvents();
  395. // Workaround for an issue with msvcrt and mintty
  396. fflush(stdout);
  397. }
  398. glfwDestroyWindow(window);
  399. for (i = 0; i < CURSOR_FRAME_COUNT; i++)
  400. glfwDestroyCursor(star_cursors[i]);
  401. for (i = 0; i < sizeof(standard_cursors) / sizeof(standard_cursors[0]); i++)
  402. glfwDestroyCursor(standard_cursors[i]);
  403. glfwTerminate();
  404. exit(EXIT_SUCCESS);
  405. }