]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/rect_layer.c
Introduce tool bar for subtract and snapping tools
[nothing.git] / src / game / level / level_editor / rect_layer.c
1 #include <float.h>
2 #include <errno.h>
3
4 #include "game/camera.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/str.h"
13 #include "undo_history.h"
14 #include "game/level/action.h"
15 #include "game.h"
16 #include "math/extrema.h"
17
18 #define RECT_LAYER_SELECTION_THICCNESS 15.0f
19 #define RECT_LAYER_ID_LABEL_SIZE vec(3.0f, 3.0f)
20 #define CREATE_AREA_THRESHOLD 10.0
21
22 static int rect_clipboard = 0;
23 static Rect rect_clipboard_rect;
24 static Color rect_clipboard_color;
25
26 static Cursor_Style resize_styles[1 << RECT_SIDE_N] = {
27     0,                         // [0]
28     CURSOR_STYLE_RESIZE_VERT,  // [1]
29     CURSOR_STYLE_RESIZE_HORIS, // [2]
30     CURSOR_STYLE_RESIZE_DIAG1, // [3]
31     CURSOR_STYLE_RESIZE_VERT,  // [4]
32     0,                         // [5]
33     CURSOR_STYLE_RESIZE_DIAG2, // [6]
34     0,                         // [7]
35     CURSOR_STYLE_RESIZE_HORIS, // [8]
36     CURSOR_STYLE_RESIZE_DIAG2, // [9]
37     0,                         // [10]
38     0,                         // [11]
39     CURSOR_STYLE_RESIZE_DIAG1  // [12]
40 };
41
42 typedef enum {
43     RECT_UNDO_ADD,
44     RECT_UNDO_DELETE,
45     RECT_UNDO_UPDATE,
46     RECT_UNDO_SWAP
47 } RectUndoType;
48
49 // Delete, Update
50 typedef struct {
51     RectUndoType type;
52     RectLayer *layer;
53     size_t index;
54     Rect rect;
55     Color color;
56     Action action;
57     char id[ENTITY_MAX_ID_SIZE];
58 } UndoElementContext;
59
60 // Add
61 typedef struct {
62     RectUndoType type;
63     RectLayer *layer;
64     size_t index;
65 } UndoAddContext;
66
67 // Swap
68 typedef struct {
69     RectUndoType type;
70     RectLayer *layer;
71     size_t index1;
72     size_t index2;
73 } UndoSwapContext;
74
75 typedef union {
76     RectUndoType type;
77     UndoAddContext add;
78     UndoElementContext element;
79     UndoSwapContext swap;
80 } RectUndoContext;
81
82 static
83 RectUndoContext create_rect_undo_add_context(RectLayer *layer, size_t index)
84 {
85     trace_assert(layer);
86     trace_assert(index < layer->rects.count);
87
88     RectUndoContext undo_context;
89     undo_context.add.type = RECT_UNDO_ADD;
90     undo_context.add.layer = layer;
91     undo_context.add.index = index;
92     return undo_context;
93 }
94
95 static
96 RectUndoContext create_rect_undo_element_context(RectLayer *layer, size_t index)
97 {
98     trace_assert(layer);
99     trace_assert(index < layer->rects.count);
100
101     RectUndoContext undo_context;
102     undo_context.element.layer = layer;
103     undo_context.element.index = index;
104     dynarray_copy_to(&layer->rects, &undo_context.element.rect, index);
105     dynarray_copy_to(&layer->colors, &undo_context.element.color, index);
106     dynarray_copy_to(&layer->ids, undo_context.element.id, index);
107     dynarray_copy_to(&layer->actions, &undo_context.element.action, index);
108     return undo_context;
109 }
110
111 static
112 RectUndoContext create_rect_undo_update_context(RectLayer *rect_layer, size_t index)
113 {
114     RectUndoContext undo_context = create_rect_undo_element_context(rect_layer, index);
115     undo_context.type = RECT_UNDO_UPDATE;
116     return undo_context;
117 }
118
119 static
120 RectUndoContext create_rect_undo_delete_context(RectLayer *rect_layer, size_t i)
121 {
122     RectUndoContext undo_context = create_rect_undo_element_context(rect_layer, i);
123     undo_context.type = RECT_UNDO_DELETE;
124     return undo_context;
125 }
126
127 static
128 RectUndoContext create_rect_undo_swap_context(RectLayer *rect_layer, size_t index1, size_t index2)
129 {
130     RectUndoContext undo_context;
131     undo_context.swap.type = RECT_UNDO_SWAP;
132     undo_context.swap.layer = rect_layer;
133     undo_context.swap.index1 = index1;
134     undo_context.swap.index2 = index2;
135     return undo_context;
136 }
137
138 static
139 void rect_layer_undo(void *context, size_t context_size)
140 {
141     trace_assert(context);
142     trace_assert(sizeof(RectUndoContext) == context_size);
143
144     RectUndoContext *undo_context = context;
145
146     switch (undo_context->type) {
147     case RECT_UNDO_ADD: {
148         RectLayer *layer = undo_context->add.layer;
149         dynarray_delete_at(&layer->rects, undo_context->add.index);
150         dynarray_delete_at(&layer->colors, undo_context->add.index);
151         dynarray_delete_at(&layer->ids, undo_context->add.index);
152         dynarray_delete_at(&layer->actions, undo_context->add.index);
153         layer->selection = -1;
154     } break;
155
156     case RECT_UNDO_DELETE: {
157         RectLayer *layer = undo_context->element.layer;
158         dynarray_insert_before(&layer->rects, undo_context->element.index, &undo_context->element.rect);
159         dynarray_insert_before(&layer->colors, undo_context->element.index, &undo_context->element.color);
160         dynarray_insert_before(&layer->ids, undo_context->element.index, &undo_context->element.id);
161         dynarray_insert_before(&layer->actions, undo_context->element.index, &undo_context->element.action);
162         layer->selection = -1;
163     } break;
164
165     case RECT_UNDO_UPDATE: {
166         RectLayer *layer = undo_context->element.layer;
167         dynarray_replace_at(&layer->rects, undo_context->element.index, &undo_context->element.rect);
168         dynarray_replace_at(&layer->colors, undo_context->element.index, &undo_context->element.color);
169         dynarray_replace_at(&layer->ids, undo_context->element.index, &undo_context->element.id);
170         dynarray_replace_at(&layer->actions, undo_context->element.index, &undo_context->element.action);
171     } break;
172
173     case RECT_UNDO_SWAP: {
174         RectLayer *layer = undo_context->element.layer;
175         dynarray_swap(&layer->rects, undo_context->swap.index1, undo_context->swap.index2);
176         dynarray_swap(&layer->colors, undo_context->swap.index1, undo_context->swap.index2);
177         dynarray_swap(&layer->ids, undo_context->swap.index1, undo_context->swap.index2);
178         dynarray_swap(&layer->actions, undo_context->swap.index1, undo_context->swap.index2);
179     } break;
180     }
181 }
182
183 #define RECT_UNDO_PUSH(HISTORY, CONTEXT)                                     \
184     do {                                                                \
185         RectUndoContext context = (CONTEXT);                                \
186         undo_history_push(                                              \
187             HISTORY,                                                    \
188             rect_layer_undo,                                            \
189             &context,                                                   \
190             sizeof(context));                                           \
191     } while(0)
192
193 static int rect_layer_add_rect(RectLayer *layer,
194                                Rect rect,
195                                Color color,
196                                UndoHistory *undo_history)
197 {
198     trace_assert(layer);
199
200     dynarray_push(&layer->rects, &rect);
201     dynarray_push(&layer->colors, &color);
202
203     char id[ENTITY_MAX_ID_SIZE];
204     snprintf(id, ENTITY_MAX_ID_SIZE, "%s_%d",
205              layer->id_name_prefix,
206              layer->id_name_counter++);
207     dynarray_push(&layer->ids, id);
208
209     dynarray_push_empty(&layer->actions);
210
211     RECT_UNDO_PUSH(
212         undo_history,
213         create_rect_undo_add_context(
214             layer,
215             layer->rects.count - 1));
216
217     return 0;
218 }
219
220 static int rect_layer_rect_at(RectLayer *layer, Vec2f position)
221 {
222     trace_assert(layer);
223
224     int n = (int) layer->rects.count;
225     Rect *rects = (Rect*)layer->rects.data;
226
227     for (int i = n - 1; i >= 0; --i) {
228         if (rect_contains_point(rects[i], position)) {
229             return (int) i;
230         }
231     }
232
233     return -1;
234 }
235
236 static void rect_layer_swap_elements(RectLayer *layer, size_t a, size_t b,
237                                      UndoHistory *undo_history)
238 {
239     trace_assert(layer);
240     trace_assert(a < layer->rects.count);
241     trace_assert(b < layer->rects.count);
242
243     dynarray_swap(&layer->rects, a, b);
244     dynarray_swap(&layer->colors, a, b);
245     dynarray_swap(&layer->ids, a, b);
246     dynarray_swap(&layer->actions, a, b);
247
248     RECT_UNDO_PUSH(undo_history, create_rect_undo_swap_context(layer, a, b));
249 }
250
251 static int rect_layer_delete_rect_at_index(RectLayer *layer,
252                                      size_t i,
253                                      UndoHistory *undo_history)
254 {
255     trace_assert(layer);
256
257     RECT_UNDO_PUSH(undo_history, create_rect_undo_delete_context(layer, i));
258
259     dynarray_delete_at(&layer->rects, i);
260     dynarray_delete_at(&layer->colors, i);
261     dynarray_delete_at(&layer->ids, i);
262     dynarray_delete_at(&layer->actions, i);
263
264     return 0;
265 }
266
267 static int calc_resize_mask(Vec2f point, Rect rect)
268 {
269     int mask = 0;
270     for (Rect_side side = 0; side < RECT_SIDE_N; ++side) {
271         if (rect_side_distance(rect, point, side) < RECT_LAYER_SELECTION_THICCNESS) {
272             mask = mask | (1 << side);
273         }
274     }
275     return mask;
276 }
277
278 #define TOOL_BUTTON_WIDTH 50.0f
279 #define TOOL_BUTTON_HEIGHT 50.0f
280 #define TOOL_BAR_PADDING 20.0f
281
282 static
283 Rect subtract_tool_button_rect(const Camera *camera)
284 {
285     const Rect view_port = camera_view_port_screen(camera);
286     return rect(
287         TOOL_BAR_PADDING,
288         view_port.h - TOOL_BUTTON_HEIGHT - TOOL_BAR_PADDING,
289         TOOL_BUTTON_WIDTH,
290         TOOL_BUTTON_HEIGHT);
291 }
292
293 static
294 Rect snapping_tool_button_rect(const Camera *camera)
295 {
296     const Rect view_port = camera_view_port_screen(camera);
297     return rect(
298         TOOL_BAR_PADDING + TOOL_BUTTON_WIDTH + TOOL_BAR_PADDING,
299         view_port.h - TOOL_BUTTON_HEIGHT - TOOL_BAR_PADDING,
300         TOOL_BUTTON_WIDTH,
301         TOOL_BUTTON_HEIGHT);
302 }
303
304 static int rect_layer_event_idle(RectLayer *layer,
305                                  const SDL_Event *event,
306                                  const Camera *camera,
307                                  UndoHistory *undo_history)
308 {
309     trace_assert(layer);
310     trace_assert(event);
311     trace_assert(camera);
312
313     int color_changed = 0;
314     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
315         return -1;
316     }
317
318     if (color_changed) {
319         if (layer->selection >= 0) {
320             dynarray_copy_to(&layer->colors, &layer->inter_color, (size_t)layer->selection);
321             layer->state = RECT_LAYER_RECOLOR;
322         }
323         return 0;
324     }
325
326     Rect *rects = (Rect*)layer->rects.data;
327
328     switch (event->type) {
329     case SDL_MOUSEBUTTONDOWN: {
330         switch (event->button.button) {
331         case SDL_BUTTON_LEFT: {
332             Vec2f screen_position =
333                 vec((float) event->button.x,
334                     (float) event->button.y);
335             if (rect_contains_point(subtract_tool_button_rect(camera), screen_position)) {
336                 layer->subtract_enabled = !layer->subtract_enabled;
337                 return 0;
338             }
339
340             if (rect_contains_point(snapping_tool_button_rect(camera), screen_position)) {
341                 layer->snapping_enabled = !layer->snapping_enabled;
342                 return 0;
343             }
344
345             Vec2f position = camera_map_screen(
346                 camera,
347                 event->button.x,
348                 event->button.y);
349             int rect_at_position =
350                 rect_layer_rect_at(layer, position);
351
352
353             Color *colors = (Color*)layer->colors.data;
354
355             if (layer->selection >= 0 &&
356                 layer->selection == rect_at_position &&
357                 (layer->resize_mask = calc_resize_mask(
358                     vec((float) event->button.x, (float)event->button.y),
359                     camera_rect(camera, rects[layer->selection])))) {
360                 layer->state = RECT_LAYER_RESIZE;
361                 dynarray_copy_to(&layer->rects, &layer->inter_rect, (size_t) layer->selection);
362             } else if (rect_at_position >= 0) {
363                 layer->selection = rect_at_position;
364                 layer->state = RECT_LAYER_MOVE;
365                 layer->move_anchor = vec_sub(
366                     position,
367                     vec(
368                         rects[layer->selection].x,
369                         rects[layer->selection].y));
370                 layer->color_picker =
371                     create_color_picker_from_rgba(colors[rect_at_position]);
372                 dynarray_copy_to(&layer->rects, &layer->inter_rect, (size_t) rect_at_position);
373             } else {
374                 layer->selection = rect_at_position;
375
376                 if (layer->selection < 0) {
377                     layer->state = layer->subtract_enabled
378                         ? RECT_LAYER_SUBTRACT
379                         : RECT_LAYER_CREATE;
380                     layer->create_begin = position;
381                     layer->create_end = position;
382                 }
383             }
384         } break;
385         }
386     } break;
387
388     case SDL_MOUSEMOTION: {
389         int resize_mask = 0;
390         Vec2f position = camera_map_screen(
391             camera,
392             event->button.x,
393             event->button.y);
394         if (layer->selection >= 0 &&
395             layer->selection == rect_layer_rect_at(layer, position) &&
396             (resize_mask = calc_resize_mask(
397                 vec((float) event->button.x, (float)event->button.y),
398                 camera_rect(camera, rects[layer->selection])))) {
399             layer->cursor->style = resize_styles[resize_mask];
400         } else {
401             layer->cursor->style = CURSOR_STYLE_POINTER;
402         }
403     } break;
404
405     case SDL_KEYDOWN: {
406         switch (event->key.keysym.sym) {
407         case SDLK_UP: {
408             if ((event->key.keysym.mod & KMOD_SHIFT)
409                 && (layer->selection >= 0)
410                 && ((size_t)(layer->selection + 1) < layer->rects.count)) {
411                 rect_layer_swap_elements(
412                     layer,
413                     (size_t) layer->selection,
414                     (size_t) layer->selection + 1,
415                     undo_history);
416                 layer->selection++;
417             }
418         } break;
419
420         case SDLK_DOWN: {
421             if ((event->key.keysym.mod & KMOD_SHIFT)
422                 && (layer->selection > 0)
423                 && ((size_t) layer->selection < layer->rects.count)) {
424                 rect_layer_swap_elements(
425                     layer,
426                     (size_t) layer->selection,
427                     (size_t) layer->selection - 1,
428                     undo_history);
429                 layer->selection--;
430             }
431         } break;
432
433         case SDLK_DELETE: {
434             if (layer->selection >= 0) {
435                 rect_layer_delete_rect_at_index(
436                     layer,
437                     (size_t) layer->selection,
438                     undo_history);
439                 layer->selection = -1;
440             }
441         } break;
442
443         case SDLK_q: {
444             // TODO(#1171): there is no UI indication that we are in the snapping mode
445             layer->snapping_enabled = !layer->snapping_enabled;
446         } break;
447
448         case SDLK_F2: {
449             if (layer->selection >= 0) {
450                 const char *ids = (char*)layer->ids.data;
451                 Color *colors = (Color*)layer->colors.data;
452
453                 edit_field_restyle(
454                     &layer->id_edit_field,
455                     RECT_LAYER_ID_LABEL_SIZE,
456                     color_invert(colors[layer->selection]));
457
458                 layer->state = RECT_LAYER_ID_RENAME;
459                 edit_field_replace(
460                     &layer->id_edit_field,
461                     ids + layer->selection * ENTITY_MAX_ID_SIZE);
462                 SDL_StartTextInput();
463             }
464         } break;
465
466         case SDLK_c: {
467             if ((event->key.keysym.mod & KMOD_LCTRL) && layer->selection >= 0) {
468                 rect_clipboard = 1;
469                 dynarray_copy_to(&layer->rects, &rect_clipboard_rect, (size_t)layer->selection);
470                 dynarray_copy_to(&layer->colors, &rect_clipboard_color, (size_t)layer->selection);
471             }
472         } break;
473
474         case SDLK_v: {
475             if ((event->key.keysym.mod & KMOD_LCTRL) && rect_clipboard) {
476                 int x, y;
477                 SDL_GetMouseState(&x, &y);
478                 Vec2f position = camera_map_screen(camera, x, y);
479
480                 rect_layer_add_rect(
481                     layer,
482                     rect(position.x, position.y,
483                          rect_clipboard_rect.w, rect_clipboard_rect.h),
484                     rect_clipboard_color,
485                     undo_history);
486             }
487         } break;
488         }
489     } break;
490     }
491
492     return 0;
493 }
494
495 #define GEOMETRY_CAPACITY 256
496
497 typedef struct {
498     size_t first;
499     size_t count;
500     Rect rects[GEOMETRY_CAPACITY];
501     Color colors[GEOMETRY_CAPACITY];
502 } Geometry;
503
504 static
505 void push_geometry(Geometry *geometry, Rect rect, Color color)
506 {
507     assert(geometry);
508     assert(geometry->count < GEOMETRY_CAPACITY);
509
510     if ((rect.w * rect.h) > 1e-6f) {
511         size_t i = (geometry->first + geometry->count) % GEOMETRY_CAPACITY;
512         geometry->rects[i] = rect;
513         geometry->colors[i] = color;
514         geometry->count++;
515     }
516 }
517
518 static
519 void subtract_rect_from_rect(Rect a, Color color_a, Rect c, Geometry *result)
520 {
521     assert(result);
522
523     Rect b = rects_overlap_area(a, c);
524
525     if (b.w * b.h < 1e-6) {
526         push_geometry(result, a, color_a);
527         return;
528     }
529
530     push_geometry(result, (Rect) {a.x, a.y, a.w, b.y - a.y}, color_a);
531     push_geometry(result, (Rect) {a.x, b.y, b.x - a.x, b.h}, color_a);
532     push_geometry(result, (Rect) {
533         b.x + b.w,
534         b.y,
535         a.w - (b.x - a.x) - b.w,
536         b.h
537     }, color_a);
538     push_geometry(result, (Rect) {
539         a.x,
540         b.y + b.h,
541         a.w,
542         a.h - (b.y - a.y) - b.h
543     }, color_a);
544 }
545
546 static
547 void subtract_rect_from_geometry(Geometry *result, Rect b)
548 {
549     assert(result);
550
551     size_t count = result->count;
552     size_t first = result->first;
553
554     for (size_t i = 0; i < count; ++i) {
555         result->first = (result->first + 1) % GEOMETRY_CAPACITY;
556         result->count -= 1;
557         subtract_rect_from_rect(
558             result->rects[(i + first) % GEOMETRY_CAPACITY],
559             result->colors[(i + first) % GEOMETRY_CAPACITY],
560             b,
561             result);
562     }
563 }
564
565 static int rect_layer_event_subtract(RectLayer *layer,
566                                      const SDL_Event *event,
567                                      const Camera *camera,
568                                      UndoHistory *undo_history)
569 {
570     trace_assert(layer);
571     trace_assert(event);
572     trace_assert(camera);
573     trace_assert(undo_history);
574
575     Rect *rects = layer->rects.data;
576     Color *colors = layer->colors.data;
577
578     switch (event->type) {
579     case SDL_MOUSEBUTTONUP: {
580         switch (event->button.button) {
581         case SDL_BUTTON_LEFT: {
582             const Rect real_rect =
583                 rect_from_points(
584                     layer->create_begin,
585                     layer->create_end);
586             const float area = real_rect.w * real_rect.h;
587
588             Geometry geometry = {0};
589
590             if (area >= CREATE_AREA_THRESHOLD) {
591                 for (size_t i = 0; i < layer->rects.count;) {
592                     Rect overlap_area = rects_overlap_area(
593                         real_rect,
594                         rects[i]);
595                     if (overlap_area.w * overlap_area.h > 1e-6) {
596                         push_geometry(&geometry, rects[i], colors[i]);
597                         rect_layer_delete_rect_at_index(layer, i, undo_history);
598                     } else {
599                         i++;
600                     }
601                 }
602
603                 subtract_rect_from_geometry(&geometry, real_rect);
604
605                 for (size_t i = 0; i < geometry.count; ++i) {
606                     size_t j = (i + geometry.first) % GEOMETRY_CAPACITY;
607                     rect_layer_add_rect(
608                         layer,
609                         geometry.rects[j],
610                         geometry.colors[j],
611                         undo_history);
612                 }
613             } else {
614                 log_info("The area is too small %f. Such small box won't be cut.\n", area);
615             }
616             layer->state = RECT_LAYER_IDLE;
617         } break;
618         }
619     } break;
620
621     case SDL_MOUSEMOTION: {
622         layer->create_end = camera_map_screen(
623             camera,
624             event->motion.x,
625             event->motion.y);
626     } break;
627     }
628
629     return 0;
630 }
631
632 static int rect_layer_event_create(RectLayer *layer,
633                                    const SDL_Event *event,
634                                    const Camera *camera,
635                                    UndoHistory *undo_history)
636 {
637     trace_assert(layer);
638     trace_assert(event);
639     trace_assert(camera);
640
641     switch (event->type) {
642     case SDL_MOUSEBUTTONUP: {
643         switch (event->button.button) {
644         case SDL_BUTTON_LEFT: {
645             const Rect real_rect =
646                 rect_from_points(
647                     layer->create_begin,
648                     layer->create_end);
649             const float area = real_rect.w * real_rect.h;
650
651             if (area >= CREATE_AREA_THRESHOLD) {
652                 rect_layer_add_rect(
653                     layer,
654                     real_rect,
655                     color_picker_rgba(&layer->color_picker),
656                     undo_history);
657             } else {
658                 log_info("The area is too small %f. Such small box won't be created.\n", area);
659             }
660             layer->state = RECT_LAYER_IDLE;
661         } break;
662         }
663     } break;
664
665     case SDL_MOUSEMOTION: {
666         layer->create_end = camera_map_screen(
667             camera,
668             event->motion.x,
669             event->motion.y);
670     } break;
671     }
672     return 0;
673 }
674
675 static
676 void snap_rect_resize_if_enabled(RectLayer *layer, Rect *a, float snapping_threshold)
677 {
678     trace_assert(layer);
679     trace_assert(layer->selection >= 0);
680     trace_assert(a);
681
682     if (!layer->snapping_enabled) return;
683
684     Rect *rects = (Rect*)layer->rects.data;
685     size_t rects_size = layer->rects.count;
686
687     for (size_t i = 0; i < rects_size; ++i) {
688         if (i == (size_t) layer->selection) continue;
689
690         const Rect b = rects[i];
691
692         if (segment_overlap(vec(a->x, a->x + a->w), vec(b.x, b.x + b.w))) {
693             snap_var2seg(&a->y, b.y, 0, b.h, snapping_threshold);
694         }
695
696         if (segment_overlap(vec(a->y, a->y + a->h), vec(b.y, b.y + b.h))) {
697             snap_var2seg(&a->x, b.x, 0, b.w, snapping_threshold);
698         }
699     }
700 }
701
702 static int rect_layer_event_resize(RectLayer *layer,
703                                    const SDL_Event *event,
704                                    const Camera *camera,
705                                    UndoHistory *undo_history)
706 {
707     trace_assert(layer);
708     trace_assert(event);
709     trace_assert(camera);
710     trace_assert(layer->selection >= 0);
711
712     Rect *rects = (Rect*)layer->rects.data;
713
714     float scaled_snap_threshold = SNAPPING_THRESHOLD / camera->scale;
715
716     switch (event->type) {
717     case SDL_MOUSEMOTION: {
718         Vec2f position = camera_map_screen(
719             camera,
720             event->button.x,
721             event->button.y);
722
723         switch (layer->resize_mask) {
724         case 1: {               // TOP
725             Rect a = rect(rects[layer->selection].x,
726                           position.y,
727                           rects[layer->selection].w,
728                           rects[layer->selection].h);
729
730             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
731
732             layer->inter_rect = rect_from_points(
733                 vec(a.x, a.y),
734                 rect_position2(rects[layer->selection]));
735         } break;
736
737         case 2: {               // LEFT
738             Rect a = rect(position.x,
739                           rects[layer->selection].y,
740                           rects[layer->selection].w,
741                           rects[layer->selection].h);
742
743             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
744
745             layer->inter_rect = rect_from_points(
746                 vec(a.x, a.y),
747                 rect_position2(rects[layer->selection]));
748         } break;
749
750         case 3: {               // TOP,LEFT
751             Rect a = rect(
752                 position.x,
753                 position.y,
754                 rects[layer->selection].w,
755                 rects[layer->selection].h);
756
757             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
758
759             layer->inter_rect = rect_from_points(
760                 vec(a.x, a.y),
761                 rect_position2(rects[layer->selection]));
762         } break;
763
764         case 4: {               // BOTTOM
765             Rect a = rect(rects[layer->selection].x,
766                           position.y,
767                           rects[layer->selection].w,
768                           rects[layer->selection].h);
769
770             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
771
772             layer->inter_rect = rect_from_points(
773                 rect_position(rects[layer->selection]),
774                 vec(rects[layer->selection].x + rects[layer->selection].w,
775                     a.y));
776         } break;
777
778         case 6: {               // BOTTOM,LEFT
779             Rect a = rect(
780                 position.x,
781                 position.y,
782                 rects[layer->selection].w,
783                 -rects[layer->selection].h);
784
785             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
786
787             layer->inter_rect = rect_from_points(
788                 vec(a.x, rects[layer->selection].y),
789                 vec(rects[layer->selection].x + rects[layer->selection].w,
790                     a.y));
791         } break;
792
793         case 8: {               // RIGHT
794             Rect a = rect(position.x,
795                           rects[layer->selection].y,
796                           rects[layer->selection].w,
797                           rects[layer->selection].h);
798
799             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
800
801             layer->inter_rect = rect_from_points(
802                 rect_position(rects[layer->selection]),
803                 vec(a.x, rects[layer->selection].y + rects[layer->selection].h));
804         } break;
805
806         case 9: {               // TOP,RIGHT
807             Rect a = rect(
808                 position.x,
809                 position.y,
810                 -rects[layer->selection].w,
811                 rects[layer->selection].h);
812
813             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
814
815             layer->inter_rect = rect_from_points(
816                 vec(rects[layer->selection].x, a.y),
817                 vec(a.x,
818                     rects[layer->selection].y + rects[layer->selection].h));
819         } break;
820
821         case 12: {              // BOTTOM,RIGHT
822             Rect a = rect(
823                 position.x,
824                 position.y,
825                 -rects[layer->selection].w,
826                 -rects[layer->selection].h);
827
828             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
829
830             layer->inter_rect = rect_from_points(
831                 rect_position(rects[layer->selection]),
832                 vec(a.x, a.y));
833         } break;
834         }
835
836     } break;
837
838     case SDL_MOUSEBUTTONUP: {
839         layer->state = RECT_LAYER_IDLE;
840         RECT_UNDO_PUSH(
841             undo_history,
842             create_rect_undo_update_context(
843                 layer,
844                 (size_t) layer->selection));
845         dynarray_replace_at(&layer->rects, (size_t) layer->selection, &layer->inter_rect);
846     } break;
847     }
848
849     return 0;
850 }
851
852 static
853 void snap_rect_move_if_enabled(RectLayer *layer, Rect *a,
854                                float snapping_threshold)
855 {
856     trace_assert(a);
857     trace_assert(layer);
858     trace_assert(layer->selection >= 0);
859
860     if (!layer->snapping_enabled) return;
861
862     Rect *rects = (Rect*)layer->rects.data;
863     size_t rects_size = layer->rects.count;
864
865     for (size_t i = 0; i < rects_size; ++i) {
866         if (i == (size_t) layer->selection) continue;
867
868         const Rect b = rects[i];
869
870         if (segment_overlap(vec(a->x, a->x + a->w), vec(b.x,  b.x  + b.w))) {
871             snap_seg2seg(&a->y, b.y, a->h, b.h, snapping_threshold);
872         }
873
874         if (segment_overlap(vec(a->y, a->y + a->h), vec(b.y,  b.y  + b.h))) {
875             snap_seg2seg(&a->x, b.x, a->w, b.w, snapping_threshold);
876         }
877     }
878 }
879
880 static int rect_layer_event_move(RectLayer *layer,
881                                  const SDL_Event *event,
882                                  const Camera *camera,
883                                  UndoHistory *undo_history)
884 {
885     trace_assert(layer);
886     trace_assert(event);
887     trace_assert(camera);
888     trace_assert(layer->selection >= 0);
889
890     Rect *rects = (Rect*)layer->rects.data;
891
892     switch (event->type) {
893     case SDL_MOUSEMOTION: {
894         const Uint8 *state = SDL_GetKeyboardState(NULL);
895         const Vec2f mouse_pos = vec_sub(
896             camera_map_screen(
897                 camera,
898                 event->button.x,
899                 event->button.y),
900             layer->move_anchor);
901
902         if (!(state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL])) {
903             layer->inter_rect.x = mouse_pos.x;
904             layer->inter_rect.y = mouse_pos.y;
905         } else {
906             const Vec2f rect_pos = rect_position(rects[layer->selection]);
907
908             const float dx = fabsf(rect_pos.x - mouse_pos.x);
909             const float dy = fabsf(rect_pos.y - mouse_pos.y);
910
911             if (dx > dy) {
912                 layer->inter_rect.x = mouse_pos.x;
913                 layer->inter_rect.y = rect_pos.y;
914             } else {
915                 layer->inter_rect.x = rect_pos.x;
916                 layer->inter_rect.y = mouse_pos.y;
917             }
918         }
919
920         snap_rect_move_if_enabled(layer, &layer->inter_rect,
921                                   SNAPPING_THRESHOLD / camera->scale);
922     } break;
923
924     case SDL_MOUSEBUTTONUP: {
925         layer->state = RECT_LAYER_IDLE;
926
927         float distance = vec_length(
928             vec_sub(rect_position(layer->inter_rect),
929                     rect_position(rects[layer->selection])));
930
931         if (distance > 1e-6) {
932             RECT_UNDO_PUSH(
933                 undo_history,
934                 create_rect_undo_update_context(
935                     layer, (size_t) layer->selection));
936             dynarray_replace_at(
937                 &layer->rects,
938                 (size_t) layer->selection,
939                 &layer->inter_rect);
940         }
941     } break;
942     }
943     return 0;
944 }
945
946 static int rect_layer_event_id_rename(RectLayer *layer,
947                                       const SDL_Event *event,
948                                       const Camera *camera,
949                                       UndoHistory *undo_history)
950 {
951     trace_assert(layer);
952     trace_assert(event);
953     trace_assert(camera);
954     trace_assert(layer->selection >= 0);
955
956     switch (event->type) {
957     case SDL_KEYDOWN: {
958         switch (event->key.keysym.sym) {
959         case SDLK_RETURN: {
960             RECT_UNDO_PUSH(
961                 undo_history,
962                 create_rect_undo_update_context(
963                     layer,
964                     (size_t) layer->selection));
965
966             char *id = dynarray_pointer_at(&layer->ids, (size_t)layer->selection);
967             memset(id, 0, ENTITY_MAX_ID_SIZE);
968             memcpy(id, edit_field_as_text(&layer->id_edit_field), ENTITY_MAX_ID_SIZE - 1);
969             layer->state = RECT_LAYER_IDLE;
970             SDL_StopTextInput();
971         } break;
972
973         case SDLK_ESCAPE: {
974             layer->state = RECT_LAYER_IDLE;
975             SDL_StopTextInput();
976         } break;
977         }
978     } break;
979     }
980
981     return edit_field_event(&layer->id_edit_field, event);
982 }
983
984 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
985 {
986     LayerPtr layer = {
987         .type = LAYER_RECT,
988         .ptr = rect_layer
989     };
990     return layer;
991 }
992
993 RectLayer *create_rect_layer(Memory *memory,
994                              const char *id_name_prefix,
995                              Cursor *cursor)
996 {
997     trace_assert(memory);
998     trace_assert(id_name_prefix);
999     trace_assert(cursor);
1000
1001     RectLayer *rect_layer = memory_alloc(memory, sizeof(RectLayer));
1002
1003     rect_layer->ids = create_dynarray(memory, sizeof(char) * ENTITY_MAX_ID_SIZE);
1004     rect_layer->rects = create_dynarray(memory, sizeof(Rect));
1005     rect_layer->colors = create_dynarray(memory, sizeof(Color));
1006     rect_layer->actions = create_dynarray(memory, sizeof(Action));
1007     rect_layer->id_edit_field.font_size = RECT_LAYER_ID_LABEL_SIZE;
1008     rect_layer->id_edit_field.font_color = COLOR_BLACK;
1009     rect_layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
1010     rect_layer->selection = -1;
1011     rect_layer->id_name_prefix = id_name_prefix;
1012     rect_layer->cursor = cursor;
1013
1014     return rect_layer;
1015 }
1016
1017 void rect_layer_load(RectLayer *layer, Memory *memory, String *input)
1018 {
1019     trace_assert(layer);
1020     trace_assert(memory);
1021     trace_assert(input);
1022
1023     int n = atoi(string_to_cstr(memory, trim(chop_by_delim(input, '\n'))));
1024     char id[ENTITY_MAX_ID_SIZE];
1025     for (int i = 0; i < n; ++i) {
1026         Rect rect;
1027         String line = trim(chop_by_delim(input, '\n'));
1028         String string_id = trim(chop_word(&line));
1029         rect.x = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1030         rect.y = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1031         rect.w = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1032         rect.h = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1033         Color color = hexs(trim(chop_word(&line)));
1034
1035         memset(id, 0, ENTITY_MAX_ID_SIZE);
1036         memcpy(
1037             id,
1038             string_id.data,
1039             min_size_t(ENTITY_MAX_ID_SIZE - 1, string_id.count));
1040
1041         dynarray_push(&layer->rects, &rect);
1042         dynarray_push(&layer->colors, &color);
1043         dynarray_push(&layer->ids, id);
1044
1045         Action action = {
1046             .type = ACTION_NONE,
1047             .entity_id = {0}
1048         };
1049
1050         String action_string = trim(chop_word(&line));
1051         if (action_string.count > 0) {
1052             action.type = (ActionType)atol(string_to_cstr(memory, action_string));
1053             switch (action.type) {
1054             case ACTION_NONE: break;
1055             case ACTION_TOGGLE_GOAL:
1056             case ACTION_HIDE_LABEL: {
1057                 String label_id = trim(chop_word(&line));
1058                 trace_assert(label_id.count > 0);
1059                 memset(action.entity_id, 0, ENTITY_MAX_ID_SIZE);
1060                 memcpy(action.entity_id,
1061                        label_id.data,
1062                        min_size_t(
1063                            ENTITY_MAX_ID_SIZE - 1,
1064                            label_id.count));
1065             } break;
1066
1067             case ACTION_N: break;
1068             }
1069         }
1070
1071         dynarray_push(&layer->actions, &action);
1072     }
1073 }
1074
1075 int rect_layer_render(const RectLayer *layer, const Camera *camera, int active)
1076 {
1077     trace_assert(layer);
1078     trace_assert(camera);
1079
1080     const size_t n = layer->rects.count;
1081     Rect *rects = (Rect *)layer->rects.data;
1082     Color *colors = (Color *)layer->colors.data;
1083     const char *ids = (const char *)layer->ids.data;
1084
1085     // The Rectangles
1086     for (size_t i = 0; i < n; ++i) {
1087         Rect rect = rects[i];
1088         Color color = colors[i];
1089
1090         if (layer->selection == (int) i) {
1091             if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
1092                 rect = layer->inter_rect;
1093             }
1094
1095             if (layer->state == RECT_LAYER_RECOLOR) {
1096                 color = layer->inter_color;
1097             }
1098         }
1099
1100         // Main Rectangle
1101         if (camera_fill_rect(
1102                 camera,
1103                 rect,
1104                 color_scale(
1105                     color,
1106                     rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
1107             return -1;
1108         }
1109     }
1110
1111     // Selection Overlay
1112     if (active && layer->selection >= 0) {
1113         Rect rect = rects[layer->selection];
1114         Color color = colors[layer->selection];
1115
1116         if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
1117             rect = layer->inter_rect;
1118         }
1119
1120         if (layer->state == RECT_LAYER_RECOLOR) {
1121             color = layer->inter_color;
1122         }
1123
1124         const Rect overlay_rect =
1125             rect_pad(
1126                 camera_rect(camera, rect),
1127                 -RECT_LAYER_SELECTION_THICCNESS * 0.5f);
1128         const Color overlay_color = color_invert(color);
1129
1130         // Selection
1131         if (camera_draw_thicc_rect_screen(
1132                 camera,
1133                 overlay_rect,
1134                 overlay_color,
1135                 RECT_LAYER_SELECTION_THICCNESS) < 0) {
1136             return -1;
1137         }
1138
1139         const Vec2f rect_id_pos = vec_sub(
1140             rect_position(rect),
1141             vec_mult(
1142                 RECT_LAYER_ID_LABEL_SIZE,
1143                 vec(0.0f, FONT_CHAR_HEIGHT)));
1144
1145         // Rectangle Id
1146         if (layer->state == RECT_LAYER_ID_RENAME) {
1147             // ID renaming Edit Field
1148             if (edit_field_render_world(
1149                     &layer->id_edit_field,
1150                     camera,
1151                     rect_id_pos) < 0) {
1152                 return -1;
1153             }
1154         } else {
1155             // Id text
1156             if (camera_render_text(
1157                     camera,
1158                     ids + layer->selection * ENTITY_MAX_ID_SIZE,
1159                     RECT_LAYER_ID_LABEL_SIZE,
1160                     color_invert(color),
1161                     rect_id_pos) < 0) {
1162                 return -1;
1163             }
1164         }
1165     }
1166
1167     // Proto Rectangle
1168     const Color color = color_picker_rgba(&layer->color_picker);
1169     if (layer->state == RECT_LAYER_CREATE) {
1170         if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
1171             return -1;
1172         }
1173     }
1174
1175     if (layer->state == RECT_LAYER_SUBTRACT) {
1176         if (camera_draw_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
1177             return -1;
1178         }
1179     }
1180
1181     if (active && color_picker_render(&layer->color_picker, camera) < 0) {
1182         return -1;
1183     }
1184
1185     // Tool bar
1186     if (active) {
1187         // TODO: subtract and snapping tools don't have any icons
1188         camera_fill_rect_screen(
1189             camera,
1190             subtract_tool_button_rect(camera),
1191             layer->subtract_enabled ? COLOR_RED : rgba(0.2f, 0.2f, 0.2f, 1.0f));
1192         camera_fill_rect_screen(
1193             camera,
1194             snapping_tool_button_rect(camera),
1195             layer->snapping_enabled ? COLOR_RED : rgba(0.2f, 0.2f, 0.2f, 1.0f));
1196     }
1197
1198     return 0;
1199 }
1200
1201 static
1202 int rect_layer_event_recolor(RectLayer *layer,
1203                              const SDL_Event *event,
1204                              const Camera *camera,
1205                              UndoHistory *undo_history)
1206 {
1207     trace_assert(layer);
1208     trace_assert(event);
1209     trace_assert(camera);
1210     trace_assert(undo_history);
1211     trace_assert(layer->selection >= 0);
1212
1213     int color_changed = 0;
1214     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
1215         return -1;
1216     }
1217
1218     if (color_changed) {
1219         layer->inter_color = color_picker_rgba(&layer->color_picker);
1220
1221         if (!color_picker_drag(&layer->color_picker)) {
1222             RECT_UNDO_PUSH(
1223                 undo_history,
1224                 create_rect_undo_update_context(
1225                     layer,
1226                     (size_t)layer->selection));
1227             dynarray_replace_at(&layer->colors, (size_t) layer->selection, &layer->inter_color);
1228             layer->state = RECT_LAYER_IDLE;
1229         }
1230     }
1231
1232     return 0;
1233 }
1234
1235 int rect_layer_event(RectLayer *layer,
1236                      const SDL_Event *event,
1237                      const Camera *camera,
1238                      UndoHistory *undo_history)
1239 {
1240     trace_assert(layer);
1241     trace_assert(event);
1242     trace_assert(undo_history);
1243
1244     switch (layer->state) {
1245     case RECT_LAYER_IDLE:
1246         return rect_layer_event_idle(layer, event, camera, undo_history);
1247
1248     case RECT_LAYER_CREATE:
1249         return rect_layer_event_create(layer, event, camera, undo_history);
1250
1251     case RECT_LAYER_RESIZE:
1252         return rect_layer_event_resize(layer, event, camera, undo_history);
1253
1254     case RECT_LAYER_MOVE:
1255         return rect_layer_event_move(layer, event, camera, undo_history);
1256
1257     case RECT_LAYER_ID_RENAME:
1258         return rect_layer_event_id_rename(layer, event, camera, undo_history);
1259
1260     case RECT_LAYER_RECOLOR:
1261         return rect_layer_event_recolor(layer, event, camera, undo_history);
1262
1263     case RECT_LAYER_SUBTRACT:
1264         return rect_layer_event_subtract(layer, event, camera, undo_history);
1265     }
1266
1267
1268     return 0;
1269 }
1270
1271 size_t rect_layer_count(const RectLayer *layer)
1272 {
1273     return layer->rects.count;
1274 }
1275
1276 const Rect *rect_layer_rects(const RectLayer *layer)
1277 {
1278     return (const Rect *)layer->rects.data;
1279 }
1280
1281 const Color *rect_layer_colors(const RectLayer *layer)
1282 {
1283     return (const Color *)layer->colors.data;
1284 }
1285
1286 const char *rect_layer_ids(const RectLayer *layer)
1287 {
1288     return (const char *)layer->ids.data;
1289 }
1290
1291 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
1292 {
1293     trace_assert(layer);
1294     trace_assert(filedump);
1295
1296     size_t n = layer->ids.count;
1297     char *ids = (char *)layer->ids.data;
1298     Rect *rects = (Rect *)layer->rects.data;
1299     Color *colors = (Color *)layer->colors.data;
1300     Action *actions = (Action *)layer->actions.data;
1301
1302     fprintf(filedump, "%zd\n", n);
1303     for (size_t i = 0; i < n; ++i) {
1304         fprintf(filedump, "%s %f %f %f %f ",
1305                 ids + ENTITY_MAX_ID_SIZE * i,
1306                 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
1307         color_hex_to_stream(colors[i], filedump);
1308
1309         switch (actions[i].type) {
1310         case ACTION_NONE: {} break;
1311
1312         case ACTION_TOGGLE_GOAL:
1313         case ACTION_HIDE_LABEL: {
1314             fprintf(filedump, " %d %.*s",
1315                     (int)actions[i].type,
1316                     ENTITY_MAX_ID_SIZE, actions[i].entity_id);
1317         } break;
1318         case ACTION_N: break;
1319         }
1320
1321         fprintf(filedump, "\n");
1322     }
1323
1324     return 0;
1325 }
1326
1327 const Action *rect_layer_actions(const RectLayer *layer)
1328 {
1329     return (const Action *)layer->actions.data;
1330 }