src/drawing.c
1#include <math.h>
2#include <stdio.h>
3#include <stdlib.h>
4
5#include "alba.h"
6
7#define PI 3.14159265358979323846
8
9void draw_triangles_indexed(
10 AlbaWindow* window,
11 const uint32_t num_vertices,
12 const float* vertices,
13 const float* attributes,
14 const uint32_t num_indices,
15 uint32_t* indices
16)
17{
18 const uint32_t offset = window->new_vertices.length / 2;
19
20 float_array_extend(&window->new_vertices, num_vertices * 2, vertices);
21 float_array_extend(&window->new_attributes, num_vertices * 4, attributes);
22
23 if (offset > 0)
24 {
25 // Fix indices
26 for (uint32_t i = 0; i < num_indices; i++)
27 {
28 indices[i] += offset;
29 }
30 }
31 uint32_array_extend(&window->new_indices, num_indices, indices);
32
33 window->dirty = 1;
34}
35
36void draw_triangles(
37 AlbaWindow* window,
38 const uint32_t num_vertices,
39 const float* vertices,
40 const float* attributes
41)
42{
43 uint32_t* indices = malloc(num_vertices * sizeof(uint32_t));
44 if (indices == NULL)
45 {
46 printf(
47 "error: unable to allocate %lu bytes for triangle indices\n",
48 num_vertices * sizeof(uint32_t)
49 );
50 return;
51 }
52
53 for (uint32_t i = 0; i < num_vertices; i++)
54 {
55 indices[i] = i;
56 }
57
58 draw_triangles_indexed(window, num_vertices, vertices, attributes, num_vertices, indices);
59
60 free(indices);
61}
62
63void draw_triangle(AlbaWindow* window, const float vertices[6], const AlbaColor color)
64{
65 // Does not try to consider winding order
66 const float attributes[] = {
67 color.r, color.g, color.b, color.a,
68 color.r, color.g, color.b, color.a,
69 color.r, color.g, color.b, color.a,
70 };
71 uint32_t indices[] = {0, 1, 2};
72 draw_triangles_indexed(window, 3, vertices, attributes, 3, indices);
73}
74
75void draw_rect(AlbaWindow* window, const float vertices[8], const AlbaColor color)
76{
77 // Does not try to consider winding order
78 const float attributes[] = {
79 color.r, color.g, color.b, color.a,
80 color.r, color.g, color.b, color.a,
81 color.r, color.g, color.b, color.a,
82 color.r, color.g, color.b, color.a,
83 };
84 uint32_t indices[] = {0, 1, 2, 0, 2, 3};
85 draw_triangles_indexed(window, 4, vertices, attributes, 6, indices);
86}
87
88void draw_rect_aa(
89 AlbaWindow* window,
90 const float x0, const float y0, const float x1, const float y1,
91 const AlbaColor color
92)
93{
94 // Does not try to consider winding order
95 const float vertices[] = {
96 x0, y0,
97 x0, y1,
98 x1, y1,
99 x1, y0,
100 };
101 draw_rect(window, vertices, color);
102}
103
104void regular_polygon_points(FloatArray* array, const uint32_t num_sides, const float x, const float y, const float r)
105{
106 float_array_reserve(array, array->length + num_sides * 2);
107
108 const float step_angle = 2 * PI / num_sides;
109 for (uint32_t i = 0; i < num_sides; i++)
110 {
111 float_array_append(array, x + r * sin(step_angle * i));
112 float_array_append(array, y - r * cos(step_angle * i));
113 }
114}
115
116void circle_points(FloatArray* array, const float x, const float y, const float r)
117{
118 const uint32_t num_sides = 8 + 2 * PI * r / 10;
119 regular_polygon_points(array, num_sides, x, y, r);
120}
121
122void draw_concave_polygon(AlbaWindow* window, const float x, const float y, FloatArray* contour, AlbaColor color)
123{
124 const uint32_t num_sides = contour->length / 2;
125 const uint32_t num_vertices = num_sides + 1;
126
127 float_array_append(contour, x);
128 float_array_append(contour, y);
129
130 FloatArray colors = {0};
131 float_array_reserve(&colors, num_vertices * 4);
132 for (uint32_t i = 0; i < num_vertices; i++)
133 {
134 float_array_extend(&colors, 4, (float*)&color);
135 }
136
137 uint32_t* indices = malloc(num_sides * 3 * sizeof(uint32_t));
138 for (uint32_t i = 0; i < num_sides; i++)
139 {
140 indices[i * 3] = num_vertices - 1;
141 indices[i * 3 + 1] = i;
142 indices[i * 3 + 2] = i + 1;
143 }
144 indices[num_sides * 3 - 1] = 0;
145
146 draw_triangles_indexed(window, num_sides + 1, contour->data, colors.data, num_sides * 3, indices);
147
148 free(indices);
149}
150
151void draw_regular_polygon(
152 AlbaWindow* window, const uint32_t num_sides,
153 const float x, const float y, const float r,
154 const AlbaColor color
155)
156{
157 if (num_sides <= 2)
158 {
159 printf("error: invalid number of sides in call to draw_regular_polygon: %d. "
160 "A polygon must have at least 3 sides\n", num_sides);
161 exit(1);
162 }
163
164 FloatArray polyon = {0};
165 regular_polygon_points(&polyon, num_sides, x, y, r);
166 draw_concave_polygon(window, x, y, &polyon, color);
167 float_array_release(&polyon);
168}
169
170void draw_circle(AlbaWindow* window, const float x, const float y, const float r, const AlbaColor color)
171{
172 FloatArray circle = {0};
173 circle_points(&circle, x, y, r);
174 draw_concave_polygon(window, x, y, &circle, color);
175 float_array_release(&circle);
176}