]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/rect_layer.c
(#950) Draw the overlay always on top
[nothing.git] / src / game / level / level_editor / rect_layer.c
1 #include "game/camera.h"
2 #include "system/lt.h"
3 #include "system/stacktrace.h"
4 #include "system/nth_alloc.h"
5 #include "system/log.h"
6 #include "math/rect.h"
7 #include "color.h"
8 #include "rect_layer.h"
9 #include "dynarray.h"
10 #include "system/line_stream.h"
11 #include "color_picker.h"
12 #include "system/str.h"
13 #include "ui/edit_field.h"
14
15 #define RECT_LAYER_ID_MAX_SIZE 36
16 #define RECT_LAYER_SELECTION_THICCNESS 5.0f
17 #define CREATE_AREA_THRESHOLD 10.0
18
19 typedef enum {
20     RECT_LAYER_IDLE = 0,
21     RECT_LAYER_CREATE,
22     RECT_LAYER_RESIZE,
23     RECT_LAYER_MOVE,
24     RECT_LAYER_ID_RENAME,
25 } RectLayerState;
26
27 struct RectLayer {
28     Lt *lt;
29     RectLayerState state;
30     Dynarray *ids;
31     Dynarray *rects;
32     Dynarray *colors;
33     ColorPicker color_picker;
34     Vec create_begin;
35     Vec create_end;
36     int selection;
37     Vec move_anchor;
38     Edit_field *id_edit_field;
39 };
40
41 typedef int (*EventHandler)(RectLayer *layer, const SDL_Event *event, const Camera *camera);
42
43 static int rect_layer_add_rect(RectLayer *layer, Rect rect, Color color)
44 {
45     trace_assert(layer);
46
47     if (dynarray_push(layer->rects, &rect) < 0) {
48         return -1;
49     }
50
51     if (dynarray_push(layer->colors, &color) < 0) {
52         return -1;
53     }
54
55     char id[RECT_LAYER_ID_MAX_SIZE];
56     for (size_t i = 0; i < RECT_LAYER_ID_MAX_SIZE - 1; ++i) {
57         id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
58     }
59     id[RECT_LAYER_ID_MAX_SIZE - 1] = '\0';
60
61     if (dynarray_push(layer->ids, id)) {
62         return -1;
63     }
64
65     return 0;
66 }
67
68 static int rect_layer_rect_at(RectLayer *layer, Vec position)
69 {
70     trace_assert(layer);
71
72     const size_t n = dynarray_count(layer->rects);
73     Rect *rects = dynarray_data(layer->rects);
74
75     for (size_t i = 0; i < n; ++i) {
76         if (rect_contains_point(rects[i], position)) {
77             return (int) i;
78         }
79     }
80
81     return -1;
82 }
83
84 static Rect rect_layer_resize_anchor(const RectLayer *layer, size_t i)
85 {
86     Rect *rects = dynarray_data(layer->rects);
87     return rect(rects[i].x + rects[i].w,
88                 rects[i].y + rects[i].h,
89                 RECT_LAYER_SELECTION_THICCNESS * 2.0f,
90                 RECT_LAYER_SELECTION_THICCNESS * 2.0f);
91 }
92
93 static int rect_layer_delete_rect_at(RectLayer *layer, size_t i)
94 {
95     trace_assert(layer);
96
97     dynarray_delete_at(layer->rects, i);
98     dynarray_delete_at(layer->colors, i);
99     dynarray_delete_at(layer->ids, i);
100
101     return 0;
102 }
103
104 static int rect_layer_event_idle(RectLayer *layer, const SDL_Event *event, const Camera *camera)
105 {
106     trace_assert(layer);
107     trace_assert(event);
108     trace_assert(camera);
109
110     switch (event->type) {
111     case SDL_MOUSEBUTTONDOWN: {
112         switch (event->button.button) {
113         case SDL_BUTTON_LEFT: {
114             Point position = camera_map_screen(
115                 camera,
116                 event->button.x,
117                 event->button.y);
118             int rect_at_position =
119                 rect_layer_rect_at(layer, position);
120
121             if (rect_at_position >= 0) {
122                 Rect *rects = dynarray_data(layer->rects);
123                 layer->selection = rect_at_position;
124                 layer->state = RECT_LAYER_MOVE;
125                 layer->move_anchor =
126                     vec_sub(
127                         position,
128                         vec(
129                             rects[layer->selection].x,
130                             rects[layer->selection].y));
131             } else if (layer->selection >= 0 && rect_contains_point(
132                            rect_layer_resize_anchor(
133                                layer,
134                                (size_t)layer->selection),
135                            position)) {
136                 layer->state = RECT_LAYER_RESIZE;
137             } else {
138                 layer->selection = rect_at_position;
139
140                 if (layer->selection < 0) {
141                     layer->state = RECT_LAYER_CREATE;
142                     layer->create_begin = position;
143                     layer->create_end = position;
144                 }
145             }
146         } break;
147         }
148     } break;
149
150     case SDL_KEYDOWN: {
151         switch (event->key.keysym.sym) {
152         case SDLK_DELETE: {
153             if (layer->selection >= 0) {
154                 rect_layer_delete_rect_at(layer, (size_t) layer->selection);
155                 layer->selection = -1;
156             }
157         } break;
158
159         case SDLK_F2: {
160             if (layer->selection >= 0) {
161                 const char *ids = dynarray_data(layer->ids);
162                 layer->state = RECT_LAYER_ID_RENAME;
163                 edit_field_replace(
164                     layer->id_edit_field,
165                     ids + layer->selection * RECT_LAYER_ID_MAX_SIZE);
166                 SDL_StartTextInput();
167             }
168         } break;
169         }
170     } break;
171     }
172
173     return 0;
174 }
175
176 static int rect_layer_event_create(RectLayer *layer, const SDL_Event *event, const Camera *camera)
177 {
178     trace_assert(layer);
179     trace_assert(event);
180     trace_assert(camera);
181
182     switch (event->type) {
183     case SDL_MOUSEBUTTONUP: {
184         switch (event->button.button) {
185         case SDL_BUTTON_LEFT: {
186             const Rect real_rect =
187                 rect_from_points(
188                     layer->create_begin,
189                     layer->create_end);
190             const float area = real_rect.w * real_rect.h;
191
192             if (area >= CREATE_AREA_THRESHOLD) {
193                 rect_layer_add_rect(
194                     layer,
195                     real_rect,
196                     color_picker_rgba(&layer->color_picker));
197             } else {
198                 log_info("The area is too small %f. Such small box won't be created.\n", area);
199             }
200             layer->state = RECT_LAYER_IDLE;
201         } break;
202         }
203     } break;
204
205     case SDL_MOUSEMOTION: {
206         layer->create_end = camera_map_screen(
207             camera,
208             event->motion.x,
209             event->motion.y);
210     } break;
211     }
212     return 0;
213 }
214
215 static int rect_layer_event_resize(RectLayer *layer, const SDL_Event *event, const Camera *camera)
216 {
217     trace_assert(layer);
218     trace_assert(event);
219     trace_assert(camera);
220
221     switch (event->type) {
222     case SDL_MOUSEMOTION: {
223         Rect *rects = dynarray_data(layer->rects);
224         trace_assert(layer->selection >= 0);
225         rects[layer->selection] = rect_from_points(
226             vec(rects[layer->selection].x, rects[layer->selection].y),
227             vec_sum(
228                 camera_map_screen(
229                     camera,
230                     event->button.x,
231                     event->button.y),
232                 vec(RECT_LAYER_SELECTION_THICCNESS * -0.5f,
233                     RECT_LAYER_SELECTION_THICCNESS * -0.5f)));
234     } break;
235
236     case SDL_MOUSEBUTTONUP: {
237         layer->state = RECT_LAYER_IDLE;
238     } break;
239     }
240
241     return 0;
242 }
243
244 static int rect_layer_event_move(RectLayer *layer, const SDL_Event *event, const Camera *camera)
245 {
246     trace_assert(layer);
247     trace_assert(event);
248     trace_assert(camera);
249
250     switch (event->type) {
251     case SDL_MOUSEMOTION: {
252         Point position = vec_sub(
253             camera_map_screen(
254                 camera,
255                 event->button.x,
256                 event->button.y),
257             layer->move_anchor);
258
259         Rect *rects = dynarray_data(layer->rects);
260
261         trace_assert(layer->selection >= 0);
262
263         rects[layer->selection].x = position.x;
264         rects[layer->selection].y = position.y;
265     } break;
266
267     case SDL_MOUSEBUTTONUP: {
268         layer->state = RECT_LAYER_IDLE;
269     } break;
270     }
271     return 0;
272 }
273
274 static int rect_layer_event_id_rename(RectLayer *layer, const SDL_Event *event, const Camera *camera)
275 {
276     trace_assert(layer);
277     trace_assert(event);
278     trace_assert(camera);
279
280     switch (event->type) {
281     case SDL_TEXTINPUT: {
282         if (edit_field_text_input(layer->id_edit_field, &event->text) < 0) {
283             return -1;
284         }
285     } break;
286
287     case SDL_KEYDOWN: {
288         switch (event->key.keysym.sym) {
289         case SDLK_RETURN: {
290             char *id =
291                 (char *)dynarray_data(layer->ids) + layer->selection * RECT_LAYER_ID_MAX_SIZE;
292             memset(id, 0, RECT_LAYER_ID_MAX_SIZE);
293             memcpy(id, edit_field_as_text(layer->id_edit_field), RECT_LAYER_ID_MAX_SIZE - 1);
294             layer->state = RECT_LAYER_IDLE;
295         } break;
296         }
297
298         if (edit_field_keyboard(layer->id_edit_field, &event->key) < 0) {
299             return -1;
300         }
301     } break;
302
303     case SDL_KEYUP: {
304         if (edit_field_keyboard(layer->id_edit_field, &event->key) < 0) {
305             return -1;
306         }
307     } break;
308     }
309     return 0;
310 }
311
312 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
313 {
314     LayerPtr layer = {
315         .type = LAYER_RECT,
316         .ptr = rect_layer
317     };
318     return layer;
319 }
320
321 RectLayer *create_rect_layer(void)
322 {
323     Lt *lt = create_lt();
324
325     RectLayer *layer = PUSH_LT(lt, nth_calloc(1, sizeof(RectLayer)), free);
326     if (layer == NULL) {
327         RETURN_LT(lt, NULL);
328     }
329     layer->lt = lt;
330
331     layer->ids = PUSH_LT(
332         lt,
333         create_dynarray(sizeof(char) * RECT_LAYER_ID_MAX_SIZE),
334         destroy_dynarray);
335     if (layer->ids == NULL) {
336         RETURN_LT(lt, NULL);
337     }
338
339     layer->rects = PUSH_LT(
340         lt,
341         create_dynarray(sizeof(Rect)),
342         destroy_dynarray);
343     if (layer->rects == NULL) {
344         RETURN_LT(lt, NULL);
345     }
346
347     layer->colors = PUSH_LT(
348         lt,
349         create_dynarray(sizeof(Color)),
350         destroy_dynarray);
351     if (layer->colors == NULL) {
352         RETURN_LT(lt, NULL);
353     }
354
355     layer->id_edit_field = PUSH_LT(
356         lt,
357         create_edit_field(
358             vec(3.0f, 3.0f),
359             COLOR_BLACK),
360         destroy_edit_field);
361     if (layer->id_edit_field == NULL) {
362         RETURN_LT(lt, NULL);
363     }
364
365     layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
366     layer->selection = -1;
367
368     return layer;
369 }
370
371 RectLayer *create_rect_layer_from_line_stream(LineStream *line_stream)
372 {
373     trace_assert(line_stream);
374
375     RectLayer *layer = create_rect_layer();
376     if (layer == NULL) {
377         return NULL;
378     }
379
380     const char *line = line_stream_next(line_stream);
381     if (line == NULL) {
382         RETURN_LT(layer->lt, NULL);
383     }
384
385     size_t count = 0;
386     if (sscanf(line, "%zu", &count) < 0) {
387         RETURN_LT(layer->lt, NULL);
388     }
389
390     for (size_t i = 0; i < count; ++i) {
391         line = line_stream_next(line_stream);
392         if (line == NULL) {
393             RETURN_LT(layer->lt, NULL);
394         }
395
396         char hex[7];
397         Rect rect;
398         char id[RECT_LAYER_ID_MAX_SIZE];
399
400         if (sscanf(line,
401                    "%"STRINGIFY(RECT_LAYER_ID_MAX_SIZE)"s%f%f%f%f%6s\n",
402                    id,
403                    &rect.x, &rect.y,
404                    &rect.w, &rect.h,
405                    hex) < 0) {
406             RETURN_LT(layer->lt, NULL);
407         }
408
409         Color color = hexstr(hex);
410
411         dynarray_push(layer->rects, &rect);
412         dynarray_push(layer->ids, id);
413         dynarray_push(layer->colors, &color);
414     }
415
416     return layer;
417 }
418
419 void destroy_rect_layer(RectLayer *layer)
420 {
421     trace_assert(layer);
422     RETURN_LT0(layer->lt);
423 }
424
425 int rect_layer_render(const RectLayer *layer, Camera *camera, int active)
426 {
427     trace_assert(layer);
428     trace_assert(camera);
429
430     const size_t n = dynarray_count(layer->rects);
431     Rect *rects = dynarray_data(layer->rects);
432     Color *colors = dynarray_data(layer->colors);
433     const char *ids = dynarray_data(layer->ids);
434
435     // The Rectangles
436     for (size_t i = 0; i < n; ++i) {
437         if (camera_fill_rect(
438                 camera,
439                 rects[i],
440                 color_scale(
441                     colors[i],
442                     rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
443             return -1;
444         }
445     }
446
447     // Proto Rectangle
448     const Color color = color_picker_rgba(&layer->color_picker);
449     if (layer->state == RECT_LAYER_CREATE) {
450         if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
451             return -1;
452         }
453     }
454
455     // ID renaming Edit Field
456     if (layer->state == RECT_LAYER_ID_RENAME) {
457         if (edit_field_render(layer->id_edit_field, camera, vec(400.0f, 400.0f)) < 0) {
458             return -1;
459         }
460     }
461
462     // Selection Overlay
463     if (active && layer->selection >= 0) {
464         const Color overlay_color = color_invert(colors[layer->selection]);
465
466         // Overlay Rectanglea
467         if (camera_fill_rect(
468                 camera,
469                 rect_scale(rects[layer->selection], RECT_LAYER_SELECTION_THICCNESS),
470                 overlay_color) < 0) {
471             return -1;
472         }
473
474         // Main Rectangle
475         if (camera_fill_rect(
476                 camera,
477                 rects[layer->selection],
478                 color_scale(
479                     colors[layer->selection],
480                     rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
481             return -1;
482         }
483
484         // Rectangle Id
485         if (camera_render_text(
486                 camera,
487                 ids + layer->selection * RECT_LAYER_ID_MAX_SIZE,
488                 vec(3.0f, 3.0f),
489                 color_invert(colors[layer->selection]),
490                 rect_position(rects[layer->selection])) < 0) {
491             return -1;
492         }
493
494         // Resize Anchor
495         if (camera_fill_rect(
496                 camera,
497                 rect_layer_resize_anchor(layer, (size_t) layer->selection),
498                 overlay_color) < 0) {
499             return -1;
500         }
501     }
502
503     if (active && color_picker_render(&layer->color_picker, camera) < 0) {
504         return -1;
505     }
506
507     return 0;
508 }
509
510 int rect_layer_event(RectLayer *layer, const SDL_Event *event, const Camera *camera)
511 {
512     trace_assert(layer);
513     trace_assert(event);
514
515     int selected = 0;
516     if (color_picker_event(&layer->color_picker, event, &selected) < 0) {
517         return -1;
518     }
519
520     if (selected) {
521         return 0;
522     }
523
524     switch (layer->state) {
525     case RECT_LAYER_IDLE:
526         return rect_layer_event_idle(layer, event, camera);
527
528     case RECT_LAYER_CREATE:
529         return rect_layer_event_create(layer, event, camera);
530
531     case RECT_LAYER_RESIZE:
532         return rect_layer_event_resize(layer, event, camera);
533
534     case RECT_LAYER_MOVE:
535         return rect_layer_event_move(layer, event, camera);
536
537     case RECT_LAYER_ID_RENAME:
538         return rect_layer_event_id_rename(layer, event, camera);
539     }
540
541     return 0;
542 }
543
544 size_t rect_layer_count(const RectLayer *layer)
545 {
546     return dynarray_count(layer->rects);
547 }
548
549 const Rect *rect_layer_rects(const RectLayer *layer)
550 {
551     return dynarray_data(layer->rects);
552 }
553
554 const Color *rect_layer_colors(const RectLayer *layer)
555 {
556     return dynarray_data(layer->colors);
557 }
558
559 const char *rect_layer_ids(const RectLayer *layer)
560 {
561     return dynarray_data(layer->ids);
562 }
563
564 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
565 {
566     trace_assert(layer);
567     trace_assert(filedump);
568
569     size_t n = dynarray_count(layer->ids);
570     char *ids = dynarray_data(layer->ids);
571     Rect *rects = dynarray_data(layer->rects);
572     Color *colors = dynarray_data(layer->colors);
573
574     fprintf(filedump, "%zd\n", n);
575     for (size_t i = 0; i < n; ++i) {
576         fprintf(filedump, "%s %f %f %f %f ",
577                 ids + RECT_LAYER_ID_MAX_SIZE * i,
578                 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
579         color_hex_to_stream(colors[i], filedump);
580         fprintf(filedump, "\n");
581     }
582
583     return 0;
584 }