xdraw

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

commit 5629be88954d57fa54305c2ac1f7e77ecb04046b
Author: Louis Burda <quent.burda@gmail.com>
Date:   Fri, 14 Jun 2024 01:11:03 +0200

Basic version

Diffstat:
A.gitignore | 1+
AMakefile | 19+++++++++++++++++++
Asdraw.c | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 202 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +sdraw diff --git a/Makefile b/Makefile @@ -0,0 +1,19 @@ +PREFIX ?= /usr/local +BINDIR ?= /bin + +LDLIBS = -lglfw -lGL + +all: sdraw + +sdraw: sdraw.c + +clean: + rm -f sdraw + +install: + install -m755 sdraw -t "$(DESTDIR)$(PREFIX)$(BINDIR)" + +uninstall: + rm "$(DESTDIR)$(PREFIX)$(BINDIR)/sdraw" + +.PHONY: all clean install uninstall diff --git a/sdraw.c b/sdraw.c @@ -0,0 +1,182 @@ +#include <GL/gl.h> +#include <GLFW/glfw3.h> + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdbool.h> + +struct point { + double x, y; +}; + +struct line { + struct point *points; + size_t count, cap; +}; + +static struct line *lines = NULL; +static size_t line_count = 0; +static size_t line_cap = 0; + +static double cursor_x = 0; +static double cursor_y = 0; + +static int window_width = 0; +static int window_height = 0; + +static bool drawing = false; + +static void +die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fputs("sdraw: ", stderr); + vfprintf(stderr, fmt, ap); + if (*fmt && fmt[strlen(fmt)] == ':') + perror(NULL); + else + putc('\n', stderr); + va_end(ap); + + exit(1); +} + +static void * +append(void *_array, size_t *count, size_t *cap, size_t size) +{ + uint8_t **array = _array; + if (*count == *cap) { + if (*cap == 0) *cap = 1; + *cap *= 2; + *array = realloc(*array, *cap * size); + if (!*array) die("realloc:"); + } + return (void *) (*array + (*count)++ * size); +} + +static void +glfwerror(int rc, const char *error) +{ + die("glfw error (%i): %s", rc, error); +} + +static void +onresize(GLFWwindow *window, int width, int height) +{ + window_width = width; + window_height = height; + glViewport(0, 0, width, height); + glClear(GL_COLOR_BUFFER_BIT); + glLoadIdentity(); + glOrtho(0, width, height, 0, -1, 1); +} + +static void +onmove(GLFWwindow *window, double x, double y) +{ + cursor_x = x; + cursor_y = y; + if (drawing && line_count) { + struct line *line = &lines[line_count-1]; + if (line->count > 0) { + struct point *last_point = &line->points[line->count-1]; + if (cursor_x == last_point->x && cursor_y == last_point->y) + return; + } + struct point *point = append(&line->points, + &line->count, &line->cap, sizeof(struct point)); + point->x = cursor_x; + point->y = cursor_y; + } +} + +static void +onclick(GLFWwindow *window, int button, int action, int mods) +{ + if (button != GLFW_MOUSE_BUTTON_LEFT) return; + + if (action == GLFW_PRESS) { + struct line *line = append(&lines, + &line_count, &line_cap, sizeof(struct line)); + line->count = line->cap = 0; + line->points = NULL; + struct point *point = append(&line->points, + &line->count, &line->cap, sizeof(struct point)); + point->x = cursor_x; + point->y = cursor_y; + drawing = true; + } else if (action == GLFW_RELEASE) { + drawing = false; + } +} + +static void +onpress(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + if (action != GLFW_PRESS) return; + + if ((mods & GLFW_MOD_CONTROL) && !strcmp(glfwGetKeyName(key, scancode), "z")) { + if (line_count) { + line_count -= 1; + free(lines[line_count].points); + } + } else if ((mods & GLFW_MOD_CONTROL) && !strcmp(glfwGetKeyName(key, scancode), "c")) { + for (size_t i = 0; i < line_count; i++) + free(lines[i].points); + line_count = 0; + } +} + +int +main(void) +{ + glfwSetErrorCallback(glfwerror); + + if (!glfwInit()) die("glfwInit"); + + GLFWwindow *window = glfwCreateWindow(640, 480, "sdraw", NULL, NULL); + if (!window) die("glfwCreateWindow"); + + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + glfwSetWindowSizeCallback(window, onresize); + glfwSetCursorPosCallback(window, onmove); + glfwSetMouseButtonCallback(window, onclick); + glfwSetKeyCallback(window, onpress); + glfwMakeContextCurrent(window); + + glClearColor(0, 0, 0, 0); + glColor3f(1, 1, 1); + glLineWidth(2); + glPointSize(2); + + glfwGetCursorPos(window, &cursor_x, &cursor_y); + glfwGetWindowSize(window, &window_width, &window_height); + + onresize(window, window_width, window_height); + + while (!glfwWindowShouldClose(window)) { + glClear(GL_COLOR_BUFFER_BIT); + + for (size_t i = 0; i < line_count; i++) { + struct line *line = &lines[i]; + glBegin(GL_LINE_STRIP); + for (size_t k = 0; k < line->count; k++) + glVertex2f(line->points[k].x, line->points[k].y); + glEnd(); + } + + glBegin(GL_POINTS); + glVertex2f(cursor_x, cursor_y); + glEnd(); + + glfwSwapBuffers(window); + + glfwPollEvents(); + } + + glfwTerminate(); +}