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