]> git.lizzy.rs Git - nothing.git/blobdiff - src/game/level/level_editor/rect_layer.c
(#164) Make layer translation units more unity build friendly
[nothing.git] / src / game / level / level_editor / rect_layer.c
index 3700ad55a79cc3bfabfbb6fb645723de1c75e232..757db4d44f97622ff4434237e76e2cd365abe14c 100644 (file)
@@ -25,9 +25,9 @@
 #define RECT_LAYER_GRID_ROWS 3
 #define RECT_LAYER_GRID_COLUMNS 4
 
-static int clipboard = 0;
-static Rect clipboard_rect;
-static Color clipboard_color;
+static int rect_clipboard = 0;
+static Rect rect_clipboard_rect;
+static Color rect_clipboard_color;
 
 static Cursor_Style resize_styles[1 << RECT_SIDE_N] = {
     0,                         // [0]
@@ -77,24 +77,19 @@ struct RectLayer {
     Grid *grid;
     Cursor *cursor;
 
-    // this is the initial size of the selected rectangle during a resize.
-    // we update this whenever the rectangle is resized, so we know the ratio
-    // to fix it to.
-    Vec2f initial_rectangle_size;
-
     int snapping_enabled;
 };
 
 typedef enum {
-    UNDO_ADD,
-    UNDO_DELETE,
-    UNDO_UPDATE,
-    UNDO_SWAP
-} UndoType;
+    RECT_UNDO_ADD,
+    RECT_UNDO_DELETE,
+    RECT_UNDO_UPDATE,
+    RECT_UNDO_SWAP
+} RectUndoType;
 
 // Delete, Update
 typedef struct {
-    UndoType type;
+    RectUndoType type;
     RectLayer *layer;
     size_t index;
     Rect rect;
@@ -105,47 +100,47 @@ typedef struct {
 
 // Add
 typedef struct {
-    UndoType type;
+    RectUndoType type;
     RectLayer *layer;
     size_t index;
 } UndoAddContext;
 
 // Swap
 typedef struct {
-    UndoType type;
+    RectUndoType type;
     RectLayer *layer;
     size_t index1;
     size_t index2;
 } UndoSwapContext;
 
 typedef union {
-    UndoType type;
+    RectUndoType type;
     UndoAddContext add;
     UndoElementContext element;
     UndoSwapContext swap;
-} UndoContext;
+} RectUndoContext;
 
 static
-UndoContext create_undo_add_context(RectLayer *layer, size_t index)
+RectUndoContext create_rect_undo_add_context(RectLayer *layer, size_t index)
 {
     trace_assert(layer);
     trace_assert(index < dynarray_count(layer->rects));
 
-    UndoContext undo_context;
-    undo_context.add.type = UNDO_ADD;
+    RectUndoContext undo_context;
+    undo_context.add.type = RECT_UNDO_ADD;
     undo_context.add.layer = layer;
     undo_context.add.index = index;
     return undo_context;
 }
 
 static
-UndoContext create_undo_element_context(RectLayer *layer)
+RectUndoContext create_rect_undo_element_context(RectLayer *layer)
 {
     trace_assert(layer);
     size_t index = (size_t) layer->selection;
     trace_assert(index < dynarray_count(layer->rects));
 
-    UndoContext undo_context;
+    RectUndoContext undo_context;
     undo_context.element.layer = layer;
     undo_context.element.index = index;
     dynarray_copy_to(layer->rects, &undo_context.element.rect, index);
@@ -156,26 +151,26 @@ UndoContext create_undo_element_context(RectLayer *layer)
 }
 
 static
-UndoContext create_undo_update_context(RectLayer *rect_layer)
+RectUndoContext create_rect_undo_update_context(RectLayer *rect_layer)
 {
-    UndoContext undo_context = create_undo_element_context(rect_layer);
-    undo_context.type = UNDO_UPDATE;
+    RectUndoContext undo_context = create_rect_undo_element_context(rect_layer);
+    undo_context.type = RECT_UNDO_UPDATE;
     return undo_context;
 }
 
 static
-UndoContext create_undo_delete_context(RectLayer *rect_layer)
+RectUndoContext create_rect_undo_delete_context(RectLayer *rect_layer)
 {
-    UndoContext undo_context = create_undo_element_context(rect_layer);
-    undo_context.type = UNDO_DELETE;
+    RectUndoContext undo_context = create_rect_undo_element_context(rect_layer);
+    undo_context.type = RECT_UNDO_DELETE;
     return undo_context;
 }
 
 static
-UndoContext create_undo_swap_context(RectLayer *rect_layer, size_t index1, size_t index2)
+RectUndoContext create_rect_undo_swap_context(RectLayer *rect_layer, size_t index1, size_t index2)
 {
-    UndoContext undo_context;
-    undo_context.swap.type = UNDO_SWAP;
+    RectUndoContext undo_context;
+    undo_context.swap.type = RECT_UNDO_SWAP;
     undo_context.swap.layer = rect_layer;
     undo_context.swap.index1 = index1;
     undo_context.swap.index2 = index2;
@@ -186,12 +181,12 @@ static
 void rect_layer_undo(void *context, size_t context_size)
 {
     trace_assert(context);
-    trace_assert(sizeof(UndoContext) == context_size);
+    trace_assert(sizeof(RectUndoContext) == context_size);
 
-    UndoContext *undo_context = context;
+    RectUndoContext *undo_context = context;
 
     switch (undo_context->type) {
-    case UNDO_ADD: {
+    case RECT_UNDO_ADD: {
         RectLayer *layer = undo_context->add.layer;
         dynarray_delete_at(layer->rects, undo_context->add.index);
         dynarray_delete_at(layer->colors, undo_context->add.index);
@@ -200,7 +195,7 @@ void rect_layer_undo(void *context, size_t context_size)
         layer->selection = -1;
     } break;
 
-    case UNDO_DELETE: {
+    case RECT_UNDO_DELETE: {
         RectLayer *layer = undo_context->element.layer;
         dynarray_insert_before(layer->rects, undo_context->element.index, &undo_context->element.rect);
         dynarray_insert_before(layer->colors, undo_context->element.index, &undo_context->element.color);
@@ -209,7 +204,7 @@ void rect_layer_undo(void *context, size_t context_size)
         layer->selection = -1;
     } break;
 
-    case UNDO_UPDATE: {
+    case RECT_UNDO_UPDATE: {
         RectLayer *layer = undo_context->element.layer;
         dynarray_replace_at(layer->rects, undo_context->element.index, &undo_context->element.rect);
         dynarray_replace_at(layer->colors, undo_context->element.index, &undo_context->element.color);
@@ -217,7 +212,7 @@ void rect_layer_undo(void *context, size_t context_size)
         dynarray_replace_at(layer->actions, undo_context->element.index, &undo_context->element.action);
     } break;
 
-    case UNDO_SWAP: {
+    case RECT_UNDO_SWAP: {
         RectLayer *layer = undo_context->element.layer;
         dynarray_swap(layer->rects, undo_context->swap.index1, undo_context->swap.index2);
         dynarray_swap(layer->colors, undo_context->swap.index1, undo_context->swap.index2);
@@ -227,9 +222,9 @@ void rect_layer_undo(void *context, size_t context_size)
     }
 }
 
-#define UNDO_PUSH(HISTORY, CONTEXT)                                     \
+#define RECT_UNDO_PUSH(HISTORY, CONTEXT)                                     \
     do {                                                                \
-        UndoContext context = (CONTEXT);                                \
+        RectUndoContext context = (CONTEXT);                                \
         undo_history_push(                                              \
             HISTORY,                                                    \
             rect_layer_undo,                                            \
@@ -262,9 +257,9 @@ static int rect_layer_add_rect(RectLayer *layer,
 
     dynarray_push_empty(layer->actions);
 
-    UNDO_PUSH(
+    RECT_UNDO_PUSH(
         undo_history,
-        create_undo_add_context(
+        create_rect_undo_add_context(
             layer,
             dynarray_count(layer->rects) - 1));
 
@@ -299,7 +294,7 @@ static void rect_layer_swap_elements(RectLayer *layer, size_t a, size_t b,
     dynarray_swap(layer->ids, a, b);
     dynarray_swap(layer->actions, a, b);
 
-    UNDO_PUSH(undo_history, create_undo_swap_context(layer, a, b));
+    RECT_UNDO_PUSH(undo_history, create_rect_undo_swap_context(layer, a, b));
 }
 
 static int rect_layer_delete_rect_at(RectLayer *layer,
@@ -308,7 +303,7 @@ static int rect_layer_delete_rect_at(RectLayer *layer,
 {
     trace_assert(layer);
 
-    UNDO_PUSH(undo_history, create_undo_delete_context(layer));
+    RECT_UNDO_PUSH(undo_history, create_rect_undo_delete_context(layer));
 
     dynarray_delete_at(layer->rects, i);
     dynarray_delete_at(layer->colors, i);
@@ -394,11 +389,6 @@ static int rect_layer_event_idle(RectLayer *layer,
                     layer->create_end = position;
                 }
             }
-
-            if (layer->selection >= 0) {
-                layer->initial_rectangle_size = vec(rects[layer->selection].w,
-                    rects[layer->selection].h);
-            }
         } break;
         }
     } break;
@@ -455,6 +445,11 @@ static int rect_layer_event_idle(RectLayer *layer,
             }
         } break;
 
+        case SDLK_q: {
+            // TODO(#1171): there is no UI indication that we are in the snapping mode
+            layer->snapping_enabled = !layer->snapping_enabled;
+        } break;
+
         case SDLK_F2: {
             if (layer->selection >= 0) {
                 const char *ids = dynarray_data(layer->ids);
@@ -475,14 +470,14 @@ static int rect_layer_event_idle(RectLayer *layer,
 
         case SDLK_c: {
             if ((event->key.keysym.mod & KMOD_LCTRL) && layer->selection >= 0) {
-                clipboard = 1;
-                dynarray_copy_to(layer->rects, &clipboard_rect, (size_t)layer->selection);
-                dynarray_copy_to(layer->colors, &clipboard_color, (size_t)layer->selection);
+                rect_clipboard = 1;
+                dynarray_copy_to(layer->rects, &rect_clipboard_rect, (size_t)layer->selection);
+                dynarray_copy_to(layer->colors, &rect_clipboard_color, (size_t)layer->selection);
             }
         } break;
 
         case SDLK_v: {
-            if ((event->key.keysym.mod & KMOD_LCTRL) && clipboard) {
+            if ((event->key.keysym.mod & KMOD_LCTRL) && rect_clipboard) {
                 int x, y;
                 SDL_GetMouseState(&x, &y);
                 Vec2f position = camera_map_screen(camera, x, y);
@@ -490,8 +485,8 @@ static int rect_layer_event_idle(RectLayer *layer,
                 rect_layer_add_rect(
                     layer,
                     rect(position.x, position.y,
-                         clipboard_rect.w, clipboard_rect.h),
-                    clipboard_color,
+                         rect_clipboard_rect.w, rect_clipboard_rect.h),
+                    rect_clipboard_color,
                     undo_history);
             }
         } break;
@@ -545,47 +540,14 @@ static int rect_layer_event_create(RectLayer *layer,
     return 0;
 }
 
-static
-void fix_rect_ratio(RectLayer *layer,
-                    float *x, float *y, // the things we can change to fix the ratio
-                    Vec2f ref_pt)       // the (fixed) reference point of the rect
-{
-    trace_assert(x);
-    trace_assert(y);
-
-    // if we're not holding down shift, don't bother.
-    if (!(SDL_GetKeyboardState(NULL)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(NULL)[SDL_SCANCODE_RSHIFT]))
-        return;
-
-    float ratio = layer->initial_rectangle_size.x / layer->initial_rectangle_size.y;
-
-    // if we are holding down control also, then make squares.
-    if (SDL_GetKeyboardState(NULL)[SDL_SCANCODE_LCTRL] || SDL_GetKeyboardState(NULL)[SDL_SCANCODE_RCTRL])
-        ratio = 1.0f;
-
-    // make some constants for us to use.
-    float inv_ratio = 1.0f / ratio;
-    float w = *x - ref_pt.x;
-    float h = *y - ref_pt.y;
-
-    float ab_w = fabsf(w);
-    float ab_h = fabsf(h);
-
-    // note: copysign takes (magnitude, sign). this thing basically lengthens the shorter side
-    // to fit the ratio. copysign is used to handle when the length is negative due to the
-    // different corner positions.
-    if (ab_w <= ratio * ab_h) {
-        *x = ref_pt.x + (ratio * copysignf(h, w));
-    } else if (ab_h <= inv_ratio * ab_w) {
-        *y = ref_pt.y + inv_ratio * copysignf(w, h);
-    }
-}
-
 static
 void snap_rect_resize_if_enabled(RectLayer *layer, Rect *a, float snapping_threshold)
 {
     trace_assert(layer);
     trace_assert(layer->selection >= 0);
+    trace_assert(a);
+
+    if (!layer->snapping_enabled) return;
 
     Rect *rects = dynarray_data(layer->rects);
     size_t rects_size = dynarray_count(layer->rects);
@@ -654,36 +616,16 @@ static int rect_layer_event_resize(RectLayer *layer,
         } break;
 
         case 3: {               // TOP,LEFT
-            float x = position.x;
-            float y = position.y;
-            float w = rects[layer->selection].w;
-            float h = rects[layer->selection].h;
-
-            // use the bottom-right as reference.
-            Vec2f ref_pos = rect_position2(rects[layer->selection]);
-            fix_rect_ratio(layer, &x, &y, ref_pos);
-
-            for (size_t i = 0; i < dynarray_count(layer->rects); ++i) {
-                if (i == (size_t) layer->selection) continue;
-
-                const Rect b = rects[i];
-                if (segment_overlap(vec(y, y + h), vec(b.y, b.y + b.h))) {
-                    if (snap_var2seg(&x, b.x, 0, b.w, scaled_snap_threshold)) {
-                        // if we did a snap, we need to update the rect to make sure it
-                        // still fits the ratio. same pattern repeats below.
-                        fix_rect_ratio(layer, &x, &y, ref_pos);
-                    }
-                }
+            Rect a = rect(
+                position.x,
+                position.y,
+                rects[layer->selection].w,
+                rects[layer->selection].h);
 
-                if (segment_overlap(vec(x, x + w), vec(b.x, b.x + b.w))) {
-                    if (snap_var2seg(&y, b.y, 0, b.h, scaled_snap_threshold)) {
-                        fix_rect_ratio(layer, &x, &y, ref_pos);
-                    }
-                }
-            }
+            snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
 
             layer->inter_rect = rect_from_points(
-                vec(x, y),
+                vec(a.x, a.y),
                 rect_position2(rects[layer->selection]));
         } break;
 
@@ -702,36 +644,18 @@ static int rect_layer_event_resize(RectLayer *layer,
         } break;
 
         case 6: {               // BOTTOM,LEFT
-            float x = position.x;
-            float y = position.y;
-            float w = rects[layer->selection].w;
-            float h = rects[layer->selection].h;
-
-            // use the top-right as reference.
-            Vec2f ref_pos = vec(rects[layer->selection].x + rects[layer->selection].w, rects[layer->selection].y);
-            fix_rect_ratio(layer, &x, &y, ref_pos);
-
-            for (size_t i = 0; i < dynarray_count(layer->rects); ++i) {
-                if (i == (size_t) layer->selection) continue;
-
-                const Rect b = rects[i];
-                if (segment_overlap(vec(y, y + h), vec(b.y, b.y + b.h))) {
-                    if (snap_var2seg(&x, b.x, 0, b.w, scaled_snap_threshold)) {
-                        fix_rect_ratio(layer, &x, &y, ref_pos);
-                    }
-                }
+            Rect a = rect(
+                position.x,
+                position.y,
+                rects[layer->selection].w,
+                -rects[layer->selection].h);
 
-                if (segment_overlap(vec(x, x + w), vec(b.x, b.x + b.w))) {
-                    if (snap_var2seg(&y, b.y, 0, b.h, scaled_snap_threshold)) {
-                        fix_rect_ratio(layer, &x, &y, ref_pos);
-                    }
-                }
-            }
+            snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
 
             layer->inter_rect = rect_from_points(
-                vec(x, rects[layer->selection].y),
+                vec(a.x, rects[layer->selection].y),
                 vec(rects[layer->selection].x + rects[layer->selection].w,
-                    y));
+                    a.y));
         } break;
 
         case 8: {               // RIGHT
@@ -748,80 +672,40 @@ static int rect_layer_event_resize(RectLayer *layer,
         } break;
 
         case 9: {               // TOP,RIGHT
-            float x = position.x;
-            float y = position.y;
-            float w = rects[layer->selection].w;
-            float h = rects[layer->selection].h;
-
-            // use bottom-left as reference.
-            Vec2f ref_pos = vec(rects[layer->selection].x, rects[layer->selection].y + rects[layer->selection].h);
-            fix_rect_ratio(layer, &x, &y, ref_pos);
-
-            for (size_t i = 0; i < dynarray_count(layer->rects); ++i) {
-                if (i == (size_t) layer->selection) continue;
-
-                const Rect b = rects[i];
-                if (segment_overlap(vec(y, y + h), vec(b.y, b.y + b.h))) {
-                    if (snap_var2seg(&x, b.x, 0, b.w, scaled_snap_threshold)) {
-                        fix_rect_ratio(layer, &x, &y, ref_pos);
-                    }
-                }
+            Rect a = rect(
+                position.x,
+                position.y,
+                -rects[layer->selection].w,
+                rects[layer->selection].h);
 
-                if (segment_overlap(vec(x, x + w), vec(b.x, b.x + b.w))) {
-                    if (snap_var2seg(&y, b.y, 0, b.h, scaled_snap_threshold)) {
-                        fix_rect_ratio(layer, &x, &y, ref_pos);
-                    }
-                }
-            }
+            snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
 
             layer->inter_rect = rect_from_points(
-                vec(rects[layer->selection].x, y),
-                vec(x,
+                vec(rects[layer->selection].x, a.y),
+                vec(a.x,
                     rects[layer->selection].y + rects[layer->selection].h));
         } break;
 
         case 12: {              // BOTTOM,RIGHT
-            float x = position.x;
-            float y = position.y;
-            float w = rects[layer->selection].w;
-            float h = rects[layer->selection].h;
-
-            // use top-left as reference.
-            Vec2f ref_pos = rect_position(rects[layer->selection]);
-            fix_rect_ratio(layer, &x, &y, ref_pos);
-
-            for (size_t i = 0; i < dynarray_count(layer->rects); ++i) {
-                if (i == (size_t) layer->selection) continue;
-
-                const Rect b = rects[i];
-                if (segment_overlap(vec(y, y + h), vec(b.y, b.y + b.h))) {
-                    if (snap_var2seg(&x, b.x, 0, b.w, scaled_snap_threshold)) {
-                        fix_rect_ratio(layer, &x, &y, ref_pos);
-                    }
-                }
+            Rect a = rect(
+                position.x,
+                position.y,
+                -rects[layer->selection].w,
+                -rects[layer->selection].h);
 
-                if (segment_overlap(vec(x, x + w), vec(b.x, b.x + b.w))) {
-                    if (snap_var2seg(&y, b.y, 0, b.h, scaled_snap_threshold)) {
-                        fix_rect_ratio(layer, &x, &y, ref_pos);
-                    }
-                }
-            }
+            snap_rect_resize_if_enabled(layer, &a, scaled_snap_threshold);
 
             layer->inter_rect = rect_from_points(
                 rect_position(rects[layer->selection]),
-                vec(x, y));
+                vec(a.x, a.y));
         } break;
         }
 
-        // note that we need to update the "initial size" even during the drag. this is because
-        // we can enter/exit the ratio mode in the middle of dragging!
-        layer->initial_rectangle_size = vec(layer->inter_rect.w, layer->inter_rect.h);
-
     } break;
 
     case SDL_MOUSEBUTTONUP: {
         layer->state = RECT_LAYER_IDLE;
-        UNDO_PUSH(undo_history, create_undo_update_context(layer));
+        RECT_UNDO_PUSH(undo_history, create_rect_undo_update_context(layer));
         dynarray_replace_at(layer->rects, (size_t) layer->selection, &layer->inter_rect);
     } break;
     }
@@ -909,7 +793,7 @@ static int rect_layer_event_move(RectLayer *layer,
                     rect_position(rects[layer->selection])));
 
         if (distance > 1e-6) {
-            UNDO_PUSH(undo_history, create_undo_update_context(layer));
+            RECT_UNDO_PUSH(undo_history, create_rect_undo_update_context(layer));
             dynarray_replace_at(layer->rects, (size_t) layer->selection, &layer->inter_rect);
         }
     } break;
@@ -931,7 +815,7 @@ static int rect_layer_event_id_rename(RectLayer *layer,
     case SDL_KEYDOWN: {
         switch (event->key.keysym.sym) {
         case SDLK_RETURN: {
-            UNDO_PUSH(undo_history, create_undo_update_context(layer));
+            RECT_UNDO_PUSH(undo_history, create_rect_undo_update_context(layer));
 
             char *id = dynarray_pointer_at(layer->ids, (size_t)layer->selection);
             memset(id, 0, ENTITY_MAX_ID_SIZE);
@@ -1246,7 +1130,7 @@ int rect_layer_event_recolor(RectLayer *layer,
         layer->inter_color = color_picker_rgba(&layer->color_picker);
 
         if (!color_picker_drag(&layer->color_picker)) {
-            UNDO_PUSH(undo_history, create_undo_update_context(layer));
+            RECT_UNDO_PUSH(undo_history, create_rect_undo_update_context(layer));
             dynarray_replace_at(layer->colors, (size_t) layer->selection, &layer->inter_color);
             layer->state = RECT_LAYER_IDLE;
         }