shapes.c (5165B)
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include <stddef.h>
5 #include "display.h"
6
7 typedef struct {
8 uint32_t x;
9 uint32_t y;
10 uint32_t width;
11 uint32_t height;
12 ta_display_sprite *sprite;
13 } ta_shape_target;
14
15 static ta_shape_target target;
16
17 static bool target_begin(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
18 if (width == 0 || height == 0 || x >= ta_display->width || y >= ta_display->height) return false;
19 if (width > ta_display->width - x) width = ta_display->width - x;
20 if (height > ta_display->height - y) height = ta_display->height - y;
21 target.x = x;
22 target.y = y;
23 target.width = width;
24 target.height = height;
25 target.sprite = NULL;
26 if (ta_display->sprite_mode) {
27 if (ta_display->bpp != 32) return false;
28 target.sprite = ta_display_sprite_create((uint16_t)width, (uint16_t)height);
29 if (!target.sprite) return false;
30 target.sprite->x = (uint16_t)x;
31 target.sprite->y = (uint16_t)y;
32 for (size_t i = 0; i < (size_t)width * height * 4; i++) target.sprite->pixels[i] = 0;
33 } else if (!ta_display->buffers[1] || (ta_display->bpp != 8 && ta_display->bpp != 32)) {
34 return false;
35 }
36 return true;
37 }
38
39 static void target_pixel(uint32_t x, uint32_t y, uint32_t color) {
40 if (x < target.x || y < target.y || x - target.x >= target.width || y - target.y >= target.height) return;
41 size_t local = (size_t)(y - target.y) * target.width + (x - target.x);
42 if (target.sprite) {
43 ((uint32_t *)target.sprite->pixels)[local] = ((color & 0xffffffu) << 8) | 0xffu;
44 } else {
45 size_t index = (size_t)y * ta_display->width + x;
46 if (ta_display->bpp == 32) {
47 ((uint32_t *)ta_display->buffers[1])[index] = color & 0xffffffu;
48 } else {
49 uint32_t red = (color >> 16) & 255;
50 uint32_t green = (color >> 8) & 255;
51 uint32_t blue = color & 255;
52 ((uint8_t *)ta_display->buffers[1])[index] = (uint8_t)((red & 0xe0) | ((green >> 3) & 0x1c) | (blue >> 6));
53 }
54 }
55 }
56
57 static void target_end(void) {
58 if (target.sprite && !ta_display_sprite_add(target.sprite)) free(target.sprite);
59 target.sprite = NULL;
60 }
61
62 void ta_shapes_draw_pixel(uint32_t x, uint32_t y, uint32_t color) {
63 if (!target_begin(x, y, 1, 1)) return;
64 target_pixel(x, y, color);
65 target_end();
66 }
67
68 void ta_shapes_draw_rectangle(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t color) {
69 if (!target_begin(x, y, width, height)) return;
70 uint32_t end_x = target.x + target.width;
71 uint32_t end_y = target.y + target.height;
72 for (uint32_t py = target.y; py < end_y; py++)
73 for (uint32_t px = target.x; px < end_x; px++) target_pixel(px, py, color);
74 target_end();
75 }
76
77 static int64_t edge(int32_t ax, int32_t ay, int32_t bx, int32_t by, int32_t px, int32_t py) {
78 return ((int64_t)px - ax) * ((int64_t)by - ay) - ((int64_t)py - ay) * ((int64_t)bx - ax);
79 }
80
81 void ta_shapes_draw_triangle(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, uint32_t x3, uint32_t y3, uint32_t color) {
82 uint32_t min_x = x1, max_x = x1, min_y = y1, max_y = y1;
83 if (x2 < min_x) min_x = x2;
84 if (x3 < min_x) min_x = x3;
85 if (x2 > max_x) max_x = x2;
86 if (x3 > max_x) max_x = x3;
87 if (y2 < min_y) min_y = y2;
88 if (y3 < min_y) min_y = y3;
89 if (y2 > max_y) max_y = y2;
90 if (y3 > max_y) max_y = y3;
91 if (max_x == 0xffffffffu || max_y == 0xffffffffu) return;
92 uint32_t width = max_x - min_x + 1, height = max_y - min_y + 1;
93 if (!target_begin(min_x, min_y, width, height)) return;
94 int64_t area = edge((int32_t)x1, (int32_t)y1, (int32_t)x2, (int32_t)y2, (int32_t)x3, (int32_t)y3);
95 if (area != 0) {
96 uint32_t end_x = target.x + target.width, end_y = target.y + target.height;
97 for (uint32_t y = target.y; y < end_y; y++) for (uint32_t x = target.x; x < end_x; x++) {
98 int64_t a = edge((int32_t)x1, (int32_t)y1, (int32_t)x2, (int32_t)y2, (int32_t)x, (int32_t)y);
99 int64_t b = edge((int32_t)x2, (int32_t)y2, (int32_t)x3, (int32_t)y3, (int32_t)x, (int32_t)y);
100 int64_t c = edge((int32_t)x3, (int32_t)y3, (int32_t)x1, (int32_t)y1, (int32_t)x, (int32_t)y);
101 if ((area > 0 && a >= 0 && b >= 0 && c >= 0) || (area < 0 && a <= 0 && b <= 0 && c <= 0)) target_pixel(x, y, color);
102 }
103 }
104 target_end();
105 }
106
107 void ta_shapes_draw_oval(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t color) {
108 if (!target_begin(x, y, width, height)) return;
109 int64_t rx = (int64_t)width / 2;
110 int64_t ry = (int64_t)height / 2;
111 int64_t cx = (int64_t)x + rx;
112 int64_t cy = (int64_t)y + ry;
113 int64_t rx2 = rx * rx, ry2 = ry * ry;
114 if (rx2 == 0) rx2 = 1;
115 if (ry2 == 0) ry2 = 1;
116 uint32_t end_x = target.x + target.width, end_y = target.y + target.height;
117 for (uint32_t py = target.y; py < end_y; py++) for (uint32_t px = target.x; px < end_x; px++) {
118 int64_t dx = (int64_t)px - cx, dy = (int64_t)py - cy;
119 if (dx * dx * ry2 + dy * dy * rx2 <= rx2 * ry2) target_pixel(px, py, color);
120 }
121 target_end();
122 }