+#define GEOMETRY_CAPACITY 256
+
+typedef struct {
+ size_t first;
+ size_t count;
+ Rect rects[GEOMETRY_CAPACITY];
+ Color colors[GEOMETRY_CAPACITY];
+} Geometry;
+
+static
+void push_geometry(Geometry *geometry, Rect rect, Color color)
+{
+ assert(geometry);
+ assert(geometry->count < GEOMETRY_CAPACITY);
+
+ if ((rect.w * rect.h) > 1e-6f) {
+ size_t i = (geometry->first + geometry->count) % GEOMETRY_CAPACITY;
+ geometry->rects[i] = rect;
+ geometry->colors[i] = color;
+ geometry->count++;
+ }
+}
+
+static
+void subtract_rect_from_rect(Rect a, Color color_a, Rect c, Geometry *result)
+{
+ assert(result);
+
+ Rect b = rects_overlap_area(a, c);
+
+ if (b.w * b.h < 1e-6) {
+ push_geometry(result, a, color_a);
+ return;
+ }
+
+ push_geometry(result, (Rect) {a.x, a.y, a.w, b.y - a.y}, color_a);
+ push_geometry(result, (Rect) {a.x, b.y, b.x - a.x, b.h}, color_a);
+ push_geometry(result, (Rect) {
+ b.x + b.w,
+ b.y,
+ a.w - (b.x - a.x) - b.w,
+ b.h
+ }, color_a);
+ push_geometry(result, (Rect) {
+ a.x,
+ b.y + b.h,
+ a.w,
+ a.h - (b.y - a.y) - b.h
+ }, color_a);
+}
+
+static
+void subtract_rect_from_geometry(Geometry *result, Rect b)
+{
+ assert(result);
+
+ size_t count = result->count;
+ size_t first = result->first;
+
+ for (size_t i = 0; i < count; ++i) {
+ result->first = (result->first + 1) % GEOMETRY_CAPACITY;
+ result->count -= 1;
+ subtract_rect_from_rect(
+ result->rects[(i + first) % GEOMETRY_CAPACITY],
+ result->colors[(i + first) % GEOMETRY_CAPACITY],
+ b,
+ result);
+ }
+}
+
+static int rect_layer_event_subtract(RectLayer *layer,
+ const SDL_Event *event,
+ const Camera *camera,
+ UndoHistory *undo_history)
+{
+ trace_assert(layer);
+ trace_assert(event);
+ trace_assert(camera);
+ trace_assert(undo_history);
+
+ Rect *rects = layer->rects.data;
+ Color *colors = layer->colors.data;
+
+ switch (event->type) {
+ case SDL_MOUSEBUTTONUP: {
+ switch (event->button.button) {
+ case SDL_BUTTON_LEFT: {
+ const Rect real_rect =
+ rect_from_points(
+ layer->create_begin,
+ layer->create_end);
+ const float area = real_rect.w * real_rect.h;
+
+ Geometry geometry = {0};
+
+ if (area >= CREATE_AREA_THRESHOLD) {
+ for (size_t i = 0; i < layer->rects.count;) {
+ Rect overlap_area = rects_overlap_area(
+ real_rect,
+ rects[i]);
+ if (overlap_area.w * overlap_area.h > 1e-6) {
+ push_geometry(&geometry, rects[i], colors[i]);
+ rect_layer_delete_rect_at_index(layer, i, undo_history);
+ } else {
+ i++;
+ }
+ }
+
+ subtract_rect_from_geometry(&geometry, real_rect);
+
+ for (size_t i = 0; i < geometry.count; ++i) {
+ size_t j = (i + geometry.first) % GEOMETRY_CAPACITY;
+ rect_layer_add_rect(
+ layer,
+ geometry.rects[j],
+ geometry.colors[j],
+ undo_history);
+ }
+ } else {
+ log_info("The area is too small %f. Such small box won't be cut.\n", area);
+ }
+ layer->state = RECT_LAYER_IDLE;
+ } break;
+ }
+ } break;
+
+ case SDL_MOUSEMOTION: {
+ layer->create_end = camera_map_screen(
+ camera,
+ event->motion.x,
+ event->motion.y);
+ } break;
+ }
+
+ return 0;
+}
+