From 6f2ab0105d9ed19f095a061dbe623e1139be81c3 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Tue, 17 Dec 2024 00:57:21 +0300 Subject: [PATCH] Shrinking is broken --- godot/astream/building_layout_data.conf | 104 ++-- src/flecs | 2 +- src/godot | 2 +- src/meshoptimizer | 2 +- .../stream/ui/building_layout_graph_ui.cpp | 6 + src/modules/stream/ui/graph_module.cpp | 4 +- src/modules/stream/ui/grow_job.cpp | 24 +- src/modules/stream/ui/growth_module.cpp | 2 + src/modules/stream/ui/region_tree.cpp | 523 +++++++++++++++++- src/modules/stream/ui/region_tree.h | 30 + src/modules/stream/world_editor.h | 1 + 11 files changed, 606 insertions(+), 94 deletions(-) diff --git a/godot/astream/building_layout_data.conf b/godot/astream/building_layout_data.conf index 93a686d..8b660b8 100644 --- a/godot/astream/building_layout_data.conf +++ b/godot/astream/building_layout_data.conf @@ -140,7 +140,7 @@ entries=[ { "type": "zone", "zone_type": 0 }, { -"children": [ 54, 55, 56, 57, 58 ], +"children": [ 54, 55, 56, 57 ], "commands": [ ], "index": 18, "name": "zone_3", @@ -148,7 +148,7 @@ entries=[ { "type": "zone", "zone_type": 1 }, { -"children": [ 59, 60 ], +"children": [ 58, 59 ], "commands": [ ], "index": 19, "name": "zone_0", @@ -156,7 +156,7 @@ entries=[ { "type": "zone", "zone_type": 0 }, { -"children": [ 61, 62 ], +"children": [ 60, 61 ], "commands": [ ], "index": 20, "name": "zone_1", @@ -304,7 +304,7 @@ entries=[ { "type": "room", "window": true }, { -"children": [ 63, 64, 65 ], +"children": [ 62, 63, 64 ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "index": 35, "name": "zone_0", @@ -312,7 +312,7 @@ entries=[ { "type": "zone", "zone_type": 0 }, { -"children": [ 66, 67 ], +"children": [ 65, 66 ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "index": 36, "name": "zone_1", @@ -330,7 +330,7 @@ entries=[ { "type": "room", "window": true }, { -"children": [ 68 ], +"children": [ 67 ], "commands": [ [ 5, [ ] ] ], "index": 38, "name": "stair_0", @@ -340,7 +340,7 @@ entries=[ { "type": "room", "window": true }, { -"children": [ 69, 70, 71 ], +"children": [ 68, 69, 70 ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "index": 39, "name": "zone_0", @@ -348,7 +348,7 @@ entries=[ { "type": "zone", "zone_type": 0 }, { -"children": [ 72, 73 ], +"children": [ 71, 72 ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "index": 40, "name": "zone_1", @@ -356,7 +356,7 @@ entries=[ { "type": "zone", "zone_type": 1 }, { -"children": [ 74 ], +"children": [ 73 ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "index": 41, "name": "zone_0", @@ -364,7 +364,7 @@ entries=[ { "type": "zone", "zone_type": 0 }, { -"children": [ 75, 76 ], +"children": [ 74, 75 ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "index": 42, "name": "zone_1", @@ -372,7 +372,7 @@ entries=[ { "type": "zone", "zone_type": 1 }, { -"children": [ 77 ], +"children": [ 76 ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "index": 43, "name": "zone_0", @@ -380,7 +380,7 @@ entries=[ { "type": "zone", "zone_type": 0 }, { -"children": [ 78 ], +"children": [ 77 ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "index": 44, "name": "zone_1", @@ -388,7 +388,7 @@ entries=[ { "type": "zone", "zone_type": 1 }, { -"children": [ 79 ], +"children": [ 78 ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "index": 45, "name": "zone_0", @@ -396,7 +396,7 @@ entries=[ { "type": "zone", "zone_type": 0 }, { -"children": [ 80 ], +"children": [ 79 ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "index": 46, "name": "zone_1", @@ -517,16 +517,6 @@ entries=[ { "children": [ ], "commands": [ ], "index": 58, -"name": "enterance_1", -"order": 5, -"room_area": 16.0, -"room_type": 304, -"type": "room", -"window": true -}, { -"children": [ ], -"commands": [ ], -"index": 59, "name": "wc_0", "order": 1, "room_area": 0.0, @@ -536,7 +526,7 @@ entries=[ { }, { "children": [ ], "commands": [ ], -"index": 60, +"index": 59, "name": "bathroom_0", "order": 2, "room_area": 64.0, @@ -546,7 +536,7 @@ entries=[ { }, { "children": [ ], "commands": [ ], -"index": 61, +"index": 60, "name": "studio_0", "order": 1, "room_area": 144.0, @@ -556,7 +546,7 @@ entries=[ { }, { "children": [ ], "commands": [ ], -"index": 62, +"index": 61, "name": "enterance_0", "order": 2, "room_area": 0.0, @@ -566,7 +556,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 63, +"index": 62, "name": "bathroom_0", "order": 0, "room_area": 16.0, @@ -576,7 +566,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 64, +"index": 63, "name": "wc_0", "order": 1, "room_area": 16.0, @@ -586,7 +576,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 65, +"index": 64, "name": "bedroom_0", "order": 2, "room_area": 36.0, @@ -596,7 +586,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 66, +"index": 65, "name": "living_room_0", "order": 0, "room_area": 36.0, @@ -606,7 +596,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 67, +"index": 66, "name": "kitchen_0", "order": 1, "room_area": 16.0, @@ -614,17 +604,17 @@ entries=[ { "type": "room", "window": true }, { -"children": [ 81, 82 ], +"children": [ 80, 81 ], "commands": [ ], "floor_index": 1, -"index": 68, +"index": 67, "name": "floor_0", "order": 0, "type": "floor" }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 69, +"index": 68, "name": "wc_0", "order": 0, "room_area": 16.0, @@ -634,7 +624,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 70, +"index": 69, "name": "bathroom_0", "order": 1, "room_area": 16.0, @@ -644,7 +634,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 71, +"index": 70, "name": "bedroom_0", "order": 2, "room_area": 64.0, @@ -654,7 +644,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 72, +"index": 71, "name": "kitchen_0", "order": 0, "room_area": 16.0, @@ -664,7 +654,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 73, +"index": 72, "name": "living_room_0", "order": 1, "room_area": 144.0, @@ -674,7 +664,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 74, +"index": 73, "name": "bathroom_0", "order": 0, "room_area": 16.0, @@ -684,7 +674,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 75, +"index": 74, "name": "kitchen_0", "order": 0, "room_area": 64.0, @@ -694,7 +684,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 76, +"index": 75, "name": "living_room_0", "order": 1, "room_area": 64.0, @@ -704,7 +694,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 77, +"index": 76, "name": "wc_0", "order": 0, "room_area": 16.0, @@ -714,7 +704,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 78, +"index": 77, "name": "living_room_0", "order": 0, "room_area": 64.0, @@ -724,7 +714,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 79, +"index": 78, "name": "bathroom_0", "order": 0, "room_area": 16.0, @@ -734,7 +724,7 @@ entries=[ { }, { "children": [ ], "commands": [ [ 5, [ ] ] ], -"index": 80, +"index": 79, "name": "living_room_0", "order": 0, "room_area": 64.0, @@ -742,24 +732,24 @@ entries=[ { "type": "room", "window": true }, { -"children": [ 83 ], +"children": [ 82 ], "commands": [ ], -"index": 81, +"index": 80, "name": "zone_0", "order": 0, "type": "zone", "zone_type": 1 }, { -"children": [ 84, 85 ], +"children": [ 83, 84 ], "commands": [ ], -"index": 82, +"index": 81, "name": "unit_0", "order": 0, "type": "unit" }, { "children": [ ], "commands": [ ], -"index": 83, +"index": 82, "name": "storage_room_0", "order": 0, "room_area": 64.0, @@ -767,17 +757,17 @@ entries=[ { "type": "room", "window": true }, { -"children": [ 86 ], +"children": [ 85 ], "commands": [ ], -"index": 84, +"index": 83, "name": "zone_0", "order": 0, "type": "zone", "zone_type": 0 }, { -"children": [ 87 ], +"children": [ 86 ], "commands": [ ], -"index": 85, +"index": 84, "name": "zone_1", "order": 0, "type": "zone", @@ -785,7 +775,7 @@ entries=[ { }, { "children": [ ], "commands": [ ], -"index": 86, +"index": 85, "name": "wc_0", "order": 0, "room_area": 16.0, @@ -795,7 +785,7 @@ entries=[ { }, { "children": [ ], "commands": [ ], -"index": 87, +"index": 86, "name": "living_room_0", "order": 0, "room_area": 16.0, diff --git a/src/flecs b/src/flecs index 57ebed1..0c70671 160000 --- a/src/flecs +++ b/src/flecs @@ -1 +1 @@ -Subproject commit 57ebed1083274ee4875631a940452f08ff08aef9 +Subproject commit 0c706715155a888f734b1b6503b5ed0358cec302 diff --git a/src/godot b/src/godot index 7fbb30e..cd92ad0 160000 --- a/src/godot +++ b/src/godot @@ -1 +1 @@ -Subproject commit 7fbb30e55ba8998a748954c297b0f98697f97b6f +Subproject commit cd92ad0f69a842d94dc2d56f83cbd8f724ed2959 diff --git a/src/meshoptimizer b/src/meshoptimizer index 20787cc..20b26f9 160000 --- a/src/meshoptimizer +++ b/src/meshoptimizer @@ -1 +1 @@ -Subproject commit 20787cc054fa0e46584c2791139c1878aa899d78 +Subproject commit 20b26f98746a439600b20065a69ab0c66c4cca5c diff --git a/src/modules/stream/ui/building_layout_graph_ui.cpp b/src/modules/stream/ui/building_layout_graph_ui.cpp index ea53c7d..04dc9c9 100644 --- a/src/modules/stream/ui/building_layout_graph_ui.cpp +++ b/src/modules/stream/ui/building_layout_graph_ui.cpp @@ -1007,6 +1007,12 @@ void BuildingLayoutGraphUI::draw_2d_grid_view(Control *draw) true); mcount++; }); + if (fc.has()) + draw->draw_circle( + Vector2(dx + 0.5f * dsize, + dy + 0.5f * dsize), + dsize * 0.12f, + Color(0.3f, 0.3f, 1.0f, 1.0f)); print_line( "draw cell: (" + itos(x) + ", " + itos(y) + ") (" + String::num(dx) + diff --git a/src/modules/stream/ui/graph_module.cpp b/src/modules/stream/ui/graph_module.cpp index 72ab81a..e24dbd2 100644 --- a/src/modules/stream/ui/graph_module.cpp +++ b/src/modules/stream/ui/graph_module.cpp @@ -404,8 +404,8 @@ void graph_module::zones_graph_module(flecs::world &ecs, else xr = xr.grow(1); int xarea = xr.size.x * xr.size.y * 16; - sum += MAX(xarea, MIN_ROOM_SIZE) * 10 / - 8; + sum += MAX(xarea, MIN_ROOM_SIZE) * 35 / + 80; assert(sum >= 0.0f); count_rooms++; } diff --git a/src/modules/stream/ui/grow_job.cpp b/src/modules/stream/ui/grow_job.cpp index 9807b5e..b94194b 100644 --- a/src/modules/stream/ui/grow_job.cpp +++ b/src/modules/stream/ui/grow_job.cpp @@ -475,9 +475,19 @@ void grow_job_queue::iterate() assert(this); flecs::query q = grid_e.world().query_builder().build(); +#if 0 + flecs::query qm = + grid_e.world().query_builder().build(); +#endif q.each([this](flecs::entity e, growth_regions &g) { flecs::log::warn("pre floor: %s", e.path().c_str()); }); +#if 0 + qm.each([this](flecs::entity em, region_tree &rt) { + rt.dump(em); + assert(rt.check(em)); + }); +#endif q.each([this](flecs::entity e, growth_regions &g) { flecs::log::warn("floor: %s", e.path().c_str()); flecs::log::warn("job count: %d", g.job_list.size()); @@ -522,21 +532,29 @@ void grow_job_queue::iterate() assert(false); break; } + { + const region_tree *rtree = e.get(); + assert(rtree); + assert(rtree->check(grid_floor_e)); + } g.job_list.pop_front(); // if (common_count > 0) // break; } + flecs::log::dbg( + "processed jobs (created region initial positions): %d", + g.job_list.size()); g.job_list.clear(); flecs::query qm = grid_e.world().query_builder().build(); qm.each([this](flecs::entity em, region_tree &rt) { assert(rt.check(em)); }); + qm.each([this](flecs::entity em, region_tree &rt) { + rt.shrink_rooms(em); + }); qm.each([this](flecs::entity em, region_tree &rt) { rt.place(em); }); - flecs::log::dbg( - "processed jobs (created region initial positions): %d", - g.job_list.size()); }); } \ No newline at end of file diff --git a/src/modules/stream/ui/growth_module.cpp b/src/modules/stream/ui/growth_module.cpp index d8e7752..3ed4b97 100644 --- a/src/modules/stream/ui/growth_module.cpp +++ b/src/modules/stream/ui/growth_module.cpp @@ -560,6 +560,7 @@ void growth_module::mark_doors(flecs::world &&ecs_) [&room_e](flecs::entity re) { room_e = re; }); + cell_e.add(); flecs::entity next_cell_e = data[ke->get()].id2entity[path[k + 1]]; next_cell_e.each< @@ -567,6 +568,7 @@ void growth_module::mark_doors(flecs::world &&ecs_) [&next_room_e](flecs::entity re) { next_room_e = re; }); + next_cell_e.add(); if (room_e.is_valid() && next_room_e.is_valid()) { if (exits.has(room_e.id()) && diff --git a/src/modules/stream/ui/region_tree.cpp b/src/modules/stream/ui/region_tree.cpp index 26051bb..4022eb6 100644 --- a/src/modules/stream/ui/region_tree.cpp +++ b/src/modules/stream/ui/region_tree.cpp @@ -63,6 +63,7 @@ void region_tree::split(flecs::entity grid_floor_e, count++; e = e->next(); } + assert(base_rtree->check(grid_floor_e)); } const region_tree *region_tree::find(flecs::entity_t which) const @@ -136,6 +137,7 @@ void region_tree::grow(flecs::entity grid_floor_e, bool limited) const struct region_tree *base_rtree = grid_floor_e.get(); assert(base_rtree); make_random r(11365); + assert(base_rtree->check(grid_floor_e)); #ifdef TESTS flecs::log::warn("grow"); #endif @@ -176,6 +178,7 @@ void region_tree::grow(flecs::entity grid_floor_e, bool limited) return hash_one_uint64((uint64_t)ptr); } }; + Vector2i pos = get_global_center(); while (1) { e = special_grow_list.front(); int count = 0; @@ -187,29 +190,64 @@ void region_tree::grow(flecs::entity grid_floor_e, bool limited) e = e->next(); continue; } + Vector2i dir = pos - item->region.rect.position; struct region backup = item->region; RegionRect2i parent_rect = item->parent->region.rect; switch (variant) { case 0: + if (dir.x > 0) + item->region.rect.position.x = + parent_rect.position.x + + parent_rect.size.x - 1; + else if (dir.x < 0) + item->region.rect.position.x = + parent_rect.position.x; + if (dir.y > 0) + item->region.rect.position.y = + parent_rect.position.y + + parent_rect.size.y - 1; + else if (dir.y < 0) + item->region.rect.position.y = + parent_rect.position.y; + break; + case 1: + if (dir.x > 0) + item->region.rect.position.x = + parent_rect.position.x + + parent_rect.size.x - 1; + else if (dir.x < 0) + item->region.rect.position.x = + parent_rect.position.x; + break; + case 2: + if (dir.y > 0) + item->region.rect.position.y = + parent_rect.position.y + + parent_rect.size.y - 1; + else if (dir.y < 0) + item->region.rect.position.y = + parent_rect.position.y; + break; + case 3: item->region.rect.position.x = parent_rect.position.x + parent_rect.size.x - 1; break; - case 1: + case 4: item->region.rect.position.x = parent_rect.position.x; break; - case 2: + case 5: item->region.rect.position.y = parent_rect.position.y + parent_rect.size.y - 1; break; - case 3: + case 6: item->region.rect.position.y = parent_rect.position.y; break; } - if (variant > 3) { + if (variant > 6) { do { item->region.rect.position.x = parent_rect.position.x + @@ -363,6 +401,7 @@ void region_tree::grow(flecs::entity grid_floor_e, bool limited) queue.clear(); assert(base_rtree->check(grid_floor_e)); } + assert(base_rtree->check(grid_floor_e)); } bool region_tree::check(flecs::entity grid_floor_e) const @@ -407,6 +446,7 @@ bool region_tree::check(flecs::entity grid_floor_e) const float aspect = (float)check_regions[i].size.x / (float)check_regions[i].size.y; if (aspect < 0.25f || aspect > 4.0f) { + flecs::log::err("bad aspect ratio"); ok = false; break; } @@ -456,6 +496,219 @@ bool region_tree::check(flecs::entity grid_floor_e) const return ok; } +// TODO: calculate if rooms touch each other and shrink smaller one +void region_tree::shrink_rooms(flecs::entity grid_floor_e) +{ + int i, accepted = 0; + assert(!parent); + dump(grid_floor_e); + List queue, shrinkable; + List left_rooms, right_rooms, forward_rooms, + backward_rooms, inside_rooms; + List::Element *rp, *rp1, *rp2; + struct touching_result { + struct region_tree *first; + struct region_tree *second; + int how; + }; + const struct region_tree *base_rtree = grid_floor_e.get(); + assert(base_rtree); + assert(base_rtree->check(grid_floor_e)); + List touching; + int grid_size = grid_floor_e + .get() + ->grid_size; + queue.push_back(this); + while (!queue.empty()) { + const struct region_tree *item = queue.front()->get(); + queue.pop_front(); + if (item->region.can_grow) + return; + if (item->is_leaf() && item->region.can_move) + return; + for (i = 0; i < (int)item->children.size(); i++) + queue.push_back(item->children[i]); + } + queue.clear(); + queue.push_back(this); + while (!queue.empty()) { + struct region_tree *item = queue.front()->get(); + queue.pop_front(); + int acceptable = 0; + if (item->is_shrinkable()) + acceptable = 0xf; + flecs::log::dbg("acceptable: %d", acceptable); + if ((acceptable & 0xf) == 0xf) { + shrinkable.push_back(item); + accepted++; + int rx, px, ry, py; + rx = item->region.rect.position.x; + px = item->parent->region.rect.position.x; + if (rx == px) { + left_rooms.push_back(item); + acceptable |= (1 << 4); + } + rx = item->region.rect.position.x + + item->region.rect.size.x - 1; + px = item->parent->region.rect.position.x + + item->parent->region.rect.size.x - 1; + if (rx == px) { + right_rooms.push_back(item); + acceptable |= (1 << 5); + } + ry = item->region.rect.position.y; + py = item->parent->region.rect.position.y; + if (ry == py) { + forward_rooms.push_back(item); + acceptable |= (1 << 6); + } + ry = item->region.rect.position.y + + item->region.rect.size.y - 1; + py = item->parent->region.rect.position.y + + item->parent->region.rect.size.y - 1; + if (ry == py) { + backward_rooms.push_back(item); + acceptable |= (1 << 7); + } + if ((acceptable & 0xf0) == 0) + inside_rooms.push_back(item); + flecs::log::dbg("acceptable: %d", acceptable); + } + for (i = 0; i < (int)item->children.size(); i++) + queue.push_back(item->children[i]); + } +#if 0 + rp1 = rooms.front(); + while (rp1) { + rp2 = rooms.front(); + while (rp2) { + if (rp1 == rp2) { + rp2 = rp2->next(); + continue; + } + int style = rp1->get()->what_touching(rp2->get()); + struct region_tree *item1 = rp1->get(), + *item2 = rp2->get(); + if (style & TOUCH_RIGHT) { + if (shrinkable.find(item2)) { + if (!right_rooms.find(item2)) + right_rooms.push_back(item2); + } else if (shrinkable.find(item1)) { + if (!left_rooms.find(item1)) + left_rooms.push_back(item1); + } + } + if (style & TOUCH_LEFT) { + if (shrinkable.find(item2)) { + if (!left_rooms.find(item2)) + left_rooms.push_back(item2); + } else if (shrinkable.find(item1)) { + if (!right_rooms.find(item1)) + right_rooms.push_back(item1); + } + } + if (style & TOUCH_FORWARD) { + if (shrinkable.find(item2)) { + if (!forward_rooms.find(item2)) + forward_rooms.push_back(item2); + } else if (shrinkable.find(item1)) { + if (!backward_rooms.find(item1)) + backward_rooms.push_back(item1); + } + } + if (style & TOUCH_BACKWARD) { + if (shrinkable.find(item2)) { + if (!backward_rooms.find(item2)) + backward_rooms.push_back(item2); + } else if (shrinkable.find(item1)) { + if (!forward_rooms.find(item1)) + forward_rooms.push_back(item1); + } + } + rp2 = rp2->next(); + } + rp1 = rp1->next(); + } +#endif + int shrunk = 0; + int shrink_mode = SHRINK_LEFT_ROOM; + while (1) { + switch (shrink_mode) { + case SHRINK_LEFT_ROOM: + rp = left_rooms.front(); + break; + case SHRINK_RIGHT_ROOM: + rp = right_rooms.front(); + break; + case SHRINK_FORWARD_ROOM: + rp = forward_rooms.front(); + break; + case SHRINK_BACKWARD_ROOM: + rp = backward_rooms.front(); + break; + case SHRINK_INSIDE_ROOM: + rp = inside_rooms.front(); + break; + } + while (rp) { + struct region backup = rp->get()->region; + List neighbors; + switch (shrink_mode) { + case SHRINK_LEFT_ROOM: + get_neighbors(grid_floor_e, RIGHT, &neighbors); + if (neighbors.size() > 0) { + rp->get()->region.rect.size.x -= 1; + shrunk++; + } + break; + case SHRINK_RIGHT_ROOM: + get_neighbors(grid_floor_e, LEFT, &neighbors); + if (neighbors.size() > 0) { + rp->get()->region.rect.position.x += 1; + rp->get()->region.rect.size.x -= 1; + shrunk++; + } + break; + case SHRINK_FORWARD_ROOM: + get_neighbors(grid_floor_e, BACKWARD, + &neighbors); + if (neighbors.size() > 0) { + rp->get()->region.rect.size.y -= 1; + shrunk++; + } + break; + case SHRINK_BACKWARD_ROOM: + get_neighbors(grid_floor_e, FORWARD, + &neighbors); + if (neighbors.size() > 0) { + rp->get()->region.rect.position.y += 1; + rp->get()->region.rect.size.y -= 1; + shrunk++; + } + break; + case SHRINK_INSIDE_ROOM: + // TODO: check neighbors + rp->get()->region.rect = + rp->get()->region.rect.grow(-1); + shrunk++; + break; + default: + assert(false); + } + if (!base_rtree->check(grid_floor_e)) + rp->get()->region = backup; + assert(base_rtree->check(grid_floor_e)); + rp = rp->next(); + } + if (shrink_mode >= SHRINK_INSIDE_ROOM) + break; + shrink_mode++; + } + assert(base_rtree->check(grid_floor_e)); + // assert(accepted == 0 || shrunk > 0); + grid_floor_e.modified(); +} void region_tree::place(flecs::entity grid_floor_e) const { int i, j, k; @@ -568,10 +821,13 @@ void region_tree::place(flecs::entity grid_floor_e) const void region_tree::move(flecs::entity grid_floor_e) { + if (!parent) + return; struct region_tree *base_rtree = grid_floor_e.get_mut(); assert(base_rtree); List queue; List movables; + List movables_sorted; int count = 0; Vector2i center; queue.push_back(base_rtree); @@ -595,37 +851,97 @@ void region_tree::move(flecs::entity grid_floor_e) flecs::log::dbg("center: %d %d", center.x, center.y); while (!movables.empty()) { struct region_tree *item = movables.front()->get(); + Vector2i dir = item->region.rect.get_center() - center; + int d = dir.x * dir.x + dir.y * dir.y; movables.pop_front(); + List::Element *e = movables.front(); + bool ok = true; + while (e) { + struct region_tree *check = e->get(); + Vector2i dir2 = + check->region.rect.get_center() - center; + int d2 = dir2.x * dir2.x + dir2.y * dir2.y; + if (d2 > d) { + ok = false; + break; + } + e = e->next(); + } + if (ok) + movables_sorted.push_back(item); + else + movables.push_back(item); + } + flecs::log::dbg("sorting done"); + int fail_count = 0; + while (!movables_sorted.empty()) { + struct region_tree *item = movables_sorted.front()->get(); if (!item->region.can_move) continue; - Vector2i dir = item->region.rect.get_center() - center, dir1, - dir2; - if (dir.x * dir.x > dir.y * dir.y) { - dir1.x = CLAMP(dir.x, -1, 1); - dir1.y = 0; - } else if (dir.x * dir.x < dir.y * dir.y) { - dir1.x = 0; - dir1.y = CLAMP(dir.y, -1, 1); - } - dir2.x = CLAMP(dir.x, -1, 1); - dir2.y = CLAMP(dir.y, -1, 1); - flecs::log::dbg("direction: %d %d", dir.x, dir.y); - RegionRect2i backup = item->region.rect; - item->region.rect.position += dir1; - if (base_rtree->check(grid_floor_e)) { - queue.push_back(item); - continue; - } else { - item->region.rect = backup; - item->region.rect.position += dir2; - if (base_rtree->check(grid_floor_e)) { - queue.push_back(item); - continue; + Vector2i gcenter = item->get_global_center(); + Vector2i dir = item->parent->region.rect.get_center() - + (center * 2 + gcenter * 4); + int flag1 = (item->region.rect.position.x + + item->region.rect.position.y) & + (1 << 1); + int flag2 = (item->region.rect.position.x + + item->region.rect.position.y) & + (1 << 2); + if (dir.x == 0 && dir.y == 0) { + if (flag1) { + dir.x = 0; + if (flag2) + dir.y = 1; + else + dir.y = -1; } else { - item->region.rect = backup; - item->region.can_move = false; + if (flag2) + dir.x = 1; + else + dir.x = -1; + dir.y = 0; } } + Vector2i mdir1, mdir2; + mdir1.x = CLAMP(dir.x, -1, 1); + mdir1.y = 0; + mdir2.x = 0; + mdir2.y = CLAMP(dir.y, -1, 1); + flecs::log::dbg("direction: %d %d", dir.x, dir.y); + flecs::log::dbg("direction1: %d %d", mdir1.x, mdir1.y); + flecs::log::dbg("direction2: %d %d", mdir2.x, mdir2.y); + flecs::log::dbg("position: %d %d", item->region.rect.position.x, + item->region.rect.position.y); + RegionRect2i backup = item->region.rect; + item->region.rect.position += mdir1; + flecs::log::dbg("updated position: %d %d", + item->region.rect.position.x, + item->region.rect.position.y); + bool ok1 = false, ok2 = false; + if (base_rtree->check(grid_floor_e)) { + fail_count = 0; + flecs::log::dbg("can still move"); + ok1 = true; + } else { + ok1 = false; + item->region.rect = backup; + item->region.rect.position += mdir2; + if (base_rtree->check(grid_floor_e)) + ok2 = true; + else + ok2 = false; + } + if (!ok1 && !ok2) { + fail_count++; + item->region.rect = backup; + if (fail_count > 10) { + item->region.can_move = false; + movables_sorted.pop_front(); + flecs::log::dbg("can't move, going to next"); + fail_count = 0; + } + } else + continue; } grid_floor_e.modified(); } @@ -702,7 +1018,156 @@ bool region_tree::is_special() const { return flag_special; } +bool region_tree::is_touching(const struct region_tree *other) const +{ + int flags = what_touching(other); + return (flags > 0); +} +void region_tree::get_room_nodes( + List *node_list) const +{ + List queue; + queue.push_back(this); + while (!queue.empty()) { + int i; + const struct region_tree *item = queue.front()->get(); + queue.pop_front(); + if (item->is_leaf() && item->is_a_room()) { + node_list->push_back(item); + } + for (i = 0; i < (int)item->children.size(); i++) + queue.push_back(item->children[i]); + } +} + +void region_tree::get_room_nodes(List *node_list) +{ + List queue; + queue.push_back(this); + while (!queue.empty()) { + int i; + struct region_tree *item = queue.front()->get(); + queue.pop_front(); + if (item->is_leaf() && item->is_a_room()) { + node_list->push_back(item); + } + for (i = 0; i < (int)item->children.size(); i++) + queue.push_back(item->children[i]); + } +} + +void region_tree::get_neighbors(flecs::entity grid_floor_e, int direction, + List *neighbors) const +{ + List rooms; + List::Element *el; + struct region_tree *base_rtree = grid_floor_e.get_mut(); + assert(base_rtree); + base_rtree->get_room_nodes(&rooms); + RegionRect2i neighbor_rect = region.rect; + neighbors->clear(); + switch (direction) { + case LEFT: + neighbor_rect.position.x -= 1; + neighbor_rect.size.x = 1; + break; + case RIGHT: + neighbor_rect.position.x += region.rect.size.x; + neighbor_rect.size.x = 1; + break; + case FORWARD: + neighbor_rect.position.y -= 1; + neighbor_rect.size.y = 1; + break; + case BACKWARD: + neighbor_rect.position.y += region.rect.size.y; + neighbor_rect.size.y = 1; + break; + default: + assert(false); + break; + } + el = rooms.front(); + while (el) { + if (el->get() == this) { + el = el->next(); + continue; + } + bool neighbor = false; + if (neighbor_rect == el->get()->region.rect) + neighbor = true; + if (neighbor_rect.encloses(el->get()->region.rect)) + neighbor = true; + if (neighbor_rect.intersects(el->get()->region.rect)) + neighbor = true; + if (el->get()->region.rect.encloses(neighbor_rect)) + neighbor = true; + if (el->get()->region.rect.intersects(neighbor_rect)) + neighbor = true; + if (neighbor) + neighbors->push_back(el->get()); + el = el->next(); + } +} + +int region_tree::what_touching(const region_tree *other) const +{ + int i; + RegionRect2i right = region.rect, left = region.rect, + forward = region.rect, backward = region.rect; + right.position.x = region.rect.position.x + region.rect.size.x; + left.position.x = region.rect.position.x - region.rect.size.x; + forward.position.y = region.rect.position.y - region.rect.size.y; + backward.position.y = region.rect.position.y + region.rect.size.y; + int flags = 0; + RegionRect2i rects[] = { right, left, forward, backward }; + for (i = 0; i < (int)sizeof(rects) / (int)sizeof(rects[0]); i++) { + if (other->region.rect == rects[i]) + flags |= (1 << i); + if (other->region.rect.encloses(rects[i])) + flags |= (1 << i); + if (other->region.rect.intersects(rects[i])) + flags |= (1 << i); + if (rects[i].encloses(other->region.rect)) + flags |= (1 << i); + } + return flags; +} + +bool region_tree::is_shrinkable() const +{ + int acceptable = 0; + if (region.rect.size.x > 2) + acceptable |= (1 << 0); + if (region.rect.size.y > 2) + acceptable |= (1 << 1); + if (is_leaf()) + acceptable |= (1 << 2); + if (parent) + acceptable |= (1 << 3); + return (acceptable & 0xf) == 0xf; +} + +Vector2i region_tree::get_global_center() const +{ + Vector2i center; + int i; + const struct region_tree *r = this; + while (r->parent) + r = r->parent; + for (i = 0; i < r->children.size(); i++) + center += r->children[i]->region.rect.get_center(); + return center; +} +Vector2i region_tree::get_center() const +{ + return region.rect.get_center(); +} +int region_tree::area() const +{ + return region.rect.get_area(); +} bool region_tree::check_candidate(int i, const RegionRect2i &candidate) const { int j; diff --git a/src/modules/stream/ui/region_tree.h b/src/modules/stream/ui/region_tree.h index 2bc4b57..9b7c239 100644 --- a/src/modules/stream/ui/region_tree.h +++ b/src/modules/stream/ui/region_tree.h @@ -22,6 +22,7 @@ struct region_tree { void grow(flecs::entity grid_floor_e, bool limited = true); bool check(flecs::entity grid_floor_e) const; void place(flecs::entity grid_floor_e) const; + void shrink_rooms(flecs::entity grid_floor_e); void move(flecs::entity grid_floor_e); void get_rects(List *rect_list) const; void get_leaf_nodes(List *node_list) const; @@ -29,6 +30,35 @@ struct region_tree { bool is_a_room(flecs::entity grid_floor_e) const; bool is_a_room() const; bool is_special() const; + bool is_touching(const struct region_tree *other) const; + enum { + TOUCH_RIGHT = 1, + TOUCH_LEFT = 2, + TOUCH_FORWARD = 4, + TOUCH_BACKWARD = 8, + }; + enum { + SHRINK_LEFT_ROOM = 1, // shrink right side + SHRINK_RIGHT_ROOM, // shrink left side + SHRINK_FORWARD_ROOM, // shrink "upper" side + SHRINK_BACKWARD_ROOM, // shrink "lower" side + SHRINK_INSIDE_ROOM, // shrink "inside" room (all sides?) + }; + enum { + LEFT = 1, + RIGHT, + FORWARD, + BACKWARD, + }; + void get_room_nodes(List *node_list) const; + void get_room_nodes(List *node_list); + void get_neighbors(flecs::entity grid_floor_e, int direction, + List *neighbors) const; + int what_touching(const struct region_tree *other) const; + bool is_shrinkable() const; + Vector2i get_global_center() const; + Vector2i get_center() const; + int area() const; private: bool check_candidate(int i, const RegionRect2i &candidate) const; diff --git a/src/modules/stream/world_editor.h b/src/modules/stream/world_editor.h index cfeedd0..325763e 100644 --- a/src/modules/stream/world_editor.h +++ b/src/modules/stream/world_editor.h @@ -119,6 +119,7 @@ public: List > floors; int growth_size; }; + struct path {}; struct belongs {}; struct border {}; struct belongs_room {};