]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/rect_layer.c
(#1108) add development ding
[nothing.git] / src / game / level / level_editor / rect_layer.c
1 #include <errno.h>
2
3 #include "game/camera.h"
4 #include "system/lt.h"
5 #include "system/stacktrace.h"
6 #include "system/nth_alloc.h"
7 #include "system/log.h"
8 #include "math/rect.h"
9 #include "color.h"
10 #include "rect_layer.h"
11 #include "dynarray.h"
12 #include "system/line_stream.h"
13 #include "color_picker.h"
14 #include "system/str.h"
15 #include "ui/edit_field.h"
16 #include "undo_history.h"
17 #include "game/level/action.h"
18
19 #define RECT_LAYER_SELECTION_THICCNESS 10.0f
20 #define RECT_LAYER_ID_LABEL_SIZE vec(3.0f, 3.0f)
21 #define CREATE_AREA_THRESHOLD 10.0
22
23 static int clipboard = 0;
24 static Rect clipboard_rect;
25 static Color clipboard_color;
26
27 typedef enum {
28     RECT_LAYER_IDLE = 0,
29     RECT_LAYER_CREATE,
30     // TODO(#955): Rectangles in Level Editor have only one resize anchor to work with
31     RECT_LAYER_RESIZE,
32     RECT_LAYER_MOVE,
33     RECT_LAYER_ID_RENAME,
34     RECT_LAYER_RECOLOR
35 } RectLayerState;
36
37 struct RectLayer {
38     Lt *lt;
39     RectLayerState state;
40     Dynarray *ids;
41     Dynarray *rects;
42     Dynarray *colors;
43     Dynarray *actions;
44     ColorPicker color_picker;
45     Vec2f create_begin;
46     Vec2f create_end;
47     int selection;
48     Vec2f move_anchor;
49     Edit_field *id_edit_field;
50     Color inter_color;
51     Rect inter_rect;
52     int id_name_counter;
53     const char *id_name_prefix;
54 };
55
56 typedef enum {
57     UNDO_ADD,
58     UNDO_DELETE,
59     UNDO_UPDATE,
60     UNDO_SWAP
61 } UndoType;
62
63 // Delete, Update
64 typedef struct {
65     UndoType type;
66     RectLayer *layer;
67     size_t index;
68     Rect rect;
69     Color color;
70     Action action;
71     char id[ENTITY_MAX_ID_SIZE];
72 } UndoElementContext;
73
74 // Add
75 typedef struct {
76     UndoType type;
77     RectLayer *layer;
78     size_t index;
79 } UndoAddContext;
80
81 // Swap
82 typedef struct {
83     UndoType type;
84     RectLayer *layer;
85     size_t index1;
86     size_t index2;
87 } UndoSwapContext;
88
89 typedef union {
90     UndoType type;
91     UndoAddContext add;
92     UndoElementContext element;
93     UndoSwapContext swap;
94 } UndoContext;
95
96 static
97 UndoContext create_undo_add_context(RectLayer *layer, size_t index)
98 {
99     trace_assert(layer);
100     trace_assert(index < dynarray_count(layer->rects));
101
102     UndoContext undo_context;
103     undo_context.add.type = UNDO_ADD;
104     undo_context.add.layer = layer;
105     undo_context.add.index = index;
106     return undo_context;
107 }
108
109 static
110 UndoContext create_undo_element_context(RectLayer *layer)
111 {
112     trace_assert(layer);
113     size_t index = (size_t) layer->selection;
114     trace_assert(index < dynarray_count(layer->rects));
115
116     UndoContext undo_context;
117     undo_context.element.layer = layer;
118     undo_context.element.index = index;
119     dynarray_copy_to(layer->rects, &undo_context.element.rect, index);
120     dynarray_copy_to(layer->colors, &undo_context.element.color, index);
121     dynarray_copy_to(layer->ids, undo_context.element.id, index);
122     dynarray_copy_to(layer->actions, &undo_context.element.action, index);
123     return undo_context;
124 }
125
126 static
127 UndoContext create_undo_update_context(RectLayer *rect_layer)
128 {
129     UndoContext undo_context = create_undo_element_context(rect_layer);
130     undo_context.type = UNDO_UPDATE;
131     return undo_context;
132 }
133
134 static
135 UndoContext create_undo_delete_context(RectLayer *rect_layer)
136 {
137     UndoContext undo_context = create_undo_element_context(rect_layer);
138     undo_context.type = UNDO_DELETE;
139     return undo_context;
140 }
141
142 static
143 UndoContext create_undo_swap_context(RectLayer *rect_layer, size_t index1, size_t index2)
144 {
145     UndoContext undo_context;
146     undo_context.swap.type = UNDO_SWAP;
147     undo_context.swap.layer = rect_layer;
148     undo_context.swap.index1 = index1;
149     undo_context.swap.index2 = index2;
150     return undo_context;
151 }
152
153 static
154 void rect_layer_undo(void *context, size_t context_size)
155 {
156     trace_assert(context);
157     trace_assert(sizeof(UndoContext) == context_size);
158
159     UndoContext *undo_context = context;
160
161     switch (undo_context->type) {
162     case UNDO_ADD: {
163         RectLayer *layer = undo_context->add.layer;
164         dynarray_delete_at(layer->rects, undo_context->add.index);
165         dynarray_delete_at(layer->colors, undo_context->add.index);
166         dynarray_delete_at(layer->ids, undo_context->add.index);
167         dynarray_delete_at(layer->actions, undo_context->add.index);
168         layer->selection = -1;
169     } break;
170
171     case UNDO_DELETE: {
172         RectLayer *layer = undo_context->element.layer;
173         dynarray_insert_before(layer->rects, undo_context->element.index, &undo_context->element.rect);
174         dynarray_insert_before(layer->colors, undo_context->element.index, &undo_context->element.color);
175         dynarray_insert_before(layer->ids, undo_context->element.index, &undo_context->element.id);
176         dynarray_insert_before(layer->actions, undo_context->element.index, &undo_context->element.action);
177         layer->selection = -1;
178     } break;
179
180     case UNDO_UPDATE: {
181         RectLayer *layer = undo_context->element.layer;
182         dynarray_replace_at(layer->rects, undo_context->element.index, &undo_context->element.rect);
183         dynarray_replace_at(layer->colors, undo_context->element.index, &undo_context->element.color);
184         dynarray_replace_at(layer->ids, undo_context->element.index, &undo_context->element.id);
185         dynarray_replace_at(layer->actions, undo_context->element.index, &undo_context->element.action);
186     } break;
187
188     case UNDO_SWAP: {
189         RectLayer *layer = undo_context->element.layer;
190         dynarray_swap(layer->rects, undo_context->swap.index1, undo_context->swap.index2);
191         dynarray_swap(layer->colors, undo_context->swap.index1, undo_context->swap.index2);
192         dynarray_swap(layer->ids, undo_context->swap.index1, undo_context->swap.index2);
193         dynarray_swap(layer->actions, undo_context->swap.index1, undo_context->swap.index2);
194     } break;
195     }
196 }
197
198 #define UNDO_PUSH(HISTORY, CONTEXT)                                     \
199     do {                                                                \
200         UndoContext context = (CONTEXT);                                \
201         undo_history_push(                                              \
202             HISTORY,                                                    \
203             rect_layer_undo,                                            \
204             &context,                                                   \
205             sizeof(context));                                           \
206     } while(0)
207
208 static int rect_layer_add_rect(RectLayer *layer,
209                                Rect rect,
210                                Color color,
211                                UndoHistory *undo_history)
212 {
213     trace_assert(layer);
214
215     if (dynarray_push(layer->rects, &rect) < 0) {
216         return -1;
217     }
218
219     if (dynarray_push(layer->colors, &color) < 0) {
220         return -1;
221     }
222
223     char id[ENTITY_MAX_ID_SIZE];
224     snprintf(id, ENTITY_MAX_ID_SIZE, "%s_%d",
225              layer->id_name_prefix,
226              layer->id_name_counter++);
227     if (dynarray_push(layer->ids, id)) {
228         return -1;
229     }
230
231     dynarray_push_empty(layer->actions);
232
233     UNDO_PUSH(
234         undo_history,
235         create_undo_add_context(
236             layer,
237             dynarray_count(layer->rects) - 1));
238
239     return 0;
240 }
241
242 static int rect_layer_rect_at(RectLayer *layer, Vec2f position)
243 {
244     trace_assert(layer);
245
246     int n = (int) dynarray_count(layer->rects);
247     Rect *rects = dynarray_data(layer->rects);
248
249     for (int i = n - 1; i >= 0; --i) {
250         if (rect_contains_point(rects[i], position)) {
251             return (int) i;
252         }
253     }
254
255     return -1;
256 }
257
258 static void rect_layer_swap_elements(RectLayer *layer, size_t a, size_t b,
259                                      UndoHistory *undo_history)
260 {
261     trace_assert(layer);
262     trace_assert(a < dynarray_count(layer->rects));
263     trace_assert(b < dynarray_count(layer->rects));
264
265     dynarray_swap(layer->rects, a, b);
266     dynarray_swap(layer->colors, a, b);
267     dynarray_swap(layer->ids, a, b);
268     dynarray_swap(layer->actions, a, b);
269
270     UNDO_PUSH(undo_history, create_undo_swap_context(layer, a, b));
271 }
272
273 static Rect rect_layer_resize_anchor(const Camera *camera, Rect boundary_rect)
274 {
275     const Rect overlay_rect =
276         rect_scale(
277             camera_rect(camera, boundary_rect),
278             RECT_LAYER_SELECTION_THICCNESS * 0.5f);
279
280     return rect(
281         overlay_rect.x + overlay_rect.w,
282         overlay_rect.y + overlay_rect.h,
283         RECT_LAYER_SELECTION_THICCNESS * 2.0f,
284         RECT_LAYER_SELECTION_THICCNESS * 2.0f);
285 }
286
287 static int rect_layer_delete_rect_at(RectLayer *layer,
288                                      size_t i,
289                                      UndoHistory *undo_history)
290 {
291     trace_assert(layer);
292
293     UNDO_PUSH(undo_history, create_undo_delete_context(layer));
294
295     dynarray_delete_at(layer->rects, i);
296     dynarray_delete_at(layer->colors, i);
297     dynarray_delete_at(layer->ids, i);
298     dynarray_delete_at(layer->actions, i);
299
300     return 0;
301 }
302
303 static int rect_layer_event_idle(RectLayer *layer,
304                                  const SDL_Event *event,
305                                  const Camera *camera,
306                                  UndoHistory *undo_history)
307 {
308     trace_assert(layer);
309     trace_assert(event);
310     trace_assert(camera);
311
312     int color_changed = 0;
313     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
314         return -1;
315     }
316
317     if (color_changed) {
318         if (layer->selection >= 0) {
319             dynarray_copy_to(layer->colors, &layer->inter_color, (size_t)layer->selection);
320             layer->state = RECT_LAYER_RECOLOR;
321         }
322         return 0;
323     }
324
325     switch (event->type) {
326     case SDL_MOUSEBUTTONDOWN: {
327         switch (event->button.button) {
328         case SDL_BUTTON_LEFT: {
329             Vec2f position = camera_map_screen(
330                 camera,
331                 event->button.x,
332                 event->button.y);
333             int rect_at_position =
334                 rect_layer_rect_at(layer, position);
335
336             Rect *rects = dynarray_data(layer->rects);
337             Color *colors = dynarray_data(layer->colors);
338
339             if (layer->selection >= 0 && rect_contains_point(
340                     rect_layer_resize_anchor(
341                         camera,
342                         rects[layer->selection]),
343                     vec(
344                         (float) event->button.x,
345                         (float) event->button.y))) {
346                 layer->state = RECT_LAYER_RESIZE;
347                 dynarray_copy_to(layer->rects, &layer->inter_rect, (size_t) layer->selection);
348             } else if (rect_at_position >= 0) {
349                 layer->selection = rect_at_position;
350                 layer->state = RECT_LAYER_MOVE;
351                 layer->move_anchor =
352                     vec_sub(
353                         position,
354                         vec(
355                             rects[layer->selection].x,
356                             rects[layer->selection].y));
357                 layer->color_picker =
358                     create_color_picker_from_rgba(colors[rect_at_position]);
359
360                 dynarray_copy_to(layer->rects, &layer->inter_rect, (size_t) rect_at_position);
361             } else {
362                 layer->selection = rect_at_position;
363
364                 if (layer->selection < 0) {
365                     layer->state = RECT_LAYER_CREATE;
366                     layer->create_begin = position;
367                     layer->create_end = position;
368                 }
369             }
370         } break;
371         }
372     } break;
373
374     case SDL_KEYDOWN: {
375         switch (event->key.keysym.sym) {
376         case SDLK_UP: {
377             if ((event->key.keysym.mod & KMOD_SHIFT)
378                 && (layer->selection >= 0)
379                 && ((size_t)(layer->selection + 1) < dynarray_count(layer->rects))) {
380                 rect_layer_swap_elements(
381                     layer,
382                     (size_t) layer->selection,
383                     (size_t) layer->selection + 1,
384                     undo_history);
385                 layer->selection++;
386             }
387         } break;
388
389         case SDLK_DOWN: {
390             if ((event->key.keysym.mod & KMOD_SHIFT)
391                 && (layer->selection > 0)
392                 && ((size_t) layer->selection < dynarray_count(layer->rects))) {
393                 rect_layer_swap_elements(
394                     layer,
395                     (size_t) layer->selection,
396                     (size_t) layer->selection - 1,
397                     undo_history);
398                 layer->selection--;
399             }
400         } break;
401
402         case SDLK_DELETE: {
403             if (layer->selection >= 0) {
404                 rect_layer_delete_rect_at(layer, (size_t) layer->selection, undo_history);
405                 layer->selection = -1;
406             }
407         } break;
408
409         case SDLK_F2: {
410             if (layer->selection >= 0) {
411                 const char *ids = dynarray_data(layer->ids);
412                 Color *colors = dynarray_data(layer->colors);
413
414                 edit_field_restyle(
415                     layer->id_edit_field,
416                     RECT_LAYER_ID_LABEL_SIZE,
417                     color_invert(colors[layer->selection]));
418
419                 layer->state = RECT_LAYER_ID_RENAME;
420                 edit_field_replace(
421                     layer->id_edit_field,
422                     ids + layer->selection * ENTITY_MAX_ID_SIZE);
423                 SDL_StartTextInput();
424             }
425         } break;
426
427         case SDLK_c: {
428             if ((event->key.keysym.mod & KMOD_LCTRL) && layer->selection >= 0) {
429                 clipboard = 1;
430                 dynarray_copy_to(layer->rects, &clipboard_rect, (size_t)layer->selection);
431                 dynarray_copy_to(layer->colors, &clipboard_color, (size_t)layer->selection);
432             }
433         } break;
434
435         case SDLK_v: {
436             if ((event->key.keysym.mod & KMOD_LCTRL) && clipboard) {
437                 int x, y;
438                 SDL_GetMouseState(&x, &y);
439                 Vec2f position = camera_map_screen(camera, x, y);
440
441                 rect_layer_add_rect(
442                     layer,
443                     rect(position.x, position.y,
444                          clipboard_rect.w, clipboard_rect.h),
445                     clipboard_color,
446                     undo_history);
447             }
448         } break;
449         }
450     } break;
451     }
452
453     return 0;
454 }
455
456 static int rect_layer_event_create(RectLayer *layer,
457                                    const SDL_Event *event,
458                                    const Camera *camera,
459                                    UndoHistory *undo_history)
460 {
461     trace_assert(layer);
462     trace_assert(event);
463     trace_assert(camera);
464
465     switch (event->type) {
466     case SDL_MOUSEBUTTONUP: {
467         switch (event->button.button) {
468         case SDL_BUTTON_LEFT: {
469             const Rect real_rect =
470                 rect_from_points(
471                     layer->create_begin,
472                     layer->create_end);
473             const float area = real_rect.w * real_rect.h;
474
475             if (area >= CREATE_AREA_THRESHOLD) {
476                 rect_layer_add_rect(
477                     layer,
478                     real_rect,
479                     color_picker_rgba(&layer->color_picker),
480                     undo_history);
481             } else {
482                 log_info("The area is too small %f. Such small box won't be created.\n", area);
483             }
484             layer->state = RECT_LAYER_IDLE;
485         } break;
486         }
487     } break;
488
489     case SDL_MOUSEMOTION: {
490         layer->create_end = camera_map_screen(
491             camera,
492             event->motion.x,
493             event->motion.y);
494     } break;
495     }
496     return 0;
497 }
498
499 static int rect_layer_event_resize(RectLayer *layer,
500                                    const SDL_Event *event,
501                                    const Camera *camera,
502                                    UndoHistory *undo_history)
503 {
504     trace_assert(layer);
505     trace_assert(event);
506     trace_assert(camera);
507     trace_assert(layer->selection >= 0);
508
509     switch (event->type) {
510     case SDL_MOUSEMOTION: {
511         layer->inter_rect = rect_from_points(
512             vec(layer->inter_rect.x, layer->inter_rect.y),
513             vec_sum(
514                 camera_map_screen(
515                     camera,
516                     event->button.x,
517                     event->button.y),
518                 vec(RECT_LAYER_SELECTION_THICCNESS * -0.5f,
519                     RECT_LAYER_SELECTION_THICCNESS * -0.5f)));
520     } break;
521
522     case SDL_MOUSEBUTTONUP: {
523         layer->state = RECT_LAYER_IDLE;
524         UNDO_PUSH(undo_history, create_undo_update_context(layer));
525         dynarray_replace_at(layer->rects, (size_t) layer->selection, &layer->inter_rect);
526     } break;
527     }
528
529     return 0;
530 }
531
532 static int rect_layer_event_move(RectLayer *layer,
533                                  const SDL_Event *event,
534                                  const Camera *camera,
535                                  UndoHistory *undo_history)
536 {
537     trace_assert(layer);
538     trace_assert(event);
539     trace_assert(camera);
540     trace_assert(layer->selection >= 0);
541
542     Rect *rects = dynarray_data(layer->rects);
543
544     switch (event->type) {
545     case SDL_MOUSEMOTION: {
546         Vec2f position = vec_sub(
547             camera_map_screen(
548                 camera,
549                 event->button.x,
550                 event->button.y),
551             layer->move_anchor);
552
553         trace_assert(layer->selection >= 0);
554
555         layer->inter_rect.x = position.x;
556         layer->inter_rect.y = position.y;
557     } break;
558
559     case SDL_MOUSEBUTTONUP: {
560         layer->state = RECT_LAYER_IDLE;
561
562         float distance = vec_length(
563             vec_sub(rect_position(layer->inter_rect),
564                     rect_position(rects[layer->selection])));
565
566         if (distance > 1e-6) {
567             UNDO_PUSH(undo_history, create_undo_update_context(layer));
568             dynarray_replace_at(layer->rects, (size_t) layer->selection, &layer->inter_rect);
569         }
570     } break;
571     }
572     return 0;
573 }
574
575 static int rect_layer_event_id_rename(RectLayer *layer,
576                                       const SDL_Event *event,
577                                       const Camera *camera,
578                                       UndoHistory *undo_history)
579 {
580     trace_assert(layer);
581     trace_assert(event);
582     trace_assert(camera);
583     trace_assert(layer->selection >= 0);
584
585     switch (event->type) {
586     case SDL_KEYDOWN: {
587         switch (event->key.keysym.sym) {
588         case SDLK_RETURN: {
589             UNDO_PUSH(undo_history, create_undo_update_context(layer));
590
591             char *id = dynarray_pointer_at(layer->ids, (size_t)layer->selection);
592             memset(id, 0, ENTITY_MAX_ID_SIZE);
593             memcpy(id, edit_field_as_text(layer->id_edit_field), ENTITY_MAX_ID_SIZE - 1);
594             layer->state = RECT_LAYER_IDLE;
595             SDL_StopTextInput();
596         } break;
597
598         case SDLK_ESCAPE: {
599             layer->state = RECT_LAYER_IDLE;
600             SDL_StopTextInput();
601         } break;
602         }
603     } break;
604     }
605
606     return edit_field_event(layer->id_edit_field, event);
607 }
608
609 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
610 {
611     LayerPtr layer = {
612         .type = LAYER_RECT,
613         .ptr = rect_layer
614     };
615     return layer;
616 }
617
618 RectLayer *create_rect_layer(const char *id_name_prefix)
619 {
620     Lt *lt = create_lt();
621
622     RectLayer *layer = PUSH_LT(lt, nth_calloc(1, sizeof(RectLayer)), free);
623     if (layer == NULL) {
624         RETURN_LT(lt, NULL);
625     }
626     layer->lt = lt;
627
628     layer->ids = PUSH_LT(
629         lt,
630         create_dynarray(sizeof(char) * ENTITY_MAX_ID_SIZE),
631         destroy_dynarray);
632     if (layer->ids == NULL) {
633         RETURN_LT(lt, NULL);
634     }
635
636     layer->rects = PUSH_LT(
637         lt,
638         create_dynarray(sizeof(Rect)),
639         destroy_dynarray);
640     if (layer->rects == NULL) {
641         RETURN_LT(lt, NULL);
642     }
643
644     layer->colors = PUSH_LT(
645         lt,
646         create_dynarray(sizeof(Color)),
647         destroy_dynarray);
648     if (layer->colors == NULL) {
649         RETURN_LT(lt, NULL);
650     }
651
652     layer->actions = PUSH_LT(
653         lt,
654         create_dynarray(sizeof(Action)),
655         destroy_dynarray);
656     if (layer->actions == NULL) {
657         RETURN_LT(lt, NULL);
658     }
659
660     layer->id_edit_field = PUSH_LT(
661         lt,
662         create_edit_field(
663             RECT_LAYER_ID_LABEL_SIZE,
664             COLOR_BLACK),
665         destroy_edit_field);
666     if (layer->id_edit_field == NULL) {
667         RETURN_LT(lt, NULL);
668     }
669
670     layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
671     layer->selection = -1;
672     layer->id_name_prefix = id_name_prefix;
673
674     return layer;
675 }
676
677 RectLayer *create_rect_layer_from_line_stream(LineStream *line_stream, const char *id_name_prefix)
678 {
679     trace_assert(line_stream);
680
681     RectLayer *layer = create_rect_layer(id_name_prefix);
682     if (layer == NULL) {
683         return NULL;
684     }
685
686     const char *line = line_stream_next(line_stream);
687     if (line == NULL) {
688         RETURN_LT(layer->lt, NULL);
689     }
690
691     size_t count = 0;
692     if (sscanf(line, "%zu", &count) < 0) {
693         RETURN_LT(layer->lt, NULL);
694     }
695
696     for (size_t i = 0; i < count; ++i) {
697         line = line_stream_next(line_stream);
698         if (line == NULL) {
699             RETURN_LT(layer->lt, NULL);
700         }
701
702         char hex[7];
703         Rect rect;
704         char id[ENTITY_MAX_ID_SIZE];
705
706         int n = 0;
707         if (sscanf(line,
708                    "%"STRINGIFY(ENTITY_MAX_ID_SIZE)"s%f%f%f%f%6s%n",
709                    id,
710                    &rect.x, &rect.y,
711                    &rect.w, &rect.h,
712                    hex, &n) <= 0) {
713             log_fail("%s\n", strerror(errno));
714             RETURN_LT(layer->lt, NULL);
715         }
716         line += n;
717
718         Color color = hexstr(hex);
719         dynarray_push(layer->rects, &rect);
720         dynarray_push(layer->ids, id);
721         dynarray_push(layer->colors, &color);
722
723         Action action = {0};
724
725         if (sscanf(line, "%d%n", (int*)&action.type, &n) > 0) {
726             line += n;
727             switch (action.type) {
728             case ACTION_NONE: break;
729
730             case ACTION_TOGGLE_GOAL:
731             case ACTION_HIDE_LABEL: {
732                 if (sscanf(line, "%"STRINGIFY(ENTITY_MAX_ID_SIZE)"s", action.entity_id) <= 0) {
733                     log_fail("%s\n", strerror(errno));
734                     RETURN_LT(layer->lt, NULL);
735                 }
736             } break;
737             }
738         }
739
740         dynarray_push(layer->actions, &action);
741     }
742
743     return layer;
744 }
745
746 void destroy_rect_layer(RectLayer *layer)
747 {
748     trace_assert(layer);
749     RETURN_LT0(layer->lt);
750 }
751
752 int rect_layer_render(const RectLayer *layer, const Camera *camera, int active)
753 {
754     trace_assert(layer);
755     trace_assert(camera);
756
757     const size_t n = dynarray_count(layer->rects);
758     Rect *rects = dynarray_data(layer->rects);
759     Color *colors = dynarray_data(layer->colors);
760     const char *ids = dynarray_data(layer->ids);
761
762     // The Rectangles
763     for (size_t i = 0; i < n; ++i) {
764         Rect rect = rects[i];
765         Color color = colors[i];
766
767         if (layer->selection == (int) i) {
768             if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
769                 rect = layer->inter_rect;
770             }
771
772             if (layer->state == RECT_LAYER_RECOLOR) {
773                 color = layer->inter_color;
774             }
775         }
776
777         if (camera_fill_rect(
778                 camera,
779                 rect,
780                 color_scale(
781                     color,
782                     rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
783             return -1;
784         }
785
786         // Selection Overlay
787         if (active && (size_t) layer->selection == i) {
788             const Rect overlay_rect =
789                 rect_scale(
790                     camera_rect(camera, rect),
791                     RECT_LAYER_SELECTION_THICCNESS * 0.5f);
792             const Color overlay_color = color_invert(color);
793
794             // Main Rectangle
795             if (camera_fill_rect(
796                     camera,
797                     rect,
798                     color_scale(
799                         color,
800                         rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
801                 return -1;
802             }
803
804             if (camera_draw_thicc_rect_screen(
805                     camera,
806                     overlay_rect,
807                     overlay_color,
808                     RECT_LAYER_SELECTION_THICCNESS) < 0) {
809                 return -1;
810             }
811
812             // Rectangle Id
813             if (layer->state == RECT_LAYER_ID_RENAME) {
814                 // ID renaming Edit Field
815                 if (edit_field_render_world(
816                         layer->id_edit_field,
817                         camera,
818                         rect_position(rect)) < 0) {
819                     return -1;
820                 }
821             } else {
822                 // Id text
823                 if (camera_render_text(
824                         camera,
825                         ids + layer->selection * ENTITY_MAX_ID_SIZE,
826                         RECT_LAYER_ID_LABEL_SIZE,
827                         color_invert(color),
828                         rect_position(rect)) < 0) {
829                     return -1;
830                 }
831             }
832
833             // Resize Anchor
834             if (camera_fill_rect_screen(
835                     camera,
836                     rect_layer_resize_anchor(camera, rect),
837                     overlay_color) < 0) {
838                 return -1;
839             }
840         }
841     }
842
843     // Proto Rectangle
844     const Color color = color_picker_rgba(&layer->color_picker);
845     if (layer->state == RECT_LAYER_CREATE) {
846         if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
847             return -1;
848         }
849     }
850
851     if (active && color_picker_render(&layer->color_picker, camera) < 0) {
852         return -1;
853     }
854
855     return 0;
856 }
857
858 static
859 int rect_layer_event_recolor(RectLayer *layer,
860                              const SDL_Event *event,
861                              const Camera *camera,
862                              UndoHistory *undo_history)
863 {
864     trace_assert(layer);
865     trace_assert(event);
866     trace_assert(camera);
867     trace_assert(undo_history);
868     trace_assert(layer->selection >= 0);
869
870     int color_changed = 0;
871     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
872         return -1;
873     }
874
875     if (color_changed) {
876         layer->inter_color = color_picker_rgba(&layer->color_picker);
877
878         if (!color_picker_drag(&layer->color_picker)) {
879             UNDO_PUSH(undo_history, create_undo_update_context(layer));
880             dynarray_replace_at(layer->colors, (size_t) layer->selection, &layer->inter_color);
881             layer->state = RECT_LAYER_IDLE;
882         }
883     }
884
885     return 0;
886 }
887
888 int rect_layer_event(RectLayer *layer,
889                      const SDL_Event *event,
890                      const Camera *camera,
891                      UndoHistory *undo_history)
892 {
893     trace_assert(layer);
894     trace_assert(event);
895     trace_assert(undo_history);
896
897     switch (layer->state) {
898     case RECT_LAYER_IDLE:
899         return rect_layer_event_idle(layer, event, camera, undo_history);
900
901     case RECT_LAYER_CREATE:
902         return rect_layer_event_create(layer, event, camera, undo_history);
903
904     case RECT_LAYER_RESIZE:
905         return rect_layer_event_resize(layer, event, camera, undo_history);
906
907     case RECT_LAYER_MOVE:
908         return rect_layer_event_move(layer, event, camera, undo_history);
909
910     case RECT_LAYER_ID_RENAME:
911         return rect_layer_event_id_rename(layer, event, camera, undo_history);
912
913     case RECT_LAYER_RECOLOR:
914         return rect_layer_event_recolor(layer, event, camera, undo_history);
915     }
916
917     return 0;
918 }
919
920 size_t rect_layer_count(const RectLayer *layer)
921 {
922     return dynarray_count(layer->rects);
923 }
924
925 const Rect *rect_layer_rects(const RectLayer *layer)
926 {
927     return dynarray_data(layer->rects);
928 }
929
930 const Color *rect_layer_colors(const RectLayer *layer)
931 {
932     return dynarray_data(layer->colors);
933 }
934
935 const char *rect_layer_ids(const RectLayer *layer)
936 {
937     return dynarray_data(layer->ids);
938 }
939
940 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
941 {
942     trace_assert(layer);
943     trace_assert(filedump);
944
945     size_t n = dynarray_count(layer->ids);
946     char *ids = dynarray_data(layer->ids);
947     Rect *rects = dynarray_data(layer->rects);
948     Color *colors = dynarray_data(layer->colors);
949     Action *actions = dynarray_data(layer->actions);
950
951     fprintf(filedump, "%zd\n", n);
952     for (size_t i = 0; i < n; ++i) {
953         fprintf(filedump, "%s %f %f %f %f ",
954                 ids + ENTITY_MAX_ID_SIZE * i,
955                 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
956         color_hex_to_stream(colors[i], filedump);
957
958         switch (actions[i].type) {
959         case ACTION_NONE: {} break;
960
961         case ACTION_TOGGLE_GOAL:
962         case ACTION_HIDE_LABEL: {
963             fprintf(filedump, " %d %.*s",
964                     (int)actions[i].type,
965                     ENTITY_MAX_ID_SIZE, actions[i].entity_id);
966         } break;
967         }
968
969         fprintf(filedump, "\n");
970     }
971
972     return 0;
973 }
974
975 const Action *rect_layer_actions(const RectLayer *layer)
976 {
977     return dynarray_data(layer->actions);
978 }