]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/rect_layer.c
cae9ee8d5ac4df5b20c11ae98fabea7172407125
[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     // TODO(#1252): push_geometry may fail if there is too many rects produced
509     assert(geometry->count < GEOMETRY_CAPACITY);
510
511     if ((rect.w * rect.h) > 1e-6f) {
512         size_t i = (geometry->first + geometry->count) % GEOMETRY_CAPACITY;
513         geometry->rects[i] = rect;
514         geometry->colors[i] = color;
515         geometry->count++;
516     }
517 }
518
519 static
520 void subtract_rect_from_rect(Rect a, Color color_a, Rect c, Geometry *result)
521 {
522     assert(result);
523
524     Rect b = rects_overlap_area(a, c);
525
526     if (b.w * b.h < 1e-6) {
527         push_geometry(result, a, color_a);
528         return;
529     }
530
531     push_geometry(result, (Rect) {a.x, a.y, a.w, b.y - a.y}, color_a);
532     push_geometry(result, (Rect) {a.x, b.y, b.x - a.x, b.h}, color_a);
533     push_geometry(result, (Rect) {
534         b.x + b.w,
535         b.y,
536         a.w - (b.x - a.x) - b.w,
537         b.h
538     }, color_a);
539     push_geometry(result, (Rect) {
540         a.x,
541         b.y + b.h,
542         a.w,
543         a.h - (b.y - a.y) - b.h
544     }, color_a);
545 }
546
547 static
548 void subtract_rect_from_geometry(Geometry *result, Rect b)
549 {
550     assert(result);
551
552     size_t count = result->count;
553     size_t first = result->first;
554
555     for (size_t i = 0; i < count; ++i) {
556         result->first = (result->first + 1) % GEOMETRY_CAPACITY;
557         result->count -= 1;
558         subtract_rect_from_rect(
559             result->rects[(i + first) % GEOMETRY_CAPACITY],
560             result->colors[(i + first) % GEOMETRY_CAPACITY],
561             b,
562             result);
563     }
564 }
565
566 static int rect_layer_event_subtract(RectLayer *layer,
567                                      const SDL_Event *event,
568                                      const Camera *camera,
569                                      UndoHistory *undo_history)
570 {
571     trace_assert(layer);
572     trace_assert(event);
573     trace_assert(camera);
574     trace_assert(undo_history);
575
576     Rect *rects = layer->rects.data;
577     Color *colors = layer->colors.data;
578
579     switch (event->type) {
580     case SDL_MOUSEBUTTONUP: {
581         switch (event->button.button) {
582         case SDL_BUTTON_LEFT: {
583             const Rect real_rect =
584                 rect_from_points(
585                     layer->create_begin,
586                     layer->create_end);
587             const float area = real_rect.w * real_rect.h;
588
589             Geometry geometry = {0};
590
591             if (area >= CREATE_AREA_THRESHOLD) {
592                 for (size_t i = 0; i < layer->rects.count;) {
593                     Rect overlap_area = rects_overlap_area(
594                         real_rect,
595                         rects[i]);
596                     if (overlap_area.w * overlap_area.h > 1e-6) {
597                         push_geometry(&geometry, rects[i], colors[i]);
598                         rect_layer_delete_rect_at_index(layer, i, undo_history);
599                     } else {
600                         i++;
601                     }
602                 }
603
604                 subtract_rect_from_geometry(&geometry, real_rect);
605
606                 for (size_t i = 0; i < geometry.count; ++i) {
607                     size_t j = (i + geometry.first) % GEOMETRY_CAPACITY;
608                     rect_layer_add_rect(
609                         layer,
610                         geometry.rects[j],
611                         geometry.colors[j],
612                         undo_history);
613                 }
614             } else {
615                 log_info("The area is too small %f. Such small box won't be cut.\n", area);
616             }
617             layer->state = RECT_LAYER_IDLE;
618         } break;
619         }
620     } break;
621
622     case SDL_MOUSEMOTION: {
623         layer->create_end = camera_map_screen(
624             camera,
625             event->motion.x,
626             event->motion.y);
627     } break;
628     }
629
630     return 0;
631 }
632
633 static int rect_layer_event_create(RectLayer *layer,
634                                    const SDL_Event *event,
635                                    const Camera *camera,
636                                    UndoHistory *undo_history)
637 {
638     trace_assert(layer);
639     trace_assert(event);
640     trace_assert(camera);
641
642     switch (event->type) {
643     case SDL_MOUSEBUTTONUP: {
644         switch (event->button.button) {
645         case SDL_BUTTON_LEFT: {
646             const Rect real_rect =
647                 rect_from_points(
648                     layer->create_begin,
649                     layer->create_end);
650             const float area = real_rect.w * real_rect.h;
651
652             if (area >= CREATE_AREA_THRESHOLD) {
653                 rect_layer_add_rect(
654                     layer,
655                     real_rect,
656                     color_picker_rgba(&layer->color_picker),
657                     undo_history);
658             } else {
659                 log_info("The area is too small %f. Such small box won't be created.\n", area);
660             }
661             layer->state = RECT_LAYER_IDLE;
662         } break;
663         }
664     } break;
665
666     case SDL_MOUSEMOTION: {
667         layer->create_end = camera_map_screen(
668             camera,
669             event->motion.x,
670             event->motion.y);
671     } break;
672     }
673     return 0;
674 }
675
676 static
677 void snap_rect_resize_if_enabled(RectLayer *layer, Rect *a, float snapping_threshold)
678 {
679     trace_assert(layer);
680     trace_assert(layer->selection >= 0);
681     trace_assert(a);
682
683     if (!layer->snapping_enabled) return;
684
685     Rect *rects = (Rect*)layer->rects.data;
686     size_t rects_size = layer->rects.count;
687
688     for (size_t i = 0; i < rects_size; ++i) {
689         if (i == (size_t) layer->selection) continue;
690
691         const Rect b = rects[i];
692
693         if (segment_overlap(vec(a->x, a->x + a->w), vec(b.x, b.x + b.w))) {
694             snap_var2seg(&a->y, b.y, 0, b.h, snapping_threshold);
695         }
696
697         if (segment_overlap(vec(a->y, a->y + a->h), vec(b.y, b.y + b.h))) {
698             snap_var2seg(&a->x, b.x, 0, b.w, snapping_threshold);
699         }
700     }
701 }
702
703 static int rect_layer_event_resize(RectLayer *layer,
704                                    const SDL_Event *event,
705                                    const Camera *camera,
706                                    UndoHistory *undo_history)
707 {
708     trace_assert(layer);
709     trace_assert(event);
710     trace_assert(camera);
711     trace_assert(layer->selection >= 0);
712
713     Rect *rects = (Rect*)layer->rects.data;
714
715     float scaled_snap_threshold = SNAPPING_THRESHOLD / camera->scale;
716
717     switch (event->type) {
718     case SDL_MOUSEMOTION: {
719         Vec2f position = camera_map_screen(
720             camera,
721             event->button.x,
722             event->button.y);
723
724         switch (layer->resize_mask) {
725         case 1: {               // TOP
726             Rect a = rect(rects[layer->selection].x,
727                           position.y,
728                           rects[layer->selection].w,
729                           rects[layer->selection].h);
730
731             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
732
733             layer->inter_rect = rect_from_points(
734                 vec(a.x, a.y),
735                 rect_position2(rects[layer->selection]));
736         } break;
737
738         case 2: {               // LEFT
739             Rect a = rect(position.x,
740                           rects[layer->selection].y,
741                           rects[layer->selection].w,
742                           rects[layer->selection].h);
743
744             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
745
746             layer->inter_rect = rect_from_points(
747                 vec(a.x, a.y),
748                 rect_position2(rects[layer->selection]));
749         } break;
750
751         case 3: {               // TOP,LEFT
752             Rect a = rect(
753                 position.x,
754                 position.y,
755                 rects[layer->selection].w,
756                 rects[layer->selection].h);
757
758             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
759
760             layer->inter_rect = rect_from_points(
761                 vec(a.x, a.y),
762                 rect_position2(rects[layer->selection]));
763         } break;
764
765         case 4: {               // BOTTOM
766             Rect a = rect(rects[layer->selection].x,
767                           position.y,
768                           rects[layer->selection].w,
769                           rects[layer->selection].h);
770
771             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
772
773             layer->inter_rect = rect_from_points(
774                 rect_position(rects[layer->selection]),
775                 vec(rects[layer->selection].x + rects[layer->selection].w,
776                     a.y));
777         } break;
778
779         case 6: {               // BOTTOM,LEFT
780             Rect a = rect(
781                 position.x,
782                 position.y,
783                 rects[layer->selection].w,
784                 -rects[layer->selection].h);
785
786             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
787
788             layer->inter_rect = rect_from_points(
789                 vec(a.x, rects[layer->selection].y),
790                 vec(rects[layer->selection].x + rects[layer->selection].w,
791                     a.y));
792         } break;
793
794         case 8: {               // RIGHT
795             Rect a = rect(position.x,
796                           rects[layer->selection].y,
797                           rects[layer->selection].w,
798                           rects[layer->selection].h);
799
800             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
801
802             layer->inter_rect = rect_from_points(
803                 rect_position(rects[layer->selection]),
804                 vec(a.x, rects[layer->selection].y + rects[layer->selection].h));
805         } break;
806
807         case 9: {               // TOP,RIGHT
808             Rect a = rect(
809                 position.x,
810                 position.y,
811                 -rects[layer->selection].w,
812                 rects[layer->selection].h);
813
814             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
815
816             layer->inter_rect = rect_from_points(
817                 vec(rects[layer->selection].x, a.y),
818                 vec(a.x,
819                     rects[layer->selection].y + rects[layer->selection].h));
820         } break;
821
822         case 12: {              // BOTTOM,RIGHT
823             Rect a = rect(
824                 position.x,
825                 position.y,
826                 -rects[layer->selection].w,
827                 -rects[layer->selection].h);
828
829             snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
830
831             layer->inter_rect = rect_from_points(
832                 rect_position(rects[layer->selection]),
833                 vec(a.x, a.y));
834         } break;
835         }
836
837     } break;
838
839     case SDL_MOUSEBUTTONUP: {
840         layer->state = RECT_LAYER_IDLE;
841         RECT_UNDO_PUSH(
842             undo_history,
843             create_rect_undo_update_context(
844                 layer,
845                 (size_t) layer->selection));
846         dynarray_replace_at(&layer->rects, (size_t) layer->selection, &layer->inter_rect);
847     } break;
848     }
849
850     return 0;
851 }
852
853 static
854 void snap_rect_move_if_enabled(RectLayer *layer, Rect *a,
855                                float snapping_threshold)
856 {
857     trace_assert(a);
858     trace_assert(layer);
859     trace_assert(layer->selection >= 0);
860
861     if (!layer->snapping_enabled) return;
862
863     Rect *rects = (Rect*)layer->rects.data;
864     size_t rects_size = layer->rects.count;
865
866     for (size_t i = 0; i < rects_size; ++i) {
867         if (i == (size_t) layer->selection) continue;
868
869         const Rect b = rects[i];
870
871         if (segment_overlap(vec(a->x, a->x + a->w), vec(b.x,  b.x  + b.w))) {
872             snap_seg2seg(&a->y, b.y, a->h, b.h, snapping_threshold);
873         }
874
875         if (segment_overlap(vec(a->y, a->y + a->h), vec(b.y,  b.y  + b.h))) {
876             snap_seg2seg(&a->x, b.x, a->w, b.w, snapping_threshold);
877         }
878     }
879 }
880
881 static int rect_layer_event_move(RectLayer *layer,
882                                  const SDL_Event *event,
883                                  const Camera *camera,
884                                  UndoHistory *undo_history)
885 {
886     trace_assert(layer);
887     trace_assert(event);
888     trace_assert(camera);
889     trace_assert(layer->selection >= 0);
890
891     Rect *rects = (Rect*)layer->rects.data;
892
893     switch (event->type) {
894     case SDL_MOUSEMOTION: {
895         const Uint8 *state = SDL_GetKeyboardState(NULL);
896         const Vec2f mouse_pos = vec_sub(
897             camera_map_screen(
898                 camera,
899                 event->button.x,
900                 event->button.y),
901             layer->move_anchor);
902
903         if (!(state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL])) {
904             layer->inter_rect.x = mouse_pos.x;
905             layer->inter_rect.y = mouse_pos.y;
906         } else {
907             const Vec2f rect_pos = rect_position(rects[layer->selection]);
908
909             const float dx = fabsf(rect_pos.x - mouse_pos.x);
910             const float dy = fabsf(rect_pos.y - mouse_pos.y);
911
912             if (dx > dy) {
913                 layer->inter_rect.x = mouse_pos.x;
914                 layer->inter_rect.y = rect_pos.y;
915             } else {
916                 layer->inter_rect.x = rect_pos.x;
917                 layer->inter_rect.y = mouse_pos.y;
918             }
919         }
920
921         snap_rect_move_if_enabled(layer, &layer->inter_rect,
922                                   SNAPPING_THRESHOLD / camera->scale);
923     } break;
924
925     case SDL_MOUSEBUTTONUP: {
926         layer->state = RECT_LAYER_IDLE;
927
928         float distance = vec_length(
929             vec_sub(rect_position(layer->inter_rect),
930                     rect_position(rects[layer->selection])));
931
932         if (distance > 1e-6) {
933             RECT_UNDO_PUSH(
934                 undo_history,
935                 create_rect_undo_update_context(
936                     layer, (size_t) layer->selection));
937             dynarray_replace_at(
938                 &layer->rects,
939                 (size_t) layer->selection,
940                 &layer->inter_rect);
941         }
942     } break;
943     }
944     return 0;
945 }
946
947 static int rect_layer_event_id_rename(RectLayer *layer,
948                                       const SDL_Event *event,
949                                       const Camera *camera,
950                                       UndoHistory *undo_history)
951 {
952     trace_assert(layer);
953     trace_assert(event);
954     trace_assert(camera);
955     trace_assert(layer->selection >= 0);
956
957     switch (event->type) {
958     case SDL_KEYDOWN: {
959         switch (event->key.keysym.sym) {
960         case SDLK_RETURN: {
961             RECT_UNDO_PUSH(
962                 undo_history,
963                 create_rect_undo_update_context(
964                     layer,
965                     (size_t) layer->selection));
966
967             char *id = dynarray_pointer_at(&layer->ids, (size_t)layer->selection);
968             memset(id, 0, ENTITY_MAX_ID_SIZE);
969             memcpy(id, edit_field_as_text(&layer->id_edit_field), ENTITY_MAX_ID_SIZE - 1);
970             layer->state = RECT_LAYER_IDLE;
971             SDL_StopTextInput();
972         } break;
973
974         case SDLK_ESCAPE: {
975             layer->state = RECT_LAYER_IDLE;
976             SDL_StopTextInput();
977         } break;
978         }
979     } break;
980     }
981
982     return edit_field_event(&layer->id_edit_field, event);
983 }
984
985 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
986 {
987     LayerPtr layer = {
988         .type = LAYER_RECT,
989         .ptr = rect_layer
990     };
991     return layer;
992 }
993
994 RectLayer *create_rect_layer(Memory *memory,
995                              const char *id_name_prefix,
996                              Cursor *cursor)
997 {
998     trace_assert(memory);
999     trace_assert(id_name_prefix);
1000     trace_assert(cursor);
1001
1002     RectLayer *rect_layer = memory_alloc(memory, sizeof(RectLayer));
1003
1004     rect_layer->ids = create_dynarray(memory, sizeof(char) * ENTITY_MAX_ID_SIZE);
1005     rect_layer->rects = create_dynarray(memory, sizeof(Rect));
1006     rect_layer->colors = create_dynarray(memory, sizeof(Color));
1007     rect_layer->actions = create_dynarray(memory, sizeof(Action));
1008     rect_layer->id_edit_field.font_size = RECT_LAYER_ID_LABEL_SIZE;
1009     rect_layer->id_edit_field.font_color = COLOR_BLACK;
1010     rect_layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
1011     rect_layer->selection = -1;
1012     rect_layer->id_name_prefix = id_name_prefix;
1013     rect_layer->cursor = cursor;
1014
1015     return rect_layer;
1016 }
1017
1018 void rect_layer_load(RectLayer *layer, Memory *memory, String *input)
1019 {
1020     trace_assert(layer);
1021     trace_assert(memory);
1022     trace_assert(input);
1023
1024     int n = atoi(string_to_cstr(memory, trim(chop_by_delim(input, '\n'))));
1025     char id[ENTITY_MAX_ID_SIZE];
1026     for (int i = 0; i < n; ++i) {
1027         Rect rect;
1028         String line = trim(chop_by_delim(input, '\n'));
1029         String string_id = trim(chop_word(&line));
1030         rect.x = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1031         rect.y = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1032         rect.w = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1033         rect.h = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
1034         Color color = hexs(trim(chop_word(&line)));
1035
1036         memset(id, 0, ENTITY_MAX_ID_SIZE);
1037         memcpy(
1038             id,
1039             string_id.data,
1040             min_size_t(ENTITY_MAX_ID_SIZE - 1, string_id.count));
1041
1042         dynarray_push(&layer->rects, &rect);
1043         dynarray_push(&layer->colors, &color);
1044         dynarray_push(&layer->ids, id);
1045
1046         Action action = {
1047             .type = ACTION_NONE,
1048             .entity_id = {0}
1049         };
1050
1051         String action_string = trim(chop_word(&line));
1052         if (action_string.count > 0) {
1053             action.type = (ActionType)atol(string_to_cstr(memory, action_string));
1054             switch (action.type) {
1055             case ACTION_NONE: break;
1056             case ACTION_TOGGLE_GOAL:
1057             case ACTION_HIDE_LABEL: {
1058                 String label_id = trim(chop_word(&line));
1059                 trace_assert(label_id.count > 0);
1060                 memset(action.entity_id, 0, ENTITY_MAX_ID_SIZE);
1061                 memcpy(action.entity_id,
1062                        label_id.data,
1063                        min_size_t(
1064                            ENTITY_MAX_ID_SIZE - 1,
1065                            label_id.count));
1066             } break;
1067
1068             case ACTION_N: break;
1069             }
1070         }
1071
1072         dynarray_push(&layer->actions, &action);
1073     }
1074 }
1075
1076 int rect_layer_render(const RectLayer *layer, const Camera *camera, int active)
1077 {
1078     trace_assert(layer);
1079     trace_assert(camera);
1080
1081     const size_t n = layer->rects.count;
1082     Rect *rects = (Rect *)layer->rects.data;
1083     Color *colors = (Color *)layer->colors.data;
1084     const char *ids = (const char *)layer->ids.data;
1085
1086     // The Rectangles
1087     for (size_t i = 0; i < n; ++i) {
1088         Rect rect = rects[i];
1089         Color color = colors[i];
1090
1091         if (layer->selection == (int) i) {
1092             if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
1093                 rect = layer->inter_rect;
1094             }
1095
1096             if (layer->state == RECT_LAYER_RECOLOR) {
1097                 color = layer->inter_color;
1098             }
1099         }
1100
1101         // Main Rectangle
1102         if (camera_fill_rect(
1103                 camera,
1104                 rect,
1105                 color_scale(
1106                     color,
1107                     rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
1108             return -1;
1109         }
1110     }
1111
1112     // Selection Overlay
1113     if (active && layer->selection >= 0) {
1114         Rect rect = rects[layer->selection];
1115         Color color = colors[layer->selection];
1116
1117         if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
1118             rect = layer->inter_rect;
1119         }
1120
1121         if (layer->state == RECT_LAYER_RECOLOR) {
1122             color = layer->inter_color;
1123         }
1124
1125         const Rect overlay_rect =
1126             rect_pad(
1127                 camera_rect(camera, rect),
1128                 -RECT_LAYER_SELECTION_THICCNESS * 0.5f);
1129         const Color overlay_color = color_invert(color);
1130
1131         // Selection
1132         if (camera_draw_thicc_rect_screen(
1133                 camera,
1134                 overlay_rect,
1135                 overlay_color,
1136                 RECT_LAYER_SELECTION_THICCNESS) < 0) {
1137             return -1;
1138         }
1139
1140         const Vec2f rect_id_pos = vec_sub(
1141             rect_position(rect),
1142             vec_mult(
1143                 RECT_LAYER_ID_LABEL_SIZE,
1144                 vec(0.0f, FONT_CHAR_HEIGHT)));
1145
1146         // Rectangle Id
1147         if (layer->state == RECT_LAYER_ID_RENAME) {
1148             // ID renaming Edit Field
1149             if (edit_field_render_world(
1150                     &layer->id_edit_field,
1151                     camera,
1152                     rect_id_pos) < 0) {
1153                 return -1;
1154             }
1155         } else {
1156             // Id text
1157             if (camera_render_text(
1158                     camera,
1159                     ids + layer->selection * ENTITY_MAX_ID_SIZE,
1160                     RECT_LAYER_ID_LABEL_SIZE,
1161                     color_invert(color),
1162                     rect_id_pos) < 0) {
1163                 return -1;
1164             }
1165         }
1166     }
1167
1168     // Proto Rectangle
1169     const Color color = color_picker_rgba(&layer->color_picker);
1170     if (layer->state == RECT_LAYER_CREATE) {
1171         if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
1172             return -1;
1173         }
1174     }
1175
1176     if (layer->state == RECT_LAYER_SUBTRACT) {
1177         if (camera_draw_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
1178             return -1;
1179         }
1180     }
1181
1182     if (active && color_picker_render(&layer->color_picker, camera) < 0) {
1183         return -1;
1184     }
1185
1186     // Tool bar
1187     if (active) {
1188         // TODO(#1251): subtract and snapping tools don't have any icons
1189         camera_fill_rect_screen(
1190             camera,
1191             subtract_tool_button_rect(camera),
1192             layer->subtract_enabled ? COLOR_RED : rgba(0.2f, 0.2f, 0.2f, 1.0f));
1193         camera_fill_rect_screen(
1194             camera,
1195             snapping_tool_button_rect(camera),
1196             layer->snapping_enabled ? COLOR_RED : rgba(0.2f, 0.2f, 0.2f, 1.0f));
1197     }
1198
1199     return 0;
1200 }
1201
1202 static
1203 int rect_layer_event_recolor(RectLayer *layer,
1204                              const SDL_Event *event,
1205                              const Camera *camera,
1206                              UndoHistory *undo_history)
1207 {
1208     trace_assert(layer);
1209     trace_assert(event);
1210     trace_assert(camera);
1211     trace_assert(undo_history);
1212     trace_assert(layer->selection >= 0);
1213
1214     int color_changed = 0;
1215     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
1216         return -1;
1217     }
1218
1219     if (color_changed) {
1220         layer->inter_color = color_picker_rgba(&layer->color_picker);
1221
1222         if (!color_picker_drag(&layer->color_picker)) {
1223             RECT_UNDO_PUSH(
1224                 undo_history,
1225                 create_rect_undo_update_context(
1226                     layer,
1227                     (size_t)layer->selection));
1228             dynarray_replace_at(&layer->colors, (size_t) layer->selection, &layer->inter_color);
1229             layer->state = RECT_LAYER_IDLE;
1230         }
1231     }
1232
1233     return 0;
1234 }
1235
1236 int rect_layer_event(RectLayer *layer,
1237                      const SDL_Event *event,
1238                      const Camera *camera,
1239                      UndoHistory *undo_history)
1240 {
1241     trace_assert(layer);
1242     trace_assert(event);
1243     trace_assert(undo_history);
1244
1245     switch (layer->state) {
1246     case RECT_LAYER_IDLE:
1247         return rect_layer_event_idle(layer, event, camera, undo_history);
1248
1249     case RECT_LAYER_CREATE:
1250         return rect_layer_event_create(layer, event, camera, undo_history);
1251
1252     case RECT_LAYER_RESIZE:
1253         return rect_layer_event_resize(layer, event, camera, undo_history);
1254
1255     case RECT_LAYER_MOVE:
1256         return rect_layer_event_move(layer, event, camera, undo_history);
1257
1258     case RECT_LAYER_ID_RENAME:
1259         return rect_layer_event_id_rename(layer, event, camera, undo_history);
1260
1261     case RECT_LAYER_RECOLOR:
1262         return rect_layer_event_recolor(layer, event, camera, undo_history);
1263
1264     case RECT_LAYER_SUBTRACT:
1265         return rect_layer_event_subtract(layer, event, camera, undo_history);
1266     }
1267
1268
1269     return 0;
1270 }
1271
1272 size_t rect_layer_count(const RectLayer *layer)
1273 {
1274     return layer->rects.count;
1275 }
1276
1277 const Rect *rect_layer_rects(const RectLayer *layer)
1278 {
1279     return (const Rect *)layer->rects.data;
1280 }
1281
1282 const Color *rect_layer_colors(const RectLayer *layer)
1283 {
1284     return (const Color *)layer->colors.data;
1285 }
1286
1287 const char *rect_layer_ids(const RectLayer *layer)
1288 {
1289     return (const char *)layer->ids.data;
1290 }
1291
1292 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
1293 {
1294     trace_assert(layer);
1295     trace_assert(filedump);
1296
1297     size_t n = layer->ids.count;
1298     char *ids = (char *)layer->ids.data;
1299     Rect *rects = (Rect *)layer->rects.data;
1300     Color *colors = (Color *)layer->colors.data;
1301     Action *actions = (Action *)layer->actions.data;
1302
1303     fprintf(filedump, "%zd\n", n);
1304     for (size_t i = 0; i < n; ++i) {
1305         fprintf(filedump, "%s %f %f %f %f ",
1306                 ids + ENTITY_MAX_ID_SIZE * i,
1307                 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
1308         color_hex_to_stream(colors[i], filedump);
1309
1310         switch (actions[i].type) {
1311         case ACTION_NONE: {} break;
1312
1313         case ACTION_TOGGLE_GOAL:
1314         case ACTION_HIDE_LABEL: {
1315             fprintf(filedump, " %d %.*s",
1316                     (int)actions[i].type,
1317                     ENTITY_MAX_ID_SIZE, actions[i].entity_id);
1318         } break;
1319         case ACTION_N: break;
1320         }
1321
1322         fprintf(filedump, "\n");
1323     }
1324
1325     return 0;
1326 }
1327
1328 const Action *rect_layer_actions(const RectLayer *layer)
1329 {
1330     return (const Action *)layer->actions.data;
1331 }