Compare commits

..

No commits in common. "12cad4c71195b740caec95d3261d1b829287f309" and "883773d07c05a75171d4ae8d501452d6d1e6befb" have entirely different histories.

10 changed files with 7 additions and 310 deletions

3
.gitignore vendored
View File

@ -1,3 +0,0 @@
.cache
compile_commands.json
main

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "intern/aliases"]
path = intern/aliases
url = https://git.thewizardapprentice.com/abdelrahman/c-cpp-aliases.git

View File

@ -1,7 +0,0 @@
# Arrow drawing test
Test drawing arrows in SDL.
To draw an arrow, click the mouse to start drawing, move your mouse to the desired location, then click again to finalise the drawing.
![Example result](./result.png)

3
build
View File

@ -1,3 +0,0 @@
#!/bin/bash
bear -- ./compile $@

View File

@ -1,9 +0,0 @@
#!/bin/bash
CC=clang
CFLAGS="-g -Wall -Iintern $(pkg-config --cflags sdl2)"
LIBS="$(pkg-config --libs sdl2) -lm"
SRC=*.c
OUT=main
(set -x ; $CC $CFLAGS $LIBS $SRC -o $OUT)

156
drawing.c
View File

@ -1,156 +0,0 @@
#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)
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->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 void draw_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;
}
SDL_RenderDrawLine(renderer, arrow_end->x, arrow_end->y, arrow_base_p0.x,
arrow_base_p0.y);
SDL_RenderDrawLine(renderer, arrow_end->x, arrow_end->y, arrow_base_p1.x,
arrow_base_p1.y);
SDL_RenderDrawLine(renderer, arrow_tip.x, arrow_tip.y, arrow_base_p0.x,
arrow_base_p0.y);
SDL_RenderDrawLine(renderer, arrow_tip.x, arrow_tip.y, arrow_base_p1.x,
arrow_base_p1.y);
}
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,
};
if (vec2_magnitude(&(arrow->direction)) != 0) {
draw_arrow_head(renderer, arrow, &end);
}
SDL_RenderDrawLine(renderer, arrow->origin.x, arrow->origin.y, end.x, end.y);
}

View File

@ -1,55 +0,0 @@
#ifndef DRAWING_H
#define DRAWING_H
#include "aliases/aliases.h"
#include <SDL_pixels.h>
#include <SDL_render.h>
#include <stdbool.h>
#define DEFAULT_ARROWS_CAPACITY 1024
#define init_arrows_default(arrows) \
init_arrows_arr(arrows, DEFAULT_ARROWS_CAPACITY)
#define init_arrows_with_capacity(arrows, capacity) \
init_arrows_arr(arrows, capacity)
typedef struct colour colour_t;
struct colour {
union {
u32 abgr;
SDL_Color colour;
};
};
typedef struct point point_t;
struct point {
i32 x;
i32 y;
};
typedef struct vec2 vec2_t;
struct vec2 {
i32 x;
i32 y;
};
typedef struct arrow arrow_t;
struct arrow {
point_t origin;
vec2_t direction;
};
typedef struct arrows arrows_t;
struct arrows {
arrow_t *lines;
u64 count;
u64 capacity;
};
bool init_arrows_arr(arrows_t *lines, u64 capacity);
void add_arrow(arrows_t *lines, arrow_t ln);
void draw_arrows(SDL_Renderer *renderer, const arrows_t *arrows,
colour_t colour);
void draw_arrow(SDL_Renderer *renderer, const arrow_t *arrow, colour_t colour);
#endif // !DRAWING_H

@ -1 +0,0 @@
Subproject commit f95f3aa499910286876c1f2cdceea8146ebcf7b1

80
main.c
View File

@ -1,27 +1,11 @@
#include "SDL_mouse.h"
#include "aliases/aliases.h"
#include "drawing.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include <SDL2/SDL_video.h> #include <SDL2/SDL_video.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
#define WINDOW_WIDTH 1280 #define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 720 #define WINDOW_HEIGHT 600
typedef struct state state_t;
struct state {
i32 mouse_x;
i32 mouse_y;
i32 current_origin_x;
i32 current_origin_y;
bool running;
bool drawing;
arrows_t arrows;
arrow_t tmp_arrow;
};
int main(void) { int main(void) {
SDL_Init(SDL_INIT_EVERYTHING); SDL_Init(SDL_INIT_EVERYTHING);
@ -33,55 +17,15 @@ int main(void) {
SDL_Renderer *renderer = SDL_CreateRenderer( SDL_Renderer *renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
state_t st = { bool running = true;
.mouse_x = -1,
.mouse_y = -1,
.current_origin_x = -1,
.current_origin_y = -1,
.running = true,
.drawing = false,
.arrows = {0},
.tmp_arrow = {0},
};
SDL_Event event = {0}; SDL_Event event = {};
if (!init_arrows_default(&(st.arrows))) { while (running) {
return EXIT_FAILURE;
}
while (st.running) {
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { switch (event.type) {
case SDL_QUIT: case SDL_QUIT:
st.running = false; running = false;
break;
case SDL_MOUSEBUTTONUP:
if (event.button.button == SDL_BUTTON_LEFT) {
if (st.drawing) {
add_arrow(&(st.arrows), st.tmp_arrow);
st.tmp_arrow = (arrow_t){0};
st.drawing = false;
} else {
st.current_origin_x = event.button.x;
st.current_origin_y = event.button.y;
st.drawing = true;
}
} else if (event.button.button == SDL_BUTTON_RIGHT) {
st.current_origin_x = -1;
st.current_origin_y = -1;
st.drawing = false;
}
break;
case SDL_MOUSEMOTION:
st.mouse_x = event.motion.x;
st.mouse_y = event.motion.y;
break; break;
} }
} }
@ -90,16 +34,6 @@ int main(void) {
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
if (st.drawing) {
st.tmp_arrow.origin = (point_t){st.current_origin_x, st.current_origin_y};
st.tmp_arrow.direction = (vec2_t){st.mouse_x - st.current_origin_x,
st.mouse_y - st.current_origin_y};
draw_arrow(renderer, &(st.tmp_arrow), (colour_t){.abgr = 0xff0000ff});
}
draw_arrows(renderer, &(st.arrows), (colour_t){.abgr = 0xff000000});
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
} }
@ -109,5 +43,5 @@ int main(void) {
SDL_Quit(); SDL_Quit();
return EXIT_SUCCESS; return 0;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB