xdraw.c (3946B)
1 #include <GL/gl.h> 2 #include <GLFW/glfw3.h> 3 4 #include <string.h> 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include <stdarg.h> 8 #include <stdbool.h> 9 10 struct point { 11 double x, y; 12 }; 13 14 struct line { 15 struct point *points; 16 size_t count, cap; 17 }; 18 19 static struct line *lines = NULL; 20 static size_t line_count = 0; 21 static size_t line_cap = 0; 22 23 static double cursor_x = 0; 24 static double cursor_y = 0; 25 26 static int window_width = 0; 27 static int window_height = 0; 28 29 static bool drawing = false; 30 31 static void 32 die(const char *fmt, ...) 33 { 34 va_list ap; 35 36 va_start(ap, fmt); 37 fputs("xdraw: ", stderr); 38 vfprintf(stderr, fmt, ap); 39 if (*fmt && fmt[strlen(fmt)] == ':') 40 perror(NULL); 41 else 42 putc('\n', stderr); 43 va_end(ap); 44 45 exit(1); 46 } 47 48 static void * 49 append(void *_array, size_t *count, size_t *cap, size_t size) 50 { 51 uint8_t **array = _array; 52 if (*count == *cap) { 53 if (*cap == 0) *cap = 1; 54 *cap *= 2; 55 *array = realloc(*array, *cap * size); 56 if (!*array) die("realloc:"); 57 } 58 return (void *) (*array + (*count)++ * size); 59 } 60 61 static void 62 glfwerror(int rc, const char *error) 63 { 64 die("glfw error (%i): %s", rc, error); 65 } 66 67 static void 68 onresize(GLFWwindow *window, int width, int height) 69 { 70 window_width = width; 71 window_height = height; 72 glViewport(0, 0, width, height); 73 glClear(GL_COLOR_BUFFER_BIT); 74 glLoadIdentity(); 75 glOrtho(0, width, height, 0, -1, 1); 76 } 77 78 static void 79 onmove(GLFWwindow *window, double x, double y) 80 { 81 cursor_x = x; 82 cursor_y = y; 83 if (drawing && line_count) { 84 struct line *line = &lines[line_count-1]; 85 if (line->count > 0) { 86 struct point *last_point = &line->points[line->count-1]; 87 if (cursor_x == last_point->x && cursor_y == last_point->y) 88 return; 89 } 90 struct point *point = append(&line->points, 91 &line->count, &line->cap, sizeof(struct point)); 92 point->x = cursor_x; 93 point->y = cursor_y; 94 } 95 } 96 97 static void 98 onclick(GLFWwindow *window, int button, int action, int mods) 99 { 100 if (button != GLFW_MOUSE_BUTTON_LEFT) return; 101 102 if (action == GLFW_PRESS) { 103 struct line *line = append(&lines, 104 &line_count, &line_cap, sizeof(struct line)); 105 line->count = line->cap = 0; 106 line->points = NULL; 107 struct point *point = append(&line->points, 108 &line->count, &line->cap, sizeof(struct point)); 109 point->x = cursor_x; 110 point->y = cursor_y; 111 drawing = true; 112 } else if (action == GLFW_RELEASE) { 113 drawing = false; 114 } 115 } 116 117 static void 118 onpress(GLFWwindow *window, int key, int scancode, int action, int mods) 119 { 120 if (action != GLFW_PRESS) return; 121 122 if ((mods & GLFW_MOD_CONTROL) && !strcmp(glfwGetKeyName(key, scancode), "z")) { 123 if (line_count) { 124 line_count -= 1; 125 free(lines[line_count].points); 126 } 127 } else if ((mods & GLFW_MOD_CONTROL) && !strcmp(glfwGetKeyName(key, scancode), "c")) { 128 for (size_t i = 0; i < line_count; i++) 129 free(lines[i].points); 130 line_count = 0; 131 } 132 } 133 134 int 135 main(void) 136 { 137 glfwSetErrorCallback(glfwerror); 138 139 if (!glfwInit()) die("glfwInit"); 140 141 GLFWwindow *window = glfwCreateWindow(640, 480, "xdraw", NULL, NULL); 142 if (!window) die("glfwCreateWindow"); 143 144 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); 145 glfwSetWindowSizeCallback(window, onresize); 146 glfwSetCursorPosCallback(window, onmove); 147 glfwSetMouseButtonCallback(window, onclick); 148 glfwSetKeyCallback(window, onpress); 149 glfwMakeContextCurrent(window); 150 151 glClearColor(0, 0, 0, 0); 152 glColor3f(1, 1, 1); 153 glLineWidth(2); 154 glPointSize(2); 155 156 glfwGetCursorPos(window, &cursor_x, &cursor_y); 157 glfwGetWindowSize(window, &window_width, &window_height); 158 159 onresize(window, window_width, window_height); 160 161 while (!glfwWindowShouldClose(window)) { 162 glClear(GL_COLOR_BUFFER_BIT); 163 164 for (size_t i = 0; i < line_count; i++) { 165 struct line *line = &lines[i]; 166 glBegin(GL_LINE_STRIP); 167 for (size_t k = 0; k < line->count; k++) 168 glVertex2f(line->points[k].x, line->points[k].y); 169 glEnd(); 170 } 171 172 glBegin(GL_POINTS); 173 glVertex2f(cursor_x, cursor_y); 174 glEnd(); 175 176 glfwSwapBuffers(window); 177 178 glfwPollEvents(); 179 } 180 181 glfwTerminate(); 182 }