185 lines
5.1 KiB
C
185 lines
5.1 KiB
C
#include "drawing.h"
|
|
#include "aliases/aliases.h"
|
|
#include <SDL_render.h>
|
|
#include <math.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define square(x) (x * x)
|
|
|
|
typedef struct line line_t;
|
|
struct line {
|
|
point_t p0;
|
|
point_t p1;
|
|
};
|
|
|
|
typedef struct triangle triangle_t;
|
|
struct triangle {
|
|
point_t p0;
|
|
point_t p1;
|
|
point_t p2;
|
|
};
|
|
|
|
INTERNAL void draw_line(SDL_Renderer *renderer, line_t ln);
|
|
INTERNAL void draw_triangle(SDL_Renderer *renderer, triangle_t triangle);
|
|
|
|
bool init_arrows_arr(arrows_t *lines, u64 capacity) {
|
|
u64 size = capacity * sizeof(arrow_t);
|
|
|
|
lines->lines = (arrow_t *)malloc(size);
|
|
if (!(lines->lines)) {
|
|
return false;
|
|
}
|
|
|
|
memset(lines->lines, 0, size);
|
|
|
|
lines->count = 0;
|
|
lines->capacity = capacity;
|
|
|
|
return true;
|
|
}
|
|
|
|
void add_arrow(arrows_t *lines, arrow_t ln) {
|
|
if (lines->count == lines->capacity) {
|
|
arrow_t *ptr = lines->lines;
|
|
|
|
u64 new_capacity =
|
|
(lines->capacity + DEFAULT_ARROWS_CAPACITY) * sizeof(arrow_t);
|
|
|
|
lines->lines = (arrow_t *)realloc(lines->lines, new_capacity);
|
|
if (!(lines->lines)) {
|
|
lines->lines = ptr;
|
|
return;
|
|
}
|
|
|
|
lines->capacity = new_capacity;
|
|
}
|
|
|
|
lines->lines[(lines->count)++] = (arrow_t){
|
|
(point_t){ln.origin.x, ln.origin.y},
|
|
(vec2_t){ln.direction.x, ln.direction.y},
|
|
};
|
|
}
|
|
|
|
void draw_arrows(SDL_Renderer *renderer, const arrows_t *arrows,
|
|
colour_t colour) {
|
|
for (u64 i = 0; i < arrows->count; ++i) {
|
|
const arrow_t *ln = &(arrows->lines[i]);
|
|
|
|
draw_arrow(renderer, ln, colour);
|
|
}
|
|
}
|
|
|
|
INTERNAL f32 vec2_magnitude(const vec2_t *vec) {
|
|
return sqrtf((f32)vec->x * vec->x + (f32)vec->y * vec->y);
|
|
}
|
|
|
|
INTERNAL triangle_t calculate_arrow_head(SDL_Renderer *renderer,
|
|
const arrow_t *arrow,
|
|
const point_t *arrow_end) {
|
|
// m = line_slope
|
|
// dx = change_in_x
|
|
// dy = change_in_y
|
|
//
|
|
// m = dy / dx
|
|
//
|
|
// for two perpendicular lines, their slopes would be m and -1/m
|
|
//
|
|
// To draw a perpendicular line with fixed length:
|
|
// dy / dx = -1 / m
|
|
// (rearranged) => dx = -m * dy
|
|
//
|
|
// From Pythagorean theorem:
|
|
// let c = desired_length
|
|
//
|
|
// c^2 = dx^2 + dy^2
|
|
// (dx substituted) => c^2 = (-m * dy)^2 + dy^2
|
|
// c^2 = m^2 * dy^2 + dy^2
|
|
// c^2 = dy^2 * (m^2 + 1)
|
|
// (rearranged) dy^2 = c^2 / (m^2 + 1)
|
|
// dy = sqrt(c^2 / (m^2 + 1))
|
|
//
|
|
// Based on this answer from StackOverflow:
|
|
// https://stackoverflow.com/a/57065334
|
|
|
|
vec2_t unit_vector = {1, 1};
|
|
if (arrow->direction.y != 0) {
|
|
unit_vector.y = arrow->direction.y / abs(arrow->direction.y);
|
|
}
|
|
|
|
point_t arrow_tip = (point_t){-1, -1};
|
|
point_t arrow_base_p0 = (point_t){-1, -1};
|
|
point_t arrow_base_p1 = (point_t){-1, -1};
|
|
f32 half_length = 20.0f;
|
|
|
|
if (arrow->direction.x == 0) {
|
|
arrow_tip.x = arrow_end->x;
|
|
arrow_tip.y = arrow_end->y + half_length * unit_vector.y;
|
|
arrow_base_p0.x = arrow_end->x - half_length;
|
|
arrow_base_p0.y = arrow_end->y;
|
|
arrow_base_p1.x = arrow_end->x + half_length;
|
|
arrow_base_p1.y = arrow_end->y;
|
|
} else {
|
|
unit_vector.x = arrow->direction.x / abs(arrow->direction.x);
|
|
|
|
// Calcualte arrow tip
|
|
f32 dx0_squared = square((f32)(arrow->direction.x));
|
|
f32 dy0_squared = square((f32)(arrow->direction.y));
|
|
|
|
f32 dy = sqrtf(square(half_length) / (dx0_squared / dy0_squared + 1.0f)) *
|
|
unit_vector.y;
|
|
f32 dx = (arrow->direction.y != 0)
|
|
? dy * arrow->direction.x / arrow->direction.y
|
|
: half_length * unit_vector.x;
|
|
|
|
// Draw perpendicular line
|
|
f32 slope = (f32)(arrow->direction.y) / arrow->direction.x;
|
|
|
|
f32 perpendicular_dy =
|
|
sqrtf(square(half_length) / (square((f32)slope) + 1.0f));
|
|
f32 perpendicular_dx = -1.0f * slope * perpendicular_dy;
|
|
|
|
arrow_tip.x = arrow_end->x + dx;
|
|
arrow_tip.y = arrow_end->y + dy;
|
|
arrow_base_p0.x = arrow_end->x - perpendicular_dx;
|
|
arrow_base_p0.y = arrow_end->y - perpendicular_dy;
|
|
arrow_base_p1.x = arrow_end->x + perpendicular_dx;
|
|
arrow_base_p1.y = arrow_end->y + perpendicular_dy;
|
|
}
|
|
|
|
return (triangle_t){arrow_tip, arrow_base_p0, arrow_base_p1};
|
|
}
|
|
|
|
void draw_arrow(SDL_Renderer *renderer, const arrow_t *arrow, colour_t colour) {
|
|
SDL_SetRenderDrawColor(renderer, colour.colour.r, colour.colour.g,
|
|
colour.colour.b, colour.colour.a);
|
|
|
|
point_t end = (point_t){
|
|
arrow->origin.x + arrow->direction.x,
|
|
arrow->origin.y + arrow->direction.y,
|
|
};
|
|
line_t line = (line_t){arrow->origin, end};
|
|
|
|
if (vec2_magnitude(&(arrow->direction)) != 0) {
|
|
triangle_t triangle = calculate_arrow_head(renderer, arrow, &end);
|
|
draw_triangle(renderer, triangle);
|
|
}
|
|
|
|
draw_line(renderer, line);
|
|
}
|
|
|
|
INTERNAL void draw_line(SDL_Renderer *renderer, line_t ln) {
|
|
SDL_RenderDrawLine(renderer, ln.p0.x, ln.p0.y, ln.p1.x, ln.p1.y);
|
|
}
|
|
|
|
INTERNAL void draw_triangle(SDL_Renderer *renderer, triangle_t triangle) {
|
|
line_t ln0 = (line_t){triangle.p0, triangle.p1};
|
|
line_t ln1 = (line_t){triangle.p0, triangle.p2};
|
|
line_t ln2 = (line_t){triangle.p1, triangle.p2};
|
|
|
|
draw_line(renderer, ln0);
|
|
draw_line(renderer, ln1);
|
|
draw_line(renderer, ln2);
|
|
}
|