commit 5629be88954d57fa54305c2ac1f7e77ecb04046b
Author: Louis Burda <quent.burda@gmail.com>
Date: Fri, 14 Jun 2024 01:11:03 +0200
Basic version
Diffstat:
A | .gitignore | | | 1 | + |
A | Makefile | | | 19 | +++++++++++++++++++ |
A | sdraw.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();
+}