]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/point_layer.c
(#964) Make LabelLayer display the ids
[nothing.git] / src / game / level / level_editor / point_layer.c
1 #include <stdio.h>
2
3 #include <SDL.h>
4
5 #include "dynarray.h"
6 #include "game/camera.h"
7 #include "system/line_stream.h"
8 #include "system/log.h"
9 #include "system/lt.h"
10 #include "system/nth_alloc.h"
11 #include "system/stacktrace.h"
12 #include "system/str.h"
13 #include "ui/edit_field.h"
14 #include "./point_layer.h"
15 #include "math/extrema.h"
16 #include "./color_picker.h"
17
18 #define POINT_LAYER_ELEMENT_RADIUS 10.0f
19
20 typedef enum {
21     POINT_LAYER_IDLE = 0,
22     POINT_LAYER_EDIT_ID
23 } PointLayerState;
24
25 struct PointLayer
26 {
27     Lt *lt;
28     PointLayerState state;
29     Dynarray/*<Point>*/ *points;
30     Dynarray/*<Color>*/ *colors;
31     Dynarray/*<char[ID_MAX_SIZE]>*/ *ids;
32     Edit_field *edit_field;
33     int selected;
34     ColorPicker color_picker;
35 };
36
37 LayerPtr point_layer_as_layer(PointLayer *point_layer)
38 {
39     LayerPtr layer = {
40         .type = LAYER_POINT,
41         .ptr = point_layer
42     };
43     return layer;
44 }
45
46 PointLayer *create_point_layer(void)
47 {
48     Lt *lt = create_lt();
49
50     PointLayer *point_layer = PUSH_LT(lt, nth_calloc(1, sizeof(PointLayer)), free);
51     if (point_layer == NULL) {
52         RETURN_LT(lt, NULL);
53     }
54     point_layer->lt = lt;
55
56     point_layer->state = POINT_LAYER_IDLE;
57
58     point_layer->points = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray);
59     if (point_layer->points == NULL) {
60         RETURN_LT(lt, NULL);
61     }
62
63     point_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
64     if (point_layer->colors == NULL) {
65         RETURN_LT(lt, NULL);
66     }
67
68     point_layer->ids = PUSH_LT(lt, create_dynarray(sizeof(char) * ID_MAX_SIZE), destroy_dynarray);
69     if (point_layer->ids == NULL) {
70         RETURN_LT(lt, NULL);
71     }
72
73     point_layer->edit_field = PUSH_LT(
74         lt,
75         create_edit_field(
76             vec(5.0f, 5.0f),
77             rgba(0.0f, 0.0f, 0.0f, 1.0f)),
78         destroy_edit_field);
79     if (point_layer->edit_field == NULL) {
80         RETURN_LT(lt, NULL);
81     }
82
83     return point_layer;
84 }
85
86 PointLayer *create_point_layer_from_line_stream(LineStream *line_stream)
87 {
88     trace_assert(line_stream);
89
90     PointLayer *point_layer = create_point_layer();
91
92     size_t count = 0;
93     if (sscanf(
94             line_stream_next(line_stream),
95             "%zu",
96             &count) == EOF) {
97         log_fail("Could not read amount of points");
98         RETURN_LT(point_layer->lt, NULL);
99     }
100
101     char color_name[7];
102     char id[ID_MAX_SIZE];
103     float x, y;
104     for (size_t i = 0; i < count; ++i) {
105         if (sscanf(
106                 line_stream_next(line_stream),
107                 "%"STRINGIFY(ID_MAX_SIZE)"s%f%f%6s",
108                 id, &x, &y, color_name) < 0) {
109             log_fail("Could not read %dth goal\n", i);
110             RETURN_LT(point_layer->lt, NULL);
111         }
112         const Color color = hexstr(color_name);
113         const Point point = vec(x, y);
114
115         dynarray_push(point_layer->colors, &color);
116         dynarray_push(point_layer->points, &point);
117         dynarray_push(point_layer->ids, id);
118     }
119
120     point_layer->selected = -1;
121
122     point_layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
123
124     return point_layer;
125 }
126
127 void destroy_point_layer(PointLayer *point_layer)
128 {
129     trace_assert(point_layer);
130     RETURN_LT0(point_layer->lt);
131 }
132
133 int point_layer_render(const PointLayer *point_layer,
134                        Camera *camera,
135                        int active)
136 {
137     trace_assert(point_layer);
138     trace_assert(camera);
139
140     const int n = (int) dynarray_count(point_layer->points);
141     Point *points = dynarray_data(point_layer->points);
142     Color *colors = dynarray_data(point_layer->colors);
143
144     for (int i = 0; i < n; ++i) {
145         const Triangle t = triangle_mat3x3_product(
146             equilateral_triangle(),
147             mat3x3_product(
148                 trans_mat(points[i].x, points[i].y),
149                 scale_mat(POINT_LAYER_ELEMENT_RADIUS)));
150
151         const Color color = color_scale(
152             colors[i],
153             rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f));
154
155         if (i == point_layer->selected) {
156             const Triangle t0 = triangle_mat3x3_product(
157                 equilateral_triangle(),
158                 mat3x3_product(
159                     trans_mat(points[i].x, points[i].y),
160                     scale_mat(15.0f)));
161
162             if (camera_fill_triangle(camera, t0, color_invert(color)) < 0) {
163                 return -1;
164             }
165         }
166
167         if (camera_fill_triangle(camera, t, color) < 0) {
168             return -1;
169         }
170
171         /* TODO(#854): The ids of PointLayer are not displayed constantly */
172     }
173
174     if (point_layer->state == POINT_LAYER_EDIT_ID) {
175         /* TODO(#855): PointLayer edit field is not scaled on zoom */
176         if (edit_field_render_screen(
177                 point_layer->edit_field,
178                 camera,
179                 camera_point(camera, points[point_layer->selected])) < 0) {
180             return -1;
181         }
182     }
183
184     if (active && color_picker_render(&point_layer->color_picker, camera) < 0) {
185         return -1;
186     }
187
188
189     return 0;
190 }
191
192 static
193 int point_layer_idle_event(PointLayer *point_layer,
194                            const SDL_Event *event,
195                            const Camera *camera)
196 {
197     trace_assert(point_layer);
198     trace_assert(event);
199     trace_assert(camera);
200
201     int selected = 0;
202     if (color_picker_event(
203             &point_layer->color_picker,
204             event,
205             &selected) < 0) {
206         return -1;
207     }
208
209     if (selected) {
210         return 0;
211     }
212
213     switch (event->type) {
214     case SDL_MOUSEBUTTONDOWN: {
215         switch (event->button.button) {
216         case SDL_BUTTON_LEFT: {
217             const int n = (int) dynarray_count(point_layer->points);
218             const Point *points = dynarray_data(point_layer->points);
219             const Point point = camera_map_screen(camera, event->button.x, event->button.y);
220             const Color color = color_picker_rgba(&point_layer->color_picker);
221
222             for (int i = 0; i < n; ++i) {
223                 if (vec_length(vec_sub(points[i], point)) < POINT_LAYER_ELEMENT_RADIUS) {
224                     point_layer->selected = i;
225                     return 0;
226                 }
227             }
228
229             char id[ID_MAX_SIZE];
230
231             for (size_t i = 0; i < ID_MAX_SIZE - 1; ++i) {
232                 id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
233             }
234             id[ID_MAX_SIZE - 1] = '\0';
235
236             dynarray_push(point_layer->points, &point);
237             dynarray_push(point_layer->colors, &color);
238             dynarray_push(point_layer->ids, id);
239         } break;
240         }
241     } break;
242
243     case SDL_KEYDOWN: {
244         switch (event->key.keysym.sym) {
245         case SDLK_DELETE: {
246             if (0 <= point_layer->selected && point_layer->selected < (int) dynarray_count(point_layer->points)) {
247                 dynarray_delete_at(point_layer->points, (size_t) point_layer->selected);
248                 dynarray_delete_at(point_layer->colors, (size_t) point_layer->selected);
249                 dynarray_delete_at(point_layer->ids, (size_t) point_layer->selected);
250             }
251             point_layer->selected = -1;
252         } break;
253
254         case SDLK_F2: {
255             if (point_layer->selected >= 0) {
256                 char *ids = dynarray_data(point_layer->ids);
257                 point_layer->state = POINT_LAYER_EDIT_ID;
258                 edit_field_replace(
259                     point_layer->edit_field,
260                     ids + ID_MAX_SIZE * point_layer->selected);
261                 SDL_StartTextInput();
262             }
263         } break;
264         }
265     } break;
266     }
267
268     return 0;
269 }
270
271 static
272 int point_layer_edit_id_event(PointLayer *point_layer,
273                               const SDL_Event *event,
274                               const Camera *camera)
275 {
276     trace_assert(point_layer);
277     trace_assert(event);
278     trace_assert(camera);
279
280     switch (event->type) {
281     case SDL_KEYDOWN: {
282         switch(event->key.keysym.sym) {
283         case SDLK_RETURN: {
284             char *ids = dynarray_data(point_layer->ids);
285             const char *text = edit_field_as_text(point_layer->edit_field);
286             size_t n = max_size_t(strlen(text), ID_MAX_SIZE - 1);
287             memcpy(ids + point_layer->selected * ID_MAX_SIZE, text, n);
288             *(ids + point_layer->selected * ID_MAX_SIZE + n) = '\0';
289             point_layer->state = POINT_LAYER_IDLE;
290             SDL_StopTextInput();
291             return 0;
292         } break;
293
294         case SDLK_ESCAPE: {
295             point_layer->state = POINT_LAYER_IDLE;
296             SDL_StopTextInput();
297             return 0;
298         } break;
299         }
300     } break;
301     }
302
303     return edit_field_event(point_layer->edit_field, event);
304 }
305
306 int point_layer_event(PointLayer *point_layer,
307                       const SDL_Event *event,
308                       const Camera *camera)
309 {
310     trace_assert(point_layer);
311     trace_assert(event);
312     trace_assert(camera);
313
314     switch (point_layer->state) {
315     case POINT_LAYER_IDLE:
316         return point_layer_idle_event(point_layer, event, camera);
317
318     case POINT_LAYER_EDIT_ID:
319         return point_layer_edit_id_event(point_layer, event, camera);
320     }
321
322     return 0;
323 }
324
325 size_t point_layer_count(const PointLayer *point_layer)
326 {
327     trace_assert(point_layer);
328     return dynarray_count(point_layer->points);
329 }
330
331 const Point *point_layer_points(const PointLayer *point_layer)
332 {
333     trace_assert(point_layer);
334     return dynarray_data(point_layer->points);
335 }
336
337 const Color *point_layer_colors(const PointLayer *point_layer)
338 {
339     trace_assert(point_layer);
340     return dynarray_data(point_layer->colors);
341 }
342
343 const char *point_layer_ids(const PointLayer *point_layer)
344 {
345     trace_assert(point_layer);
346     return dynarray_data(point_layer->ids);
347 }
348
349 int point_layer_dump_stream(const PointLayer *point_layer,
350                             FILE *filedump)
351 {
352     trace_assert(point_layer);
353     trace_assert(filedump);
354
355     size_t n = dynarray_count(point_layer->ids);
356     char *ids = dynarray_data(point_layer->ids);
357     Point *points = dynarray_data(point_layer->points);
358     Color *colors = dynarray_data(point_layer->colors);
359
360     fprintf(filedump, "%zd\n", n);
361     for (size_t i = 0; i < n; ++i) {
362         fprintf(filedump, "%s %f %f ",
363                 ids + ID_MAX_SIZE * i,
364                 points[i].x, points[i].y);
365         color_hex_to_stream(colors[i], filedump);
366         fprintf(filedump, "\n");
367     }
368
369     return 0;
370 }