]> git.lizzy.rs Git - nothing.git/blob - src/game/level/labels.c
Merge pull request #1 from tsoding/master
[nothing.git] / src / game / level / labels.c
1 #include "system/stacktrace.h"
2 #include <stdbool.h>
3
4 #include "game/camera.h"
5 #include "game/level/labels.h"
6 #include "system/str.h"
7 #include "system/line_stream.h"
8 #include "system/lt.h"
9 #include "system/nth_alloc.h"
10 #include "system/log.h"
11 #include "ebisp/interpreter.h"
12 #include "broadcast.h"
13
14 #define LABEL_MAX_ID_SIZE 36
15
16 enum LabelState
17 {
18     LABEL_STATE_VIRGIN = 0,
19     LABEL_STATE_APPEARED,
20     LABEL_STATE_HIDDEN
21 };
22
23 struct Labels
24 {
25     Lt *lt;
26     size_t count;
27     char **ids;
28     Vec *positions;
29     Color *colors;
30     char **texts;
31     float *alphas;
32     float *delta_alphas;
33     enum LabelState *states;
34 };
35
36 Labels *create_labels_from_line_stream(LineStream *line_stream)
37 {
38     trace_assert(line_stream);
39
40     Lt *const lt = create_lt();
41     if (lt == NULL) {
42         return NULL;
43     }
44
45     Labels * const labels = PUSH_LT(lt, nth_calloc(1, sizeof(Labels)), free);
46     if (labels == NULL) {
47         RETURN_LT(lt, NULL);
48     }
49     labels->lt = lt;
50
51     if (sscanf(
52             line_stream_next(line_stream),
53             "%lu",
54             &labels->count) == EOF) {
55         log_fail("Could not read amount of labels\n");
56         RETURN_LT(lt, NULL);
57     }
58
59     labels->ids = PUSH_LT(lt, nth_calloc(1, sizeof(char*) * labels->count), free);
60     if (labels->ids == NULL) {
61         RETURN_LT(lt, NULL);
62     }
63
64     labels->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec) * labels->count), free);
65     if (labels->positions == NULL) {
66         RETURN_LT(lt, NULL);
67     }
68
69     labels->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * labels->count), free);
70     if (labels->colors == NULL) {
71         RETURN_LT(lt, NULL);
72     }
73
74     labels->texts = PUSH_LT(lt, nth_calloc(1, sizeof(char*) * labels->count), free);
75     if (labels->texts == NULL) {
76         RETURN_LT(lt, NULL);
77     }
78
79     labels->alphas = PUSH_LT(lt, nth_calloc(1, sizeof(float) * labels->count), free);
80     if (labels->alphas == NULL) {
81         RETURN_LT(lt, NULL);
82     }
83
84     labels->delta_alphas = PUSH_LT(lt, nth_calloc(1, sizeof(float) * labels->count), free);
85     if (labels->delta_alphas == NULL) {
86         RETURN_LT(lt, NULL);
87     }
88
89     labels->states = PUSH_LT(lt, nth_calloc(1, sizeof(enum LabelState) * labels->count), free);
90     if (labels->states == NULL) {
91         RETURN_LT(lt, NULL);
92     }
93
94     char color[7];
95     for (size_t i = 0; i < labels->count; ++i) {
96         labels->alphas[i] = 0.0f;
97         labels->delta_alphas[i] = 0.0f;
98         labels->states[i] = LABEL_STATE_VIRGIN;
99         labels->texts[i] = NULL;
100
101         labels->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * LABEL_MAX_ID_SIZE), free);
102         if (labels->ids[i] == NULL) {
103             RETURN_LT(lt, NULL);
104         }
105
106         if (sscanf(
107                 line_stream_next(line_stream),
108                 "%" STRINGIFY(LABEL_MAX_ID_SIZE) "s%f%f%6s\n",
109                 labels->ids[i],
110                 &labels->positions[i].x,
111                 &labels->positions[i].y,
112                 color) == EOF) {
113             log_fail("Could not read position and color of %dth label\n", i);
114             RETURN_LT(lt, NULL);
115         }
116
117         labels->colors[i] = hexstr(color);
118
119         const char *label_text = line_stream_next(line_stream);
120         if (label_text == NULL) {
121             log_fail("Could not read text of %dth label\n", i);
122             RETURN_LT(lt, NULL);
123         }
124
125         labels->texts[i] = PUSH_LT(
126             lt,
127             string_duplicate(label_text, NULL),
128             free);
129         if (labels->texts[i] == NULL) {
130             RETURN_LT(lt, NULL);
131         }
132
133         trim_endline(labels->texts[i]);
134     }
135
136     return labels;
137 }
138
139 void destroy_labels(Labels *label)
140 {
141     trace_assert(label);
142     RETURN_LT0(label->lt);
143 }
144
145 int labels_render(const Labels *label,
146                  Camera *camera)
147 {
148     trace_assert(label);
149     trace_assert(camera);
150
151     for (size_t i = 0; i < label->count; ++i) {
152         /* Easing */
153         const float state = label->alphas[i] * (2 - label->alphas[i]);
154
155         if (camera_render_text(camera,
156                                label->texts[i],
157                                vec(2.0f, 2.0f),
158                                rgba(label->colors[i].r,
159                                     label->colors[i].g,
160                                     label->colors[i].b,
161                                     state),
162                                vec_sum(label->positions[i],
163                                        vec(0.0f, -8.0f * state))) < 0) {
164             return -1;
165         }
166     }
167
168     return 0;
169 }
170
171 void labels_update(Labels *label,
172                    float delta_time)
173 {
174     trace_assert(label);
175     (void) delta_time;
176
177     for (size_t i = 0; i < label->count; ++i) {
178         label->alphas[i] = label->alphas[i] + label->delta_alphas[i] * delta_time;
179
180         if (label->alphas[i] < 0.0f) {
181             label->alphas[i] = 0.0f;
182             label->delta_alphas[i] = 0.0f;
183         }
184
185         if (label->alphas[i] > 1.0f) {
186             label->alphas[i] = 1.0f;
187             label->delta_alphas[i] = 0.0f;
188         }
189     }
190 }
191
192 void labels_enter_camera_event(Labels *labels,
193                                const Camera *camera)
194 {
195     trace_assert(labels);
196     trace_assert(camera);
197
198     for (size_t i = 0; i < labels->count; ++i) {
199         const int became_visible = camera_is_text_visible(
200             camera,
201             vec(2.0f, 2.0f),
202             labels->positions[i],
203             labels->texts[i]);
204
205         if (labels->states[i] == LABEL_STATE_VIRGIN && became_visible) {
206             labels->states[i] = LABEL_STATE_APPEARED;
207             labels->alphas[i] = 0.0f;
208             labels->delta_alphas[i] = 1.0f;
209         }
210     }
211 }
212
213 static struct EvalResult
214 labels_action(Labels *labels,
215               size_t index,
216               Gc *gc,
217               struct Scope *scope,
218               struct Expr path)
219 {
220     trace_assert(labels);
221     trace_assert(gc);
222     trace_assert(scope);
223
224     const char *target = NULL;
225     struct Expr rest = void_expr();
226     struct EvalResult res = match_list(gc, "q*", path, &target, &rest);
227     if (res.is_error) {
228         return res;
229     }
230
231     if (strcmp(target, "hide") == 0) {
232         if (labels->states[index] != LABEL_STATE_HIDDEN) {
233             labels->states[index] = LABEL_STATE_HIDDEN;
234             labels->alphas[index] = 1.0f;
235             labels->delta_alphas[index] = -3.0f;
236         }
237         return eval_success(NIL(gc));
238     }
239
240     return unknown_target(gc, labels->ids[index], target);
241 }
242
243 struct EvalResult
244 labels_send(Labels *labels, Gc *gc, struct Scope *scope, struct Expr path)
245 {
246     trace_assert(labels);
247     trace_assert(gc);
248     trace_assert(scope);
249
250     const char *target = NULL;
251     struct Expr rest = void_expr();
252     struct EvalResult res = match_list(gc, "s*", path, &target, &rest);
253     if (res.is_error) {
254         return res;
255     }
256
257     for (size_t i = 0; i < labels->count; ++i) {
258         if (strcmp(target, labels->ids[i]) == 0) {
259             return labels_action(labels, i, gc, scope, rest);
260         }
261     }
262
263     return unknown_target(gc, "label", target);
264 }