]> git.lizzy.rs Git - nothing.git/blob - src/game/level/labels.c
95ea708775fe2f2b184209775de286888f404271
[nothing.git] / src / game / level / labels.c
1 #include <stdio.h>
2 #include <stdbool.h>
3
4 #include "config.h"
5 #include "game/camera.h"
6 #include "game/level/labels.h"
7 #include "game/level/level_editor/label_layer.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 enum LabelState
16 {
17     LABEL_STATE_VIRGIN = 0,
18     LABEL_STATE_APPEARED,
19     LABEL_STATE_HIDDEN
20 };
21
22 struct Labels
23 {
24     Lt *lt;
25     size_t count;
26     char *ids;
27     Vec2f *positions;
28     Color *colors;
29     char **texts;
30
31     /* Animation state */
32     float *alphas;
33     float *delta_alphas;
34     enum LabelState *states;
35 };
36
37 Labels *create_labels_from_label_layer(const LabelLayer *label_layer)
38 {
39     trace_assert(label_layer);
40
41     Lt *lt = create_lt();
42
43     Labels *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     labels->count = label_layer_count(label_layer);
50
51     labels->ids = PUSH_LT(lt, nth_calloc(labels->count, sizeof(char) * ENTITY_MAX_ID_SIZE), free);
52     if (labels->ids == NULL) {
53         RETURN_LT(lt, NULL);
54     }
55     memcpy(labels->ids,
56            label_layer_ids(label_layer),
57            labels->count * sizeof(char) * ENTITY_MAX_ID_SIZE);
58
59     labels->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec2f) * labels->count), free);
60     if (labels->positions == NULL) {
61         RETURN_LT(lt, NULL);
62     }
63     memcpy(labels->positions,
64            label_layer_positions(label_layer),
65            labels->count * sizeof(Vec2f));
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     memcpy(labels->colors,
72            label_layer_colors(label_layer),
73            labels->count * sizeof(Color));
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     char *texts = labels_layer_texts(label_layer);
81     for (size_t i = 0; i < labels->count; ++i) {
82         labels->texts[i] = PUSH_LT(
83             labels->lt,
84             string_duplicate(texts + i * LABEL_LAYER_TEXT_MAX_SIZE, NULL),
85             free);
86     }
87
88     labels->alphas = PUSH_LT(lt, nth_calloc(1, sizeof(float) * labels->count), free);
89     if (labels->alphas == NULL) {
90         RETURN_LT(lt, NULL);
91     }
92
93     labels->delta_alphas = PUSH_LT(lt, nth_calloc(1, sizeof(float) * labels->count), free);
94     if (labels->delta_alphas == NULL) {
95         RETURN_LT(lt, NULL);
96     }
97
98     labels->states = PUSH_LT(lt, nth_calloc(1, sizeof(enum LabelState) * labels->count), free);
99     if (labels->states == NULL) {
100         RETURN_LT(lt, NULL);
101     }
102
103     return labels;
104 }
105
106 void destroy_labels(Labels *label)
107 {
108     trace_assert(label);
109     RETURN_LT0(label->lt);
110 }
111
112 int labels_render(const Labels *label,
113                   const Camera *camera)
114 {
115     trace_assert(label);
116     trace_assert(camera);
117
118     for (size_t i = 0; i < label->count; ++i) {
119         /* Easing */
120         const float state = label->alphas[i] * (2 - label->alphas[i]);
121
122         if (camera_render_text(camera,
123                                label->texts[i],
124                                LABELS_SIZE,
125                                rgba(label->colors[i].r,
126                                     label->colors[i].g,
127                                     label->colors[i].b,
128                                     state),
129                                vec_sum(label->positions[i],
130                                        vec(0.0f, -8.0f * state))) < 0) {
131             return -1;
132         }
133     }
134
135     return 0;
136 }
137
138 void labels_update(Labels *label,
139                    float delta_time)
140 {
141     trace_assert(label);
142     (void) delta_time;
143
144     for (size_t i = 0; i < label->count; ++i) {
145         label->alphas[i] = label->alphas[i] + label->delta_alphas[i] * delta_time;
146
147         if (label->alphas[i] < 0.0f) {
148             label->alphas[i] = 0.0f;
149             label->delta_alphas[i] = 0.0f;
150         }
151
152         if (label->alphas[i] > 1.0f) {
153             label->alphas[i] = 1.0f;
154             label->delta_alphas[i] = 0.0f;
155         }
156     }
157 }
158
159 void labels_enter_camera_event(Labels *labels,
160                                const Camera *camera)
161 {
162     trace_assert(labels);
163     trace_assert(camera);
164
165     for (size_t i = 0; i < labels->count; ++i) {
166         const int became_visible = camera_is_text_visible(
167             camera,
168             vec(2.0f, 2.0f),
169             labels->positions[i],
170             labels->texts[i]);
171
172         if (labels->states[i] == LABEL_STATE_VIRGIN && became_visible) {
173             labels->states[i] = LABEL_STATE_APPEARED;
174             labels->alphas[i] = 0.0f;
175             labels->delta_alphas[i] = 1.0f;
176         }
177     }
178 }
179
180 void labels_hide(Labels *labels, char id[ENTITY_MAX_ID_SIZE])
181 {
182     trace_assert(labels);
183     trace_assert(id);
184
185     for (size_t i = 0; i < labels->count; ++i) {
186         if (strncmp(id, labels->ids + i * ENTITY_MAX_ID_SIZE, ENTITY_MAX_ID_SIZE) == 0) {
187             if (labels->states[i] != LABEL_STATE_HIDDEN) {
188                 labels->states[i] = LABEL_STATE_HIDDEN;
189                 labels->alphas[i] = 1.0f;
190                 labels->delta_alphas[i] = -3.0f;
191             }
192             return;
193         }
194     }
195 }