summaryrefslogtreecommitdiffstats
path: root/src/main.c
blob: 9014f22165cee6e35f9101856502118428dbc914 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <SDL3/SDL.h>
#include <math.h>
#include <stdio.h>

#define LOG(...)                                                               \
  do {                                                                         \
    fprintf(stderr, __VA_ARGS__);                                              \
    fprintf(stderr, "\n");                                                     \
  } while (0)

#define QUADRATIC_BEZIER_CURVE_CONTROL_POINT_COUNT 4
#define CONTROL_POINT_RECTANGLE_SIZE 20.f

struct vec2 {
  float x;
  float y;
};
struct vec2 vec2_add(struct vec2 lhs, struct vec2 rhs) {
  return (struct vec2){.x = lhs.x + rhs.x, .y = lhs.y + rhs.y};
}

struct vec2 vec2_mul_scalar(struct vec2 lhs, float rhs) {
  return (struct vec2){.x = lhs.x * rhs, .y = lhs.y * rhs};
}

struct vec2 bezier_quadratic(
    float t, const struct vec2
                 control_points[QUADRATIC_BEZIER_CURVE_CONTROL_POINT_COUNT]) {

  struct vec2 a = vec2_mul_scalar(control_points[0], powf(1.f - t, 3.f));
  struct vec2 b =
      vec2_mul_scalar(control_points[1], 3 * powf(1.f - t, 2.f) * t);
  struct vec2 c = vec2_mul_scalar(control_points[2], 3 * (1.f - t) * t * t);
  struct vec2 d = vec2_mul_scalar(control_points[3], t * t * t);
  return vec2_add(a, vec2_add(b, vec2_add(c, d)));
}

struct state {
  struct vec2 control_points[QUADRATIC_BEZIER_CURVE_CONTROL_POINT_COUNT];
  int set_control_point_count;
};
void state_render(const struct state *state, SDL_Renderer *renderer) {
  for (int set_control_point_index = 0;
       set_control_point_index < state->set_control_point_count;
       set_control_point_index++) {
    const struct vec2 *set_control_point =
        &state->control_points[set_control_point_index];
    SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF);
    SDL_RenderFillRect(
        renderer,
        &(const SDL_FRect){
            set_control_point->x - CONTROL_POINT_RECTANGLE_SIZE / 2.f,
            set_control_point->y - CONTROL_POINT_RECTANGLE_SIZE / 2.f,
            CONTROL_POINT_RECTANGLE_SIZE, CONTROL_POINT_RECTANGLE_SIZE});
  }

  if (state->set_control_point_count ==
      QUADRATIC_BEZIER_CURVE_CONTROL_POINT_COUNT) {
    float prev_t = 0.f;
    for (int ti = 0; ti < 100; ti += 1) {
      float t = ti / 100.f;
      struct vec2 first_point = bezier_quadratic(prev_t, state->control_points);
      struct vec2 second_point = bezier_quadratic(t, state->control_points);
      SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF);
      SDL_RenderLine(renderer, first_point.x, first_point.y, second_point.x,
                     second_point.y);
      prev_t = t;
    }
  }
}
void state_on_click(struct state *state, struct vec2 position) {
  if (state->set_control_point_count <
      QUADRATIC_BEZIER_CURVE_CONTROL_POINT_COUNT) {
    state->control_points[state->set_control_point_count++] = position;
  }
}

int main(void) {
  bool sdl_initialized = SDL_Init(SDL_INIT_VIDEO);
  SDL_Window *window = NULL;
  if (sdl_initialized) {
    window = SDL_CreateWindow("bezier", 1280, 720, 0);
  }

  SDL_Renderer *renderer = NULL;
  if (window) {
    renderer = SDL_CreateRenderer(window, NULL);
  }

  struct state state = {0};

  if (renderer) {
    bool running = true;
    while (running) {
      SDL_Event event;
      while (SDL_PollEvent(&event)) {
        bool quit = event.type == SDL_EVENT_QUIT;
        bool escape_pressed =
            event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_ESCAPE;

        if (quit || escape_pressed) {
          running = false;
        } else if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN &&
                   event.button.button == SDL_BUTTON_LEFT) {
          state_on_click(
              &state, (struct vec2){.x = event.button.x, .y = event.button.y});
        }
      }

      SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
      SDL_RenderClear(renderer);
      state_render(&state, renderer);
      SDL_RenderPresent(renderer);
    }
  }

  if (renderer) {
    SDL_DestroyRenderer(renderer);
  }
  if (window) {
    SDL_DestroyWindow(window);
  }
  if (sdl_initialized) {
    SDL_Quit();
  }

  return 0;
}
Go back to lisible.xyz