]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/rect_layer.c
(#1253) Let subtract tool cut out a window inside of a platform
[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 #define TOOL_BAR_BACKGROUND rgba(0.8f, 0.8f, 0.8f, 1.0f)
282 #define TOOL_BAR_FOREGROUND rgba(0.2f, 0.2f, 0.2f, 1.0f)
283
284 static
285 Rect subtract_tool_button_rect(const Camera *camera)
286 {
287     const Rect view_port = camera_view_port_screen(camera);
288     return rect(
289         TOOL_BAR_PADDING,
290         view_port.h - TOOL_BUTTON_HEIGHT - TOOL_BAR_PADDING,
291         TOOL_BUTTON_WIDTH,
292         TOOL_BUTTON_HEIGHT);
293 }
294
295 static
296 Rect snapping_tool_button_rect(const Camera *camera)
297 {
298     const Rect view_port = camera_view_port_screen(camera);
299     return rect(
300         TOOL_BAR_PADDING + TOOL_BUTTON_WIDTH + TOOL_BAR_PADDING,
301         view_port.h - TOOL_BUTTON_HEIGHT - TOOL_BAR_PADDING,
302         TOOL_BUTTON_WIDTH,
303         TOOL_BUTTON_HEIGHT);
304 }
305
306 static int rect_layer_event_idle(RectLayer *layer,
307                                  const SDL_Event *event,
308                                  const Camera *camera,
309                                  UndoHistory *undo_history)
310 {
311     trace_assert(layer);
312     trace_assert(event);
313     trace_assert(camera);
314
315     int color_changed = 0;
316     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
317         return -1;
318     }
319
320     if (color_changed) {
321         if (layer->selection >= 0) {
322             dynarray_copy_to(&layer->colors, &layer->inter_color, (size_t)layer->selection);
323             layer->state = RECT_LAYER_RECOLOR;
324         }
325         return 0;
326     }
327
328     Rect *rects = (Rect*)layer->rects.data;
329
330     switch (event->type) {
331     case SDL_MOUSEBUTTONDOWN: {
332         switch (event->button.button) {
333         case SDL_BUTTON_LEFT: {
334             Vec2f screen_position =
335                 vec((float) event->button.x,
336                     (float) event->button.y);
337             if (rect_contains_point(subtract_tool_button_rect(camera), screen_position)) {
338                 layer->subtract_enabled = !layer->subtract_enabled;
339                 return 0;
340             }
341
342             if (rect_contains_point(snapping_tool_button_rect(camera), screen_position)) {
343                 layer->snapping_enabled = !layer->snapping_enabled;
344                 return 0;
345             }
346
347             Vec2f position = camera_map_screen(
348                 camera,
349                 event->button.x,
350                 event->button.y);
351             int rect_at_position =
352                 rect_layer_rect_at(layer, position);
353
354
355             Color *colors = (Color*)layer->colors.data;
356
357             if (layer->subtract_enabled) {
358                 layer->state = RECT_LAYER_SUBTRACT;
359                 layer->create_begin = position;
360                 layer->create_end = position;
361             } else if (layer->selection >= 0 &&
362                        layer->selection == rect_at_position &&
363                        (layer->resize_mask = calc_resize_mask(
364                            vec((float) event->button.x, (float)event->button.y),
365                            camera_rect(camera, rects[layer->selection])))) {
366                 layer->state = RECT_LAYER_RESIZE;
367                 dynarray_copy_to(&layer->rects, &layer->inter_rect, (size_t) layer->selection);
368             } else if (rect_at_position >= 0) {
369                 layer->selection = rect_at_position;
370                 layer->state = RECT_LAYER_MOVE;
371                 layer->move_anchor = vec_sub(
372                     position,
373                     vec(
374                         rects[layer->selection].x,
375                         rects[layer->selection].y));
376                 layer->color_picker =
377                     create_color_picker_from_rgba(colors[rect_at_position]);
378                 dynarray_copy_to(&layer->rects, &layer->inter_rect, (size_t) rect_at_position);
379             } else {
380                 layer->selection = rect_at_position;
381
382                 if (layer->selection < 0) {
383                     layer->state = RECT_LAYER_CREATE;
384                     layer->create_begin = position;
385                     layer->create_end = position;
386                 }
387             }
388         } break;
389         }
390     } break;
391
392     case SDL_MOUSEMOTION: {
393         int resize_mask = 0;
394         Vec2f position = camera_map_screen(
395             camera,
396             event->button.x,
397             event->button.y);
398         if (layer->selection >= 0 &&
399             layer->selection == rect_layer_rect_at(layer, position) &&
400             (resize_mask = calc_resize_mask(
401                 vec((float) event->button.x, (float)event->button.y),
402                 camera_rect(camera, rects[layer->selection])))) {
403             layer->cursor->style = resize_styles[resize_mask];
404         } else {
405             layer->cursor->style = CURSOR_STYLE_POINTER;
406         }
407     } break;
408
409     case SDL_KEYDOWN: {
410         switch (event->key.keysym.sym) {
411         case SDLK_UP: {
412             if ((event->key.keysym.mod & KMOD_SHIFT)
413                 && (layer->selection >= 0)
414                 && ((size_t)(layer->selection + 1) < layer->rects.count)) {
415                 rect_layer_swap_elements(
416                     layer,
417                     (size_t) layer->selection,
418                     (size_t) layer->selection + 1,
419                     undo_history);
420                 layer->selection++;
421             }
422         } break;
423
424         case SDLK_DOWN: {
425             if ((event->key.keysym.mod & KMOD_SHIFT)
426                 && (layer->selection > 0)
427                 && ((size_t) layer->selection < layer->rects.count)) {
428                 rect_layer_swap_elements(
429                     layer,
430                     (size_t) layer->selection,
431                     (size_t) layer->selection - 1,
432                     undo_history);
433                 layer->selection--;
434             }
435         } break;
436
437         case SDLK_DELETE: {
438             if (layer->selection >= 0) {
439                 rect_layer_delete_rect_at_index(
440                     layer,
441                     (size_t) layer->selection,
442                     undo_history);
443                 layer->selection = -1;
444             }
445         } break;
446
447         case SDLK_q: {
448             // TODO(#1171): there is no UI indication that we are in the snapping mode
449             layer->snapping_enabled = !layer->snapping_enabled;
450         } break;
451
452         case SDLK_F2: {
453             if (layer->selection >= 0) {
454                 const char *ids = (char*)layer->ids.data;
455                 Color *colors = (Color*)layer->colors.data;
456
457                 edit_field_restyle(
458                     &layer->id_edit_field,
459                     RECT_LAYER_ID_LABEL_SIZE,
460                     color_invert(colors[layer->selection]));
461
462                 layer->state = RECT_LAYER_ID_RENAME;
463                 edit_field_replace(
464                     &layer->id_edit_field,
465                     ids + layer->selection * ENTITY_MAX_ID_SIZE);
466                 SDL_StartTextInput();
467             }
468         } break;
469
470         case SDLK_c: {
471             if ((event->key.keysym.mod & KMOD_LCTRL) && layer->selection >= 0) {
472                 rect_clipboard = 1;
473                 dynarray_copy_to(&layer->rects, &rect_clipboard_rect, (size_t)layer->selection);
474                 dynarray_copy_to(&layer->colors, &rect_clipboard_color, (size_t)layer->selection);
475             }
476         } break;
477
478         case SDLK_v: {
479             if ((event->key.keysym.mod & KMOD_LCTRL) && rect_clipboard) {
480                 int x, y;
481                 SDL_GetMouseState(&x, &y);
482                 Vec2f position = camera_map_screen(camera, x, y);
483
484                 rect_layer_add_rect(
485                     layer,
486                     rect(position.x, position.y,
487                          rect_clipboard_rect.w, rect_clipboard_rect.h),
488                     rect_clipboard_color,
489                     undo_history);
490             }
491         } break;
492         }
493     } break;
494     }
495
496     return 0;
497 }
498
499 #define GEOMETRY_CAPACITY 256
500
501 typedef struct {
502     size_t first;
503     size_t count;
504     Rect rects[GEOMETRY_CAPACITY];
505     Color colors[GEOMETRY_CAPACITY];
506 } Geometry;
507
508 static
509 void push_geometry(Geometry *geometry, Rect rect, Color color)
510 {
511     assert(geometry);
512     // TODO(#1252): push_geometry may fail if there is too many rects produced
513     assert(geometry->count < GEOMETRY_CAPACITY);
514
515     if ((rect.w * rect.h) > 1e-6f) {
516         size_t i = (geometry->first + geometry->count) % GEOMETRY_CAPACITY;
517         geometry->rects[i] = rect;
518         geometry->colors[i] = color;
519         geometry->count++;
520     }
521 }
522
523 static
524 void subtract_rect_from_rect(Rect a, Color color_a, Rect c, Geometry *result)
525 {
526     assert(result);
527
528     Rect b = rects_overlap_area(a, c);
529
530     if (b.w * b.h < 1e-6) {
531         push_geometry(result, a, color_a);
532         return;
533     }
534
535     push_geometry(result, (Rect) {a.x, a.y, a.w, b.y - a.y}, color_a);
536     push_geometry(result, (Rect) {a.x, b.y, b.x - a.x, b.h}, color_a);
537     push_geometry(result, (Rect) {
538         b.x + b.w,
539         b.y,
540         a.w - (b.x - a.x) - b.w,
541         b.h
542     }, color_a);
543     push_geometry(result, (Rect) {
544         a.x,
545         b.y + b.h,
546         a.w,
547         a.h - (b.y - a.y) - b.h
548     }, color_a);
549 }
550
551 static
552 void subtract_rect_from_geometry(Geometry *result, Rect b)
553 {
554     assert(result);
555
556     size_t count = result->count;
557     size_t first = result->first;
558
559     for (size_t i = 0; i < count; ++i) {
560         result->first = (result->first + 1) % GEOMETRY_CAPACITY;
561         result->count -= 1;
562         subtract_rect_from_rect(
563             result->rects[(i + first) % GEOMETRY_CAPACITY],
564             result->colors[(i + first) % GEOMETRY_CAPACITY],
565             b,
566             result);
567     }
568 }
569
570 static int rect_layer_event_subtract(RectLayer *layer,
571                                      const SDL_Event *event,
572                                      const Camera *camera,
573                                      UndoHistory *undo_history)
574 {
575     trace_assert(layer);
576     trace_assert(event);
577     trace_assert(camera);
578     trace_assert(undo_history);
579
580     Rect *rects = layer->rects.data;
581     Color *colors = layer->colors.data;
582
583     switch (event->type) {
584     case SDL_MOUSEBUTTONUP: {
585         switch (event->button.button) {
586         case SDL_BUTTON_LEFT: {
587             const Rect real_rect =
588                 rect_from_points(
589                     layer->create_begin,
590                     layer->create_end);
591             const float area = real_rect.w * real_rect.h;
592
593             Geometry geometry = {0};
594
595             if (area >= CREATE_AREA_THRESHOLD) {
596                 for (size_t i = 0; i < layer->rects.count;) {
597                     Rect overlap_area = rects_overlap_area(
598                         real_rect,
599                         rects[i]);
600                     if (overlap_area.w * overlap_area.h > 1e-6) {
601                         push_geometry(&geometry, rects[i], colors[i]);
602                         rect_layer_delete_rect_at_index(layer, i, undo_history);
603                     } else {
604                         i++;
605                     }
606                 }
607
608                 subtract_rect_from_geometry(&geometry, real_rect);
609
610                 for (size_t i = 0; i < geometry.count; ++i) {
611                     size_t j = (i + geometry.first) % GEOMETRY_CAPACITY;
612                     rect_layer_add_rect(
613                         layer,
614                         geometry.rects[j],
615                         geometry.colors[j],
616                         undo_history);
617                 }
618             } else {
619                 log_info("The area is too small %f. Such small box won't be cut.\n", area);
620             }
621             layer->state = RECT_LAYER_IDLE;
622         } break;
623         }
624     } break;
625
626     case SDL_MOUSEMOTION: {
627         layer->create_end = camera_map_screen(
628             camera,
629             event->motion.x,
630             event->motion.y);
631     } break;
632     }
633
634     return 0;
635 }
636
637 static int rect_layer_event_create(RectLayer *layer,
638                                    const SDL_Event *event,
639                                    const Camera *camera,
640                                    UndoHistory *undo_history)
641 {
642     trace_assert(layer);
643     trace_assert(event);
644     trace_assert(camera);
645
646     switch (event->type) {
647     case SDL_MOUSEBUTTONUP: {
648         switch (event->button.button) {
649         case SDL_BUTTON_LEFT: {
650             const Rect real_rect =
651                 rect_from_points(
652                     layer->create_begin,
653                     layer->create_end);
654             const float area = real_rect.w * real_rect.h;
655
656             if (area >= CREATE_AREA_THRESHOLD) {
657                 rect_layer_add_rect(
658                     layer,
659                     real_rect,
660                     color_picker_rgba(&layer->color_picker),
661                     undo_history);
662             } else {
663                 log_info("The area is too small %f. Such small box won't be created.\n", area);
664             }
665             layer->state = RECT_LAYER_IDLE;
666         } break;
667         }
668     } break;
669
670     case SDL_MOUSEMOTION: {
671         layer->create_end = camera_map_screen(
672             camera,
673             event->motion.x,
674             event->motion.y);
675     } break;
676     }
677     return 0;
678 }
679
680 static
681 void snap_rect_resize_if_enabled(RectLayer *layer, Rect *a, float snapping_threshold)
682 {
683     trace_assert(layer);
684     trace_assert(layer->selection >= 0);
685     trace_assert(a);
686
687     if (!layer->snapping_enabled) return;
688
689     Rect *rects = (Rect*)layer->rects.data;
690     size_t rects_size = layer->rects.count;
691
692     for (size_t i = 0; i < rects_size; ++i) {
693         if (i == (size_t) layer->selection) continue;
694
695         const Rect b = rects[i];
696
697         if (segment_overlap(vec(a->x, a->x + a->w), vec(b.x, b.x + b.w))) {
698             snap_var2seg(&a->y, b.y, 0, b.h, snapping_threshold);
699         }
700
701         if (segment_overlap(vec(a->y, a->y + a->h), vec(b.y, b.y + b.h))) {
702             snap_var2seg(&a->x, b.x, 0, b.w, snapping_threshold);
703         }
704     }
705 }
706
707 static int rect_layer_event_resize(RectLayer *layer,
708                                    const SDL_Event *event,
709                                    const Camera *camera,
710                                    UndoHistory *undo_history)
711 {
712     trace_assert(layer);
713     trace_assert(event);
714     trace_assert(camera);
715     trace_assert(layer->selection >= 0);
716
717     Rect *rects = (Rect*)layer->rects.data;
718
719     float scaled_snap_threshold = SNAPPING_THRESHOLD / camera->scale;
720
721     switch (event->type) {
722     case SDL_MOUSEMOTION: {
723         Vec2f position = camera_map_screen(
724             camera,
725             event->button.x,
726             event->button.y);
727
728         switch (layer->resize_mask) {
729         case 1: {               // TOP
730             Rect a = rect(rects[layer->selection].x,
731                           position.y,
732                           rects[layer->selection].w,
733                           rects[layer->selection].h);
734
735             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
736
737             layer->inter_rect = rect_from_points(
738                 vec(a.x, a.y),
739                 rect_position2(rects[layer->selection]));
740         } break;
741
742         case 2: {               // LEFT
743             Rect a = rect(position.x,
744                           rects[layer->selection].y,
745                           rects[layer->selection].w,
746                           rects[layer->selection].h);
747
748             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
749
750             layer->inter_rect = rect_from_points(
751                 vec(a.x, a.y),
752                 rect_position2(rects[layer->selection]));
753         } break;
754
755         case 3: {               // TOP,LEFT
756             Rect a = rect(
757                 position.x,
758                 position.y,
759                 rects[layer->selection].w,
760                 rects[layer->selection].h);
761
762             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
763
764             layer->inter_rect = rect_from_points(
765                 vec(a.x, a.y),
766                 rect_position2(rects[layer->selection]));
767         } break;
768
769         case 4: {               // BOTTOM
770             Rect a = rect(rects[layer->selection].x,
771                           position.y,
772                           rects[layer->selection].w,
773                           rects[layer->selection].h);
774
775             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
776
777             layer->inter_rect = rect_from_points(
778                 rect_position(rects[layer->selection]),
779                 vec(rects[layer->selection].x + rects[layer->selection].w,
780                     a.y));
781         } break;
782
783         case 6: {               // BOTTOM,LEFT
784             Rect a = rect(
785                 position.x,
786                 position.y,
787                 rects[layer->selection].w,
788                 -rects[layer->selection].h);
789
790             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
791
792             layer->inter_rect = rect_from_points(
793                 vec(a.x, rects[layer->selection].y),
794                 vec(rects[layer->selection].x + rects[layer->selection].w,
795                     a.y));
796         } break;
797
798         case 8: {               // RIGHT
799             Rect a = rect(position.x,
800                           rects[layer->selection].y,
801                           rects[layer->selection].w,
802                           rects[layer->selection].h);
803
804             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
805
806             layer->inter_rect = rect_from_points(
807                 rect_position(rects[layer->selection]),
808                 vec(a.x, rects[layer->selection].y + rects[layer->selection].h));
809         } break;
810
811         case 9: {               // TOP,RIGHT
812             Rect a = rect(
813                 position.x,
814                 position.y,
815                 -rects[layer->selection].w,
816                 rects[layer->selection].h);
817
818             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
819
820             layer->inter_rect = rect_from_points(
821                 vec(rects[layer->selection].x, a.y),
822                 vec(a.x,
823                     rects[layer->selection].y + rects[layer->selection].h));
824         } break;
825
826         case 12: {              // BOTTOM,RIGHT
827             Rect a = rect(
828                 position.x,
829                 position.y,
830                 -rects[layer->selection].w,
831                 -rects[layer->selection].h);
832
833             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
834
835             layer->inter_rect = rect_from_points(
836                 rect_position(rects[layer->selection]),
837                 vec(a.x, a.y));
838         } break;
839         }
840
841     } break;
842
843     case SDL_MOUSEBUTTONUP: {
844         layer->state = RECT_LAYER_IDLE;
845         RECT_UNDO_PUSH(
846             undo_history,
847             create_rect_undo_update_context(
848                 layer,
849                 (size_t) layer->selection));
850         dynarray_replace_at(&layer->rects, (size_t) layer->selection, &layer->inter_rect);
851     } break;
852     }
853
854     return 0;
855 }
856
857 static
858 void snap_rect_move_if_enabled(RectLayer *layer, Rect *a,
859                                float snapping_threshold)
860 {
861     trace_assert(a);
862     trace_assert(layer);
863     trace_assert(layer->selection >= 0);
864
865     if (!layer->snapping_enabled) return;
866
867     Rect *rects = (Rect*)layer->rects.data;
868     size_t rects_size = layer->rects.count;
869
870     for (size_t i = 0; i < rects_size; ++i) {
871         if (i == (size_t) layer->selection) continue;
872
873         const Rect b = rects[i];
874
875         if (segment_overlap(vec(a->x, a->x + a->w), vec(b.x,  b.x  + b.w))) {
876             snap_seg2seg(&a->y, b.y, a->h, b.h, snapping_threshold);
877         }
878
879         if (segment_overlap(vec(a->y, a->y + a->h), vec(b.y,  b.y  + b.h))) {
880             snap_seg2seg(&a->x, b.x, a->w, b.w, snapping_threshold);
881         }
882     }
883 }
884
885 static int rect_layer_event_move(RectLayer *layer,
886                                  const SDL_Event *event,
887                                  const Camera *camera,
888                                  UndoHistory *undo_history)
889 {
890     trace_assert(layer);
891     trace_assert(event);
892     trace_assert(camera);
893     trace_assert(layer->selection >= 0);
894
895     Rect *rects = (Rect*)layer->rects.data;
896
897     switch (event->type) {
898     case SDL_MOUSEMOTION: {
899         const Uint8 *state = SDL_GetKeyboardState(NULL);
900         const Vec2f mouse_pos = vec_sub(
901             camera_map_screen(
902                 camera,
903                 event->button.x,
904                 event->button.y),
905             layer->move_anchor);
906
907         if (!(state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL])) {
908             layer->inter_rect.x = mouse_pos.x;
909             layer->inter_rect.y = mouse_pos.y;
910         } else {
911             const Vec2f rect_pos = rect_position(rects[layer->selection]);
912
913             const float dx = fabsf(rect_pos.x - mouse_pos.x);
914             const float dy = fabsf(rect_pos.y - mouse_pos.y);
915
916             if (dx > dy) {
917                 layer->inter_rect.x = mouse_pos.x;
918                 layer->inter_rect.y = rect_pos.y;
919             } else {
920                 layer->inter_rect.x = rect_pos.x;
921                 layer->inter_rect.y = mouse_pos.y;
922             }
923         }
924
925         snap_rect_move_if_enabled(layer, &layer->inter_rect,
926                                   SNAPPING_THRESHOLD / camera->scale);
927     } break;
928
929     case SDL_MOUSEBUTTONUP: {
930         layer->state = RECT_LAYER_IDLE;
931
932         float distance = vec_length(
933             vec_sub(rect_position(layer->inter_rect),
934                     rect_position(rects[layer->selection])));
935
936         if (distance > 1e-6) {
937             RECT_UNDO_PUSH(
938                 undo_history,
939                 create_rect_undo_update_context(
940                     layer, (size_t) layer->selection));
941             dynarray_replace_at(
942                 &layer->rects,
943                 (size_t) layer->selection,
944                 &layer->inter_rect);
945         }
946     } break;
947     }
948     return 0;
949 }
950
951 static int rect_layer_event_id_rename(RectLayer *layer,
952                                       const SDL_Event *event,
953                                       const Camera *camera,
954                                       UndoHistory *undo_history)
955 {
956     trace_assert(layer);
957     trace_assert(event);
958     trace_assert(camera);
959     trace_assert(layer->selection >= 0);
960
961     switch (event->type) {
962     case SDL_KEYDOWN: {
963         switch (event->key.keysym.sym) {
964         case SDLK_RETURN: {
965             RECT_UNDO_PUSH(
966                 undo_history,
967                 create_rect_undo_update_context(
968                     layer,
969                     (size_t) layer->selection));
970
971             char *id = dynarray_pointer_at(&layer->ids, (size_t)layer->selection);
972             memset(id, 0, ENTITY_MAX_ID_SIZE);
973             memcpy(id, edit_field_as_text(&layer->id_edit_field), ENTITY_MAX_ID_SIZE - 1);
974             layer->state = RECT_LAYER_IDLE;
975             SDL_StopTextInput();
976         } break;
977
978         case SDLK_ESCAPE: {
979             layer->state = RECT_LAYER_IDLE;
980             SDL_StopTextInput();
981         } break;
982         }
983     } break;
984     }
985
986     return edit_field_event(&layer->id_edit_field, event);
987 }
988
989 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
990 {
991     LayerPtr layer = {
992         .type = LAYER_RECT,
993         .ptr = rect_layer
994     };
995     return layer;
996 }
997
998 RectLayer *create_rect_layer(Memory *memory,
999                              const char *id_name_prefix,
1000                              Cursor *cursor)
1001 {
1002     trace_assert(memory);
1003     trace_assert(id_name_prefix);
1004     trace_assert(cursor);
1005
1006     RectLayer *rect_layer = memory_alloc(memory, sizeof(RectLayer));
1007
1008     rect_layer->ids = create_dynarray(memory, sizeof(char) * ENTITY_MAX_ID_SIZE);
1009     rect_layer->rects = create_dynarray(memory, sizeof(Rect));
1010     rect_layer->colors = create_dynarray(memory, sizeof(Color));
1011     rect_layer->actions = create_dynarray(memory, sizeof(Action));
1012     rect_layer->id_edit_field.font_size = RECT_LAYER_ID_LABEL_SIZE;
1013     rect_layer->id_edit_field.font_color = COLOR_BLACK;
1014     rect_layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
1015     rect_layer->selection = -1;
1016     rect_layer->id_name_prefix = id_name_prefix;
1017     rect_layer->cursor = cursor;
1018
1019     return rect_layer;
1020 }
1021
1022 void rect_layer_load(RectLayer *layer, Memory *memory, String *input)
1023 {
1024     trace_assert(layer);
1025     trace_assert(memory);
1026     trace_assert(input);
1027
1028     int n = atoi(string_to_cstr(memory, trim(chop_by_delim(input, '\n'))));
1029     char id[ENTITY_MAX_ID_SIZE];
1030     for (int i = 0; i < n; ++i) {
1031         Rect rect;
1032         String line = trim(chop_by_delim(input, '\n'));
1033         String string_id = trim(chop_word(&line));
1034         rect.x = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1035         rect.y = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1036         rect.w = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1037         rect.h = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1038         Color color = hexs(trim(chop_word(&line)));
1039
1040         memset(id, 0, ENTITY_MAX_ID_SIZE);
1041         memcpy(
1042             id,
1043             string_id.data,
1044             min_size_t(ENTITY_MAX_ID_SIZE - 1, string_id.count));
1045
1046         dynarray_push(&layer->rects, &rect);
1047         dynarray_push(&layer->colors, &color);
1048         dynarray_push(&layer->ids, id);
1049
1050         Action action = {
1051             .type = ACTION_NONE,
1052             .entity_id = {0}
1053         };
1054
1055         String action_string = trim(chop_word(&line));
1056         if (action_string.count > 0) {
1057             action.type = (ActionType)atol(string_to_cstr(memory, action_string));
1058             switch (action.type) {
1059             case ACTION_NONE: break;
1060             case ACTION_TOGGLE_GOAL:
1061             case ACTION_HIDE_LABEL: {
1062                 String label_id = trim(chop_word(&line));
1063                 trace_assert(label_id.count > 0);
1064                 memset(action.entity_id, 0, ENTITY_MAX_ID_SIZE);
1065                 memcpy(action.entity_id,
1066                        label_id.data,
1067                        min_size_t(
1068                            ENTITY_MAX_ID_SIZE - 1,
1069                            label_id.count));
1070             } break;
1071
1072             case ACTION_N: break;
1073             }
1074         }
1075
1076         dynarray_push(&layer->actions, &action);
1077     }
1078 }
1079
1080 static
1081 void render_tool_bar_button(const Camera *camera,
1082                             Rect button_rect, const char *text,
1083                             Color background_color,
1084                             Color foreground_color)
1085 {
1086     const Vec2f text_size = vec(5.0f, 5.0f);
1087     const Rect text_rect = sprite_font_boundary_box(
1088         vec(0.0f, 0.0f), text_size, text);
1089     camera_fill_rect_screen(
1090         camera,
1091         button_rect,
1092         background_color);
1093     camera_render_text_screen(
1094         camera,
1095         text,
1096         text_size,
1097         foreground_color,
1098         vec(
1099             button_rect.x + (button_rect.w - text_rect.w) * 0.5f,
1100             button_rect.y + (button_rect.h - text_rect.h) * 0.5f));
1101 }
1102
1103
1104 int rect_layer_render(const RectLayer *layer, const Camera *camera, int active)
1105 {
1106     trace_assert(layer);
1107     trace_assert(camera);
1108
1109     const size_t n = layer->rects.count;
1110     Rect *rects = (Rect *)layer->rects.data;
1111     Color *colors = (Color *)layer->colors.data;
1112     const char *ids = (const char *)layer->ids.data;
1113
1114     // The Rectangles
1115     for (size_t i = 0; i < n; ++i) {
1116         Rect rect = rects[i];
1117         Color color = colors[i];
1118
1119         if (layer->selection == (int) i) {
1120             if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
1121                 rect = layer->inter_rect;
1122             }
1123
1124             if (layer->state == RECT_LAYER_RECOLOR) {
1125                 color = layer->inter_color;
1126             }
1127         }
1128
1129         // Main Rectangle
1130         if (camera_fill_rect(
1131                 camera,
1132                 rect,
1133                 color_scale(
1134                     color,
1135                     rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
1136             return -1;
1137         }
1138     }
1139
1140     // Selection Overlay
1141     if (active && layer->selection >= 0) {
1142         Rect rect = rects[layer->selection];
1143         Color color = colors[layer->selection];
1144
1145         if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
1146             rect = layer->inter_rect;
1147         }
1148
1149         if (layer->state == RECT_LAYER_RECOLOR) {
1150             color = layer->inter_color;
1151         }
1152
1153         const Rect overlay_rect =
1154             rect_pad(
1155                 camera_rect(camera, rect),
1156                 -RECT_LAYER_SELECTION_THICCNESS * 0.5f);
1157         const Color overlay_color = color_invert(color);
1158
1159         // Selection
1160         if (camera_draw_thicc_rect_screen(
1161                 camera,
1162                 overlay_rect,
1163                 overlay_color,
1164                 RECT_LAYER_SELECTION_THICCNESS) < 0) {
1165             return -1;
1166         }
1167
1168         const Vec2f rect_id_pos = vec_sub(
1169             rect_position(rect),
1170             vec_mult(
1171                 RECT_LAYER_ID_LABEL_SIZE,
1172                 vec(0.0f, FONT_CHAR_HEIGHT)));
1173
1174         // Rectangle Id
1175         if (layer->state == RECT_LAYER_ID_RENAME) {
1176             // ID renaming Edit Field
1177             if (edit_field_render_world(
1178                     &layer->id_edit_field,
1179                     camera,
1180                     rect_id_pos) < 0) {
1181                 return -1;
1182             }
1183         } else {
1184             // Id text
1185             if (camera_render_text(
1186                     camera,
1187                     ids + layer->selection * ENTITY_MAX_ID_SIZE,
1188                     RECT_LAYER_ID_LABEL_SIZE,
1189                     color_invert(color),
1190                     rect_id_pos) < 0) {
1191                 return -1;
1192             }
1193         }
1194     }
1195
1196     // Proto Rectangle
1197     const Color color = color_picker_rgba(&layer->color_picker);
1198     if (layer->state == RECT_LAYER_CREATE) {
1199         if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
1200             return -1;
1201         }
1202     }
1203
1204     if (layer->state == RECT_LAYER_SUBTRACT) {
1205         if (camera_draw_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
1206             return -1;
1207         }
1208     }
1209
1210     if (active && color_picker_render(&layer->color_picker, camera) < 0) {
1211         return -1;
1212     }
1213
1214     // Tool bar
1215     if (active) {
1216         render_tool_bar_button(
1217             camera, subtract_tool_button_rect(camera), "/",
1218             layer->subtract_enabled ? TOOL_BAR_BACKGROUND : TOOL_BAR_FOREGROUND,
1219             layer->subtract_enabled ? TOOL_BAR_FOREGROUND : TOOL_BAR_BACKGROUND);
1220
1221         render_tool_bar_button(
1222             camera, snapping_tool_button_rect(camera), "S",
1223             layer->snapping_enabled ? TOOL_BAR_BACKGROUND : TOOL_BAR_FOREGROUND,
1224             layer->snapping_enabled ? TOOL_BAR_FOREGROUND : TOOL_BAR_BACKGROUND);
1225     }
1226
1227     return 0;
1228 }
1229
1230 static
1231 int rect_layer_event_recolor(RectLayer *layer,
1232                              const SDL_Event *event,
1233                              const Camera *camera,
1234                              UndoHistory *undo_history)
1235 {
1236     trace_assert(layer);
1237     trace_assert(event);
1238     trace_assert(camera);
1239     trace_assert(undo_history);
1240     trace_assert(layer->selection >= 0);
1241
1242     int color_changed = 0;
1243     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
1244         return -1;
1245     }
1246
1247     if (color_changed) {
1248         layer->inter_color = color_picker_rgba(&layer->color_picker);
1249
1250         if (!color_picker_drag(&layer->color_picker)) {
1251             RECT_UNDO_PUSH(
1252                 undo_history,
1253                 create_rect_undo_update_context(
1254                     layer,
1255                     (size_t)layer->selection));
1256             dynarray_replace_at(&layer->colors, (size_t) layer->selection, &layer->inter_color);
1257             layer->state = RECT_LAYER_IDLE;
1258         }
1259     }
1260
1261     return 0;
1262 }
1263
1264 int rect_layer_event(RectLayer *layer,
1265                      const SDL_Event *event,
1266                      const Camera *camera,
1267                      UndoHistory *undo_history)
1268 {
1269     trace_assert(layer);
1270     trace_assert(event);
1271     trace_assert(undo_history);
1272
1273     switch (layer->state) {
1274     case RECT_LAYER_IDLE:
1275         return rect_layer_event_idle(layer, event, camera, undo_history);
1276
1277     case RECT_LAYER_CREATE:
1278         return rect_layer_event_create(layer, event, camera, undo_history);
1279
1280     case RECT_LAYER_RESIZE:
1281         return rect_layer_event_resize(layer, event, camera, undo_history);
1282
1283     case RECT_LAYER_MOVE:
1284         return rect_layer_event_move(layer, event, camera, undo_history);
1285
1286     case RECT_LAYER_ID_RENAME:
1287         return rect_layer_event_id_rename(layer, event, camera, undo_history);
1288
1289     case RECT_LAYER_RECOLOR:
1290         return rect_layer_event_recolor(layer, event, camera, undo_history);
1291
1292     case RECT_LAYER_SUBTRACT:
1293         return rect_layer_event_subtract(layer, event, camera, undo_history);
1294     }
1295
1296
1297     return 0;
1298 }
1299
1300 size_t rect_layer_count(const RectLayer *layer)
1301 {
1302     return layer->rects.count;
1303 }
1304
1305 const Rect *rect_layer_rects(const RectLayer *layer)
1306 {
1307     return (const Rect *)layer->rects.data;
1308 }
1309
1310 const Color *rect_layer_colors(const RectLayer *layer)
1311 {
1312     return (const Color *)layer->colors.data;
1313 }
1314
1315 const char *rect_layer_ids(const RectLayer *layer)
1316 {
1317     return (const char *)layer->ids.data;
1318 }
1319
1320 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
1321 {
1322     trace_assert(layer);
1323     trace_assert(filedump);
1324
1325     size_t n = layer->ids.count;
1326     char *ids = (char *)layer->ids.data;
1327     Rect *rects = (Rect *)layer->rects.data;
1328     Color *colors = (Color *)layer->colors.data;
1329     Action *actions = (Action *)layer->actions.data;
1330
1331     fprintf(filedump, "%zd\n", n);
1332     for (size_t i = 0; i < n; ++i) {
1333         fprintf(filedump, "%s %f %f %f %f ",
1334                 ids + ENTITY_MAX_ID_SIZE * i,
1335                 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
1336         color_hex_to_stream(colors[i], filedump);
1337
1338         switch (actions[i].type) {
1339         case ACTION_NONE: {} break;
1340
1341         case ACTION_TOGGLE_GOAL:
1342         case ACTION_HIDE_LABEL: {
1343             fprintf(filedump, " %d %.*s",
1344                     (int)actions[i].type,
1345                     ENTITY_MAX_ID_SIZE, actions[i].entity_id);
1346         } break;
1347         case ACTION_N: break;
1348         }
1349
1350         fprintf(filedump, "\n");
1351     }
1352
1353     return 0;
1354 }
1355
1356 const Action *rect_layer_actions(const RectLayer *layer)
1357 {
1358     return (const Action *)layer->actions.data;
1359 }