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}