]> git.lizzy.rs Git - nothing.git/blob - src/dying_rect.c
(#110) Turn seen goals into checkpoints
[nothing.git] / src / dying_rect.c
1 #include <assert.h>
2 #include <SDL2/SDL.h>
3
4 #include "./lt.h"
5 #include "./error.h"
6 #include "./dying_rect.h"
7 #include "./algo.h"
8
9 #define DYING_RECT_PIECE_COUNT 20
10 #define DYING_RECT_PIECE_SIZE 20.0f
11
12 typedef struct piece_t {
13     point_t position;
14     float angle;
15     float angle_velocity;
16     vec_t direction;
17     triangle_t body;
18 } piece_t;
19
20 struct dying_rect_t
21 {
22     lt_t *lt;
23
24     vec_t position;
25     vec_t size;
26     color_t color;
27     float duration;
28     float time_passed;
29     piece_t *pieces;
30 };
31
32 dying_rect_t *create_dying_rect(rect_t rect,
33                                 color_t color,
34                                 float duration)
35 {
36     lt_t *lt = create_lt();
37     if (lt == NULL) {
38         return NULL;
39     }
40
41     dying_rect_t *dying_rect = PUSH_LT(lt, malloc(sizeof(dying_rect_t)), free);
42     if (dying_rect == NULL) {
43         throw_error(ERROR_TYPE_LIBC);
44         RETURN_LT(lt, NULL);
45     }
46
47     dying_rect->lt = lt;
48     dying_rect->position = vec(rect.x, rect.y);
49     dying_rect->size = vec(rect.w, rect.h);
50     dying_rect->color = color;
51     dying_rect->duration = duration;
52     dying_rect->time_passed = 0;
53
54     dying_rect->pieces = PUSH_LT(lt, malloc(sizeof(piece_t) * DYING_RECT_PIECE_COUNT), free);
55     if (dying_rect->pieces == NULL) {
56         throw_error(ERROR_TYPE_LIBC);
57         RETURN_LT(lt, NULL);
58     }
59
60     for (size_t i = 0; i < DYING_RECT_PIECE_COUNT; ++i) {
61         dying_rect->pieces[i].position = dying_rect->position;
62         dying_rect->pieces[i].angle = rand_float(2 * PI);
63         dying_rect->pieces[i].angle_velocity = rand_float(8.0f);
64         dying_rect->pieces[i].body = random_triangle(DYING_RECT_PIECE_SIZE);
65         dying_rect->pieces[i].direction = vec_from_polar(
66             rand_float_range(-PI, 0.0f),
67             rand_float_range(100.0f, 300.0f));
68     }
69
70     return dying_rect;
71 }
72
73 void destroy_dying_rect(dying_rect_t *dying_rect)
74 {
75     assert(dying_rect);
76     RETURN_LT0(dying_rect->lt);
77 }
78
79 /* TODO(#109): Dying Rect animation is too boring */
80 int dying_rect_render(const dying_rect_t *dying_rect,
81                       SDL_Renderer *renderer,
82                       const camera_t *camera)
83 {
84     assert(dying_rect);
85     assert(renderer);
86     assert(camera);
87
88     for (size_t i = 0; i < DYING_RECT_PIECE_COUNT; ++i) {
89         color_t color = dying_rect->color;
90         color.a = fminf(1.0f, 4.0f - (float) dying_rect->time_passed / (float) dying_rect->duration * 4.0f);
91
92         if (camera_fill_triangle(
93                 camera,
94                 renderer,
95                 triangle_mat3x3_product(
96                     dying_rect->pieces[i].body,
97                     mat3x3_product(
98                         trans_mat(dying_rect->pieces[i].position.x,
99                                   dying_rect->pieces[i].position.y),
100                         rot_mat(dying_rect->pieces[i].angle))),
101                 color) < 0) {
102             return -1;
103         }
104     }
105
106     return 0;
107 }
108
109 int dying_rect_update(dying_rect_t *dying_rect,
110                       float delta_time)
111 {
112     assert(dying_rect);
113     assert(delta_time > 0.0f);
114
115     if (dying_rect_is_dead(dying_rect)) {
116         return 0;
117     }
118
119     dying_rect->time_passed = dying_rect->time_passed + delta_time;
120
121     for (size_t i = 0; i < DYING_RECT_PIECE_COUNT; ++i) {
122         vec_add(
123             &dying_rect->pieces[i].position,
124             vec_scala_mult(
125                 dying_rect->pieces[i].direction,
126                 delta_time));
127         dying_rect->pieces[i].angle = fmodf(
128             dying_rect->pieces[i].angle + dying_rect->pieces[i].angle_velocity * delta_time,
129             2.0f * PI);
130     }
131
132     return 0;
133 }
134
135 int dying_rect_is_dead(const dying_rect_t *dying_rect)
136 {
137     assert(dying_rect);
138     return dying_rect->time_passed >= dying_rect->duration;
139 }