sdraw

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

sdraw.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
     10struct point {
     11	double x, y;
     12};
     13
     14struct line {
     15	struct point *points;
     16	size_t count, cap;
     17};
     18
     19static struct line *lines = NULL;
     20static size_t line_count = 0;
     21static size_t line_cap = 0;
     22
     23static double cursor_x = 0;
     24static double cursor_y = 0;
     25
     26static int window_width = 0;
     27static int window_height = 0;
     28
     29static bool drawing = false;
     30
     31static void
     32die(const char *fmt, ...)
     33{
     34	va_list ap;
     35
     36	va_start(ap, fmt);
     37	fputs("sdraw: ", 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
     48static void *
     49append(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
     61static void
     62glfwerror(int rc, const char *error)
     63{
     64	die("glfw error (%i): %s", rc, error);
     65}
     66
     67static void
     68onresize(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
     78static void
     79onmove(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
     97static void
     98onclick(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
    117static void
    118onpress(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
    134int
    135main(void)
    136{
    137	glfwSetErrorCallback(glfwerror);
    138
    139	if (!glfwInit()) die("glfwInit");
    140
    141	GLFWwindow *window = glfwCreateWindow(640, 480, "sdraw", 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}