Browse Source

Add anti-aliased line drawer (slow, but effective)

K. Lange 4 years ago
parent
commit
06a7ca8cd9
3 changed files with 109 additions and 2 deletions
  1. 31 1
      apps/drawlines.c
  2. 13 0
      base/usr/include/toaru/graphics.h
  3. 65 1
      lib/graphics.c

+ 31 - 1
apps/drawlines.c

@@ -20,6 +20,7 @@
 #include <pthread.h>
 #include <time.h>
 #include <sched.h>
+#include <math.h>
 
 #include <toaru/yutani.h>
 #include <toaru/graphics.h>
@@ -30,11 +31,16 @@ static yutani_t * yctx;
 static yutani_window_t * wina;
 static gfx_context_t * ctx;
 static int should_exit = 0;
+static int thick = 0;
 
 void * draw_thread(void * garbage) {
 	(void)garbage;
 	while (!should_exit) {
-		draw_line(ctx, rand() % width, rand() % width, rand() % height, rand() % height, rgb(rand() % 255,rand() % 255,rand() % 255));
+		if (thick) {
+			draw_line_aa(ctx, rand() % width, rand() % width, rand() % height, rand() % height, rgb(rand() % 255,rand() % 255,rand() % 255), (float)thick);
+		} else {
+			draw_line(ctx, rand() % width, rand() % width, rand() % height, rand() % height, rgb(rand() % 255,rand() % 255,rand() % 255));
+		}
 		yutani_flip(yctx, wina);
 		usleep(16666);
 	}
@@ -42,6 +48,18 @@ void * draw_thread(void * garbage) {
 	return NULL;
 }
 
+static void show_usage(char * argv[]) {
+	printf(
+			"drawlines - graphical demo, draws lines randomly\n"
+			"\n"
+			"usage: %s [-t thickness]\n"
+			"\n"
+			" -t     \033[3mdraw with anti-aliasing and the specified thickness\033[0m\n"
+			" -?     \033[3mshow this help text\033[0m\n"
+			"\n", argv[0]);
+}
+
+
 int main (int argc, char ** argv) {
 	left   = 100;
 	top    = 100;
@@ -50,6 +68,18 @@ int main (int argc, char ** argv) {
 
 	srand(time(NULL));
 
+	int c;
+	while ((c = getopt(argc, argv, "t:?")) != -1) {
+		switch (c) {
+			case 't':
+				thick = atoi(optarg);
+				break;
+			case '?':
+				show_usage(argv);
+				return 0;
+		}
+	}
+
 	yctx = yutani_init();
 	if (!yctx) {
 		fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]);

+ 13 - 0
base/usr/include/toaru/graphics.h

@@ -93,3 +93,16 @@ extern uint32_t getBilinearFilteredPixelColor(sprite_t * tex, double u, double v
 extern uint32_t interp_colors(uint32_t bottom, uint32_t top, uint8_t interp);
 extern void draw_rounded_rectangle(gfx_context_t * ctx, int32_t x, int32_t y, uint16_t width, uint16_t height, int radius, uint32_t color);
 extern void draw_rectangle(gfx_context_t * ctx, int32_t x, int32_t y, uint16_t width, uint16_t height, uint32_t color);
+
+struct gfx_point {
+	float x;
+	float y;
+};
+
+extern float gfx_point_distance(struct gfx_point * a, struct gfx_point * b);
+extern float gfx_point_distance_squared(struct gfx_point * a, struct gfx_point * b);
+extern float gfx_point_dot(struct gfx_point * a, struct gfx_point * b);
+extern struct gfx_point gfx_point_sub(struct gfx_point * a, struct gfx_point * b);
+extern struct gfx_point gfx_point_add(struct gfx_point * a, struct gfx_point * b);
+extern float gfx_line_distance(struct gfx_point * p, struct gfx_point * v, struct gfx_point * w);
+extern void draw_line_aa(gfx_context_t * ctx, int x_1, int x_2, int y_1, int y_2, uint32_t color, float thickness);

+ 65 - 1
lib/graphics.c

@@ -797,9 +797,73 @@ void draw_rounded_rectangle(gfx_context_t * ctx, int32_t x, int32_t y, uint16_t
 			GFX(ctx, _x, _y) = alpha_blend_rgba(GFX(ctx, _x, _y), c);
 			GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), c);
 		}
+	}
+}
 
+float gfx_point_distance(struct gfx_point * a, struct gfx_point * b) {
+	return sqrt((a->x - b->x) * (a->x - b->x) + (a->y - b->y) * (a->y - b->y));
+}
 
+float gfx_point_distance_squared(struct gfx_point * a, struct gfx_point * b) {
+	return (a->x - b->x) * (a->x - b->x) + (a->y - b->y) * (a->y - b->y);
+}
 
-	}
+float gfx_point_dot(struct gfx_point * a, struct gfx_point * b) {
+	return (a->x * b->x) + (a->y * b->y);
+}
+
+struct gfx_point gfx_point_sub(struct gfx_point * a, struct gfx_point * b) {
+	struct gfx_point p = {a->x - b->x, a->y - b->y};
+	return p;
+}
+
+struct gfx_point gfx_point_add(struct gfx_point * a, struct gfx_point * b) {
+	struct gfx_point p = {a->x + b->x, a->y + b->y};
+	return p;
+}
+
+#define fmax(a,b) ((a) > (b) ? (a) : (b))
+#define fmin(a,b) ((a) < (b) ? (a) : (b))
+
+float gfx_line_distance(struct gfx_point * p, struct gfx_point * v, struct gfx_point * w) {
+	float lengthlength = gfx_point_distance_squared(v,w);
 
+	if (lengthlength == 0.0) return gfx_point_distance(p, v); /* point */
+
+	struct gfx_point p_v = gfx_point_sub(p,v);
+	struct gfx_point w_v = gfx_point_sub(w,v);
+	float tmp = gfx_point_dot(&p_v,&w_v) / lengthlength;
+	tmp = fmin(1.0,tmp);
+	float t = fmax(0.0, tmp);
+
+	w_v.x *= t;
+	w_v.y *= t;
+
+	struct gfx_point v_t = gfx_point_add(v, &w_v);
+	return gfx_point_distance(p, &v_t);
+}
+
+/**
+ * This is slow, but it works...
+ *
+ * Maybe acceptable for baked UI elements?
+ */
+void draw_line_aa(gfx_context_t * ctx, int x_1, int x_2, int y_1, int y_2, uint32_t color, float thickness) {
+	struct gfx_point v = {(float)x_1, (float)y_1};
+	struct gfx_point w = {(float)x_2, (float)y_2};
+
+	for (int y = 0; y < ctx->height; ++y) {
+		for (int x = 0; x < ctx->width; ++x) {
+			struct gfx_point p = {x,y};
+			float d = gfx_line_distance(&p,&v,&w);
+			if (d < thickness + 0.5) {
+				if (d < thickness - 0.5) {
+					GFX(ctx,x,y) = color;
+				} else {
+					uint32_t f_color = rgb(255 * (1.0 - (d - thickness + 0.5)), 0, 0);
+					GFX(ctx,x,y) = alpha_blend(GFX(ctx,x,y), color, f_color);
+				}
+			}
+		}
+	}
 }