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