xdraw

Simple drawing app
git clone https://git.sinitax.com/sinitax/xdraw
Log | Files | Refs | sfeed.txt

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 }