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