Now generating layouts with corridoors

This commit is contained in:
2024-12-08 19:16:06 +03:00
parent d46401b973
commit 5d4c653c9a
17 changed files with 901 additions and 1122 deletions

View File

@@ -18,7 +18,8 @@ public = [
[308, "Cellar", { "window": true }],
[309, "Office", { "window": true }],
[310, "Server Room", { "window": true }],
[311, "Room", { "window": true }]
[311, "Room", { "window": true }],
[312, "Studio", { "window": true }]
]
parts_library_path = "res://astream/building-layouts/building-elements-v2.glb"
[commands]
@@ -33,3 +34,96 @@ commands = [
[7, "PopPosition"]
]
; private rooms
[rooms/200]
name = "WC"
window = false
grow = false
private = true
[rooms/201]
name = "Bathroom"
window = false
grow = false
private = true
[rooms/202]
name = "Bedroom"
private = true
[rooms/203]
name = "Holding Cell"
window = false
private = true
[rooms/204]
name = "Dormitory"
private = true
[rooms/205]
name = "Torture Room"
window = false
private = true
; public rooms
[rooms/300]
name = "Living Room"
[rooms/301]
name = "Family Room"
[rooms/302]
name = "Kitchen"
[rooms/303]
name = "Dining Room"
[rooms/304]
name = "Enterance"
wall = true
window = false
special = true
[rooms/305]
name = "Stair"
window = false
special = true
[rooms/306]
name = "Elevator"
window = false
special = true
[rooms/307]
name = "Storage Room"
[rooms/308]
name = "Cellar"
window = false
[rooms/309]
name = "Office"
[rooms/310]
name = "Server Room"
[rooms/311]
name = "Room"
[rooms/312]
name = "Studio"
[rooms/313]
name = "General Store"
[rooms/default]
name = "Unknown Room"
wall = false
window = true
grow = true
private = false
special = false

View File

@@ -23,8 +23,6 @@ BuildingLayoutGraph::BuildingLayoutGraph()
ecs.import <growth_module>();
Error err = config.load("res://astream/building_layout.conf");
assert(err == OK);
public_rooms = config.get_value("rooms", "public", Array());
private_rooms = config.get_value("rooms", "private", Array());
load_layouts();
}
@@ -39,35 +37,6 @@ BuildingLayoutGraph *BuildingLayoutGraph::get_singleton()
return singleton;
}
void BuildingLayoutGraph::get_room_data(int id, Array &result)
{
int i;
Array rooms;
rooms.append_array(private_rooms);
rooms.append_array(public_rooms);
int index = -1;
for (i = 0; i < rooms.size(); i++) {
Array room_data = rooms[i];
int room_id = room_data[0];
if (room_id == id) {
index = i;
break;
}
}
Array room = rooms[index];
result = room;
}
const Array &BuildingLayoutGraph::get_private_rooms() const
{
return private_rooms;
}
const Array &BuildingLayoutGraph::get_public_rooms() const
{
return public_rooms;
}
void BuildingLayoutGraph::destroy_graph_entity(const String &path)
{
flecs::world ecs = BaseData::get_singleton()->get();
@@ -301,25 +270,19 @@ void BuildingLayoutGraph::get_menu_entries(flecs::entity e,
int zone_type =
e.get<WorldEditor::components::buildings_layout_zone>()
->type;
if (zone_type == 0) {
const Array &private_rooms = get_private_rooms();
for (i = 0; i < private_rooms.size(); i++) {
Array room_data = private_rooms[i];
int id = room_data[0];
String room_name = room_data[1];
Pair<int, String> item(
{ id, "Create " + room_name });
list->push_back(item);
}
} else if (zone_type == 1) {
const Array &public_rooms = get_public_rooms();
for (i = 0; i < public_rooms.size(); i++) {
Array room_data = public_rooms[i];
int id = room_data[0];
String room_name = room_data[1];
Pair<int, String> item(
{ id, "Create " + room_name });
list->push_back(item);
for (i = 0; i < 10000; i++) {
if (config.has_section("rooms/" + itos(i))) {
String room_name = config.get_value(
"rooms/" + itos(i), "name",
"Invalid Room");
bool private_room = config.get_value(
"rooms/" + itos(i), "private", false);
if ((private_room && zone_type == 0) ||
(!private_room && zone_type == 1)) {
Pair<int, String> item(
{ i, "Create " + room_name });
list->push_back(item);
}
}
}
}

View File

@@ -6,8 +6,6 @@ class BuildingLayoutGraph {
BuildingLayoutGraph();
ConfigFile config;
Array public_rooms;
Array private_rooms;
flecs::entity create_graph_entity(const String &base_path,
const String &entity_type);
@@ -20,9 +18,8 @@ public:
memdelete(singleton);
singleton = nullptr;
}
void get_room_data(int id, Array &result);
const Array &get_private_rooms() const;
const Array &get_public_rooms() const;
bool has_room_type(int id) const;
Variant get_room_type_property(int id, const String &property) const;
void create_zone(const String &base_path, int zone_type);
void create_unit(const String &base_path);
void create_floor(const String &base_path);

View File

@@ -192,255 +192,11 @@ void graph_module::create_floor_components(
floor_e.add<WorldEditor::components::belongs>(base_floor_e);
}
#if 0
void growth_regions::create_region(flecs::entity floor_e, flecs::entity seed_e,
flecs::entity parent_e,
flecs::entity region_e,
const Vector2i &position, float area,
int parent_index)
{
int i;
struct growth_regions::region r;
r.parent = parent_e.id();
r.seed_et = seed_e.id();
r.region_et = region_e.id();
r.rect.position = position;
r.rect.size = Vector2i(1, 1);
r.remains_area = MAX((int)(area * 2.0f) / 16 + 1, 16);
r.can_grow_square = true;
r.can_grow = true;
r.complete = false;
r.parent_region = parent_index;
flecs::log::dbg("create region %s in %s",
(r.rect.operator String()).ascii().ptr(),
(parent_regions[parent_index].rect.operator String())
.ascii()
.ptr());
assert(parent_regions[parent_index].rect.encloses(r.rect));
bool ok = true;
assert(check_region(-1, r.rect));
const struct growth_regions *reg = floor_e.get<growth_regions>();
for (i = 0; i < reg->regions.size(); i++) {
if (reg->regions[i].region_et == r.region_et) {
ok = false;
break;
}
if (reg->regions[i].rect.position == r.rect.position) {
ok = false;
break;
}
}
r.remains_area -= 1;
assert(ok);
if (ok) {
floor_e.get_mut<growth_regions>()->complete = false;
floor_e.get_mut<growth_regions>()->regions.push_back(r);
floor_e.modified<growth_regions>();
flecs::log::warn("region created for %s",
region_e.path().c_str());
}
}
#endif
flecs::entity growth_regions::create_cell(flecs::entity floor_e,
flecs::entity region_e, int id)
{
#if 0
flecs::entity ret;
flecs::log::dbg("create_cell: %s %d", region_e.path().c_str(), id);
if (floor_e.get<WorldEditor::components::buildings_layout_grid_floor>()
->cells.has(id)) {
flecs::log::err("cell %d already exists", id);
return ret;
}
#endif
String pname("cell_" + itos(id));
flecs::entity cell_e = floor_e.lookup(pname.ascii().ptr());
if (cell_e.is_valid())
flecs::log::err("cell %d already exists", id);
assert(!cell_e.is_valid());
cell_e = floor_e.world().entity(pname.ascii().ptr()).child_of(floor_e);
floor_e.get_mut<WorldEditor::components::buildings_layout_grid_floor>()
->cells.insert(id);
floor_e.get_mut<WorldEditor::components::buildings_layout_grid_floor>()
->size_left--;
floor_e.modified<WorldEditor::components::buildings_layout_grid_floor>();
if (cell_e.is_valid()) {
cell_e.set<WorldEditor::components::buildings_layout_grid_cell>(
{ String(region_e.name()), id });
cell_e.add<WorldEditor::components::belongs>(region_e);
if (region_e.has<
WorldEditor::components::buildings_layout_room>()) {
int mcount = 0;
cell_e.each<WorldEditor::components::belongs_room>(
[&mcount, region_e](flecs::entity e) {
if (e.id() != region_e.id())
assert(false);
mcount++;
});
if (mcount == 0)
cell_e.add<WorldEditor::components::belongs_room>(
region_e);
}
}
return cell_e;
}
flecs::entity growth_regions::update_cell(flecs::entity floor_e,
flecs::entity parent_e,
flecs::entity region_e, int id)
{
flecs::log::dbg("create_cell: %s %d", region_e.path().c_str(), id);
String pname("cell_" + itos(id));
flecs::entity cell_e = floor_e.lookup(pname.ascii().ptr());
if (!cell_e.is_valid()) {
flecs::log::warn("creating new cell %s", cell_e.path());
cell_e = floor_e.world()
.entity(pname.ascii().ptr())
.child_of(floor_e);
assert(cell_e.is_valid());
}
// assert(cell_e.has<WorldEditor::components::belongs>(parent_e));
/* already there */
floor_e.get_mut<WorldEditor::components::buildings_layout_grid_floor>()
->cells.insert(id);
floor_e.modified<WorldEditor::components::buildings_layout_grid_floor>();
cell_e.set<WorldEditor::components::buildings_layout_grid_cell>(
{ String(region_e.name()), id });
cell_e.remove<WorldEditor::components::belongs>(parent_e);
cell_e.add<WorldEditor::components::belongs>(region_e);
if (region_e.has<WorldEditor::components::buildings_layout_room>()) {
int mcount = 0;
cell_e.each<WorldEditor::components::belongs_room>(
[&mcount, region_e, cell_e](flecs::entity e) {
flecs::log::err("adding region %s to cell %s",
region_e.path().c_str(),
cell_e.path().c_str());
flecs::log::err("already belongs to %s",
e.path().c_str());
assert(mcount == 0);
assert(region_e.id() == e.id());
mcount++;
});
if (mcount == 0)
cell_e.add<WorldEditor::components::belongs_room>(
region_e);
}
return cell_e;
}
static inline int int_distance(const Vector2i &v1, const Vector2i &v2)
{
Vector2i l = v2 - v1;
return l.x * l.x + l.y * l.y;
}
#if 0
void growth_regions::split_region(
flecs::entity grid_floor_e, int region_index,
const List<Pair<flecs::entity, float> > &region_list)
{
int i, j;
struct make_random r(173);
int grid_size = grid_floor_e
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
growth_regions::region parent_region = regions[region_index];
// can't split rooms
assert(!grid_floor_e.world()
.entity(parent_region.region_et)
.has<WorldEditor::components::buildings_layout_room>());
regions.remove(region_index);
RegionRect2i clip_rect = parent_region.rect;
int parent_region_index = parent_regions.size();
parent_regions.push_back(parent_region);
flecs::log::warn("moved parent region %d", region_index);
assert(clip_rect.get_area() > region_list.size());
const List<Pair<flecs::entity, float> >::Element *e =
region_list.front();
Set<Vector2i> positions;
LocalVector<Pair<flecs::entity, Vector2i> > new_start;
int base_index = 0;
while (e) {
Vector2i pos;
int iterations = 1000;
while (1) {
int i;
pos = clip_rect.position +
Vector2i(r.get() % clip_rect.size.x,
r.get() % clip_rect.size.y);
assert(clip_rect.has_point(pos));
if (!positions.has(pos)) {
bool ok = true;
for (i = 0; i < (int)new_start.size(); i++) {
if (iterations < 100 &&
int_distance(new_start[i].second,
pos) < 2) {
ok = false;
break;
}
if (iterations < 200 &&
int_distance(new_start[i].second,
pos) < 1) {
ok = false;
break;
}
}
if (ok) {
positions.insert(pos);
break;
}
}
iterations--;
if (iterations < 0) {
assert(false);
break;
}
}
for (i = 0; i < regions.size(); i++) {
if (parent_region_index == regions[i].parent_region)
flecs::log::dbg(
"sibling regions: %d: %s", i,
(regions[i].rect.operator String())
.ascii()
.ptr());
}
flecs::log::dbg("cell: position: %d, %d", pos.x, pos.y);
for (i = 0; i < regions.size(); i++)
assert(parent_regions[regions[i].parent_region]
.rect.encloses(regions[i].rect));
for (i = 0; i < regions.size(); i++)
for (j = 0; j < regions.size(); j++) {
if (i == j)
continue;
if (regions[i].rect.encloses(regions[j].rect) ||
regions[j].rect.intersects(
regions[i].rect) ||
regions[i].rect.intersects(regions[j].rect))
assert(false);
}
assert(parent_region.rect.has_point(pos));
struct region reg;
new_start.push_back({ e->get().first, pos });
reg.can_grow = true;
reg.can_grow_square = true;
reg.complete = false;
reg.parent = parent_region.region_et;
reg.parent_region = parent_region_index;
reg.rect = RegionRect2i(pos, Vector2i(1, 1));
reg.region_et = e->get().first.id();
reg.remains_area = (int)Math::ceil(e->get().second);
int cell_id = pos.x + grid_size * pos.y;
flecs::entity parent_e =
grid_floor_e.world().entity(reg.parent);
flecs::entity cell_e = update_cell(grid_floor_e, parent_e,
e->get().first, cell_id);
reg.seed_et = cell_e.id();
regions.push_back(reg);
e = e->next();
base_index++;
complete = false;
}
}
#endif
void graph_module::zones_graph_module(flecs::world &ecs,
const String &module_name)
{
@@ -629,8 +385,27 @@ void graph_module::zones_graph_module(flecs::world &ecs,
buildings_layout_floor_index
&rindex) {
if (index.index == rindex.index) {
sum += MAX(rarea.area, MIN_ROOM_SIZE) *
10 / 8;
int rsize = (int)Math::sqrt(rarea.area /
16.0f) +
1;
bool priv =
BuildingLayoutGraph::get_singleton()
->get_room_type_property(
r.room_type,
"private");
bool window =
BuildingLayoutGraph::get_singleton()
->get_room_type_property(
r.room_type,
"window");
RegionRect2i xr(0, 0, rsize, rsize);
if (priv && !window)
xr = xr.grow(2);
else
xr = xr.grow(1);
int xarea = xr.size.x * xr.size.y * 16;
sum += MAX(xarea, MIN_ROOM_SIZE) * 10 /
8;
assert(sum >= 0.0f);
count_rooms++;
}
@@ -1380,6 +1155,22 @@ BuildingLayoutGraph::create_graph_entity(const String &base_path,
return new_e;
}
bool BuildingLayoutGraph::has_room_type(int id) const
{
return (config.has_section("rooms/" + itos(id)));
}
Variant
BuildingLayoutGraph::get_room_type_property(int id,
const String &property) const
{
assert(has_room_type(id));
Variant ret = config.get_value("rooms/" + itos(id), property,
config.get_value("rooms/default",
property, Variant()));
return ret;
}
void BuildingLayoutGraph::create_zone(const String &base_path, int zone_type)
{
flecs::entity new_e = create_graph_entity(base_path, "zone");
@@ -1416,11 +1207,13 @@ void BuildingLayoutGraph::create_floor(const String &base_path)
void BuildingLayoutGraph::create_room(const String &base_path, int id)
{
Array room;
BuildingLayoutGraph::get_singleton()->get_room_data(id, room);
assert(!room.empty());
String type_name = room[1];
Dictionary room_options = room[2];
bool window = room_options.get("window", false);
assert(config.has_section("rooms/" + itos(id)));
bool window = config.get_value("rooms/" + itos(id), "window",
config.get_value("rooms/default",
"window", true));
String type_name = config.get_value(
"rooms/" + itos(id), "name",
config.get_value("rooms/default", "name", "Unknown"));
type_name = type_name.replace(" ", "_").to_lower();
flecs::entity new_e = create_graph_entity(base_path, type_name);
new_e.set<WorldEditor::components::buildings_layout_room>(

View File

@@ -63,56 +63,6 @@ out:
return result;
}
#if 0
void grid_misc::place_regions(flecs::entity grid_floor_e)
{
int i;
int grid_size = grid_floor_e
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
// flecs::log::dbg("###=== %s", grid_floor_e.path().c_str());
flecs::entity grid_e = grid_floor_e.parent();
assert(grid_e.is_valid());
growth_regions::region parent_reg;
parent_reg.can_grow = false;
parent_reg.complete = true;
parent_reg.rect.position = Vector2i();
parent_reg.rect.size = Vector2i(grid_size, grid_size);
parent_reg.can_grow_square = false;
growth_regions *g = grid_floor_e.get_mut<growth_regions>();
int parent_index = g->parent_regions.size();
g->parent_regions.push_back(parent_reg);
for (i = 0; i < (int)positions.size(); i++) {
int cell_id = positions[i].second.x +
grid_size * positions[i].second.y;
flecs::entity region_e =
grid_e.world().entity(positions[i].first);
assert(region_e.is_valid());
Rect2i check;
check.position = positions[i].second;
check.size = Vector2i(1, 1);
// flecs::log::dbg("%s ->region: %s cell_id %d",
// grid_floor_e.path().c_str(),
// region_e.path().c_str(), cell_id);
assert(g->check_region(-1, check));
flecs::entity cell_e =
g->create_cell(grid_floor_e, region_e, cell_id);
assert(cell_e.is_valid());
flecs::log::warn("grid cell: %s", cell_e.path().c_str());
float area = get_entity_area(region_e);
// flecs::log::dbg("region: %s: parent: %s",
// region_e.path().c_str(),
// region_e.parent().path().c_str());
g->create_region(grid_floor_e, cell_e, region_e.parent(),
region_e, positions[i].second, area,
parent_index);
flecs::log::warn("grid cell: %s", cell_e.path().c_str());
}
// flecs::log::dbg("###=== %s done", grid_floor_e.path().c_str());
}
#endif
#if 0
void grid_misc::place_regions_common(flecs::entity parent_e,
@@ -396,36 +346,6 @@ void grid_misc::filter_candidates(flecs::entity ce, float area,
}
#if 0
void grid_misc::place_region_cells(
flecs::entity grid_floor_e,
const WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g)
{
int i;
for (i = 0; i < g.regions.size(); i++) {
int x, y;
RegionRect2i rect = g.regions[i].rect;
for (x = rect.position.x; x <= rect.position.x + rect.size.x;
x++)
for (y = rect.position.y;
y <= rect.position.y + rect.size.y; y++) {
int id = x + fl.grid_size * y;
if (!fl.cells.has(id)) {
flecs::entity seed_e =
grid_floor_e.world().entity(
g.regions[i].seed_et);
assert(seed_e.is_valid());
assert(seed_e.parent().is_valid());
assert(seed_e.parent().id() ==
grid_floor_e.id());
queue_grow_cell(seed_e, id);
}
}
}
}
#endif
void grid_misc::queue_grow_cell(flecs::entity seed_e, int id)
{
assert(seed_e.is_valid());
@@ -455,220 +375,6 @@ void grid_misc::queue_grow_cell(flecs::entity seed_e, int id)
}
}
#if 0
void grid_misc::print_can_grow(int state, growth_regions &g, int index,
const char *what)
{
const growth_regions::region &region = g.regions[index];
bool can = false;
if (!strcmp(what, "square"))
can = region.can_grow_square;
else if (!strcmp(what, "rect"))
can = region.can_grow;
if (can)
flecs::log::dbg(
"state: %d: index %d: region can still grow %s %d",
state, index, what, region.remains_area);
else
flecs::log::dbg("state: %d: index %d: region can't grow %s %d",
state, index, what, region.remains_area);
if (region.can_grow_region())
flecs::log::dbg("state %d: index %d: region can still continue",
state, index);
}
bool grid_misc::grow_state0(growth_regions &g, int index,
const RegionRect2i &clip)
{
bool ok = true, ret = false;
RegionRect2i mrect;
growth_regions::region &region = g.regions.write[index];
mrect = region.rect;
assert(g.check_region(index, mrect));
mrect = mrect.grow(1);
ok = clip.encloses(mrect);
// if (!ok)
// flecs::log::dbg("state: %d: index %d: out of clip area",
// 0, index);
if (ok) {
ok = g.check_region(index, mrect);
// if (!ok)
// flecs::log::dbg(
// "state: %d: index %d: check_region failed",
// 0, index);
}
if (ok) {
ret = region.update_region_size(mrect);
// if (!ret)
// flecs::log::dbg(
// "state: %d: index %d: update_region_size failed",
// 0, index);
}
print_can_grow(0, g, index, "square");
// if (!ret)
// flecs::log::dbg("state %d could not grow region %d: %d",
// 0, index, region.remains_area);
// else
// flecs::log::dbg("state %d could grow region %d: %d", 0,
// index, region.remains_area);
return ret;
}
#if 0
bool grid_misc::grow_state1(growth_regions &g, int index,
const RegionRect2i &clip)
{
int d;
bool ret = false;
RegionRect2i mrect;
growth_regions::region &region = g.regions.write[index];
int count = 0;
for (d = 0; d < 4; d++) {
bool ok;
mrect = region.rect;
assert(g.check_region(index, mrect));
switch (d) {
case 0:
mrect.position.y -= 1;
mrect.size.y += 1;
break;
case 1:
mrect.size.y += 1;
break;
case 2:
mrect.position.x -= 1;
mrect.size.x += 1;
break;
case 3:
mrect.size.x += 1;
break;
}
ok = g.parent_regions[region.parent_region].rect.encloses(
mrect);
if (ok)
ok = clip.encloses(mrect);
if (ok) {
ok = false;
if (mrect.size.y > 0 && mrect.size.x > 0) {
float aspect = (float)mrect.size.x /
(float)mrect.size.y;
ok = (aspect > 0.2f && aspect < 5.0f);
}
}
if (ok)
ok = g.check_region(index, mrect);
if (ok) {
bool result = region.update_region_size(mrect);
if (result)
count++;
}
}
if (count > 0) {
ret = true;
// flecs::log::dbg(
// "state %d could grow region %d: %d - %d out of %d times",
// 0, index, region.remains_area, count, 4);
}
print_can_grow(1, g, index, "rect");
// if (!ret)
// flecs::log::dbg(
// "state %d could not grow region rect %d: %d", 0,
// index, region.remains_area);
return ret;
}
#endif
#endif
#if 0
void grid_misc::grow_region_rects(
flecs::entity floor_e,
WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g)
{
int i;
bool grown = true;
int state = 0;
if (g.complete)
return;
Rect2i clip(0, 0, fl.grid_size, fl.grid_size);
state = 0;
// flecs::log::dbg("growing square");
while (grown) {
grown = false;
int count = 0;
for (i = 0; i < g.regions.size(); i++) {
growth_regions::region &region = g.regions.write[i];
RegionRect2i mrect = region.rect;
// flecs::log::dbg("grow_region_rects: region %d",
// i);
if (!region.can_grow_region()) {
// flecs::log::dbg(
// "grow_region_rects: skip %d",
// i);
continue;
}
mrect = region.rect;
bool result = false;
result = grow_state0(g, i, clip);
if (result)
count++;
}
if (count > 0) {
grown = true;
// flecs::log::dbg("grown squares %d times of %d",
// count, g.regions.size());
}
// if (!grown)
// flecs::log::dbg(
// "grow_region_rects: could not grow more squares");
}
state = 1;
grown = true;
// flecs::log::dbg("growing rect");
while (grown) {
grown = false;
int count = 0;
for (i = 0; i < g.regions.size(); i++) {
growth_regions::region &region = g.regions.write[i];
RegionRect2i mrect = region.rect;
// flecs::log::dbg("grow_region_rects: region %d",
// i);
if (!region.can_grow_region()) {
// flecs::log::dbg(
// "grow_region_rects: skip %d",
// i);
continue;
}
mrect = region.rect;
bool result = false;
result = grow_state1(g, i, clip);
if (result)
count++;
// if (!result)
// flecs::log::dbg(
// "state %d could not grow region %d",
// state, i);
// else
// flecs::log::dbg(
// "state %d could grow region %d: %d",
// state, i, region.remains_area);
}
if (count > 0) {
grown = true;
// flecs::log::dbg("grown rects %d times of %d",
// count, g.regions.size());
}
// if (!grown)
// flecs::log::dbg(
// "grow_region_rects: could not grow any more rects");
}
flecs::log::dbg("grow_region_rects: complete");
g.complete = true;
flecs::log::dbg("grow_region_rects: %s: done", floor_e.path().c_str());
}
void grid_misc::subregions_init(flecs::world w)
{
flecs::query<const WorldEditor::components::buildings_layout_area> qprep =

View File

@@ -177,16 +177,6 @@ struct grid_misc {
const WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g);
void queue_grow_cell(flecs::entity seed_e, int id);
void print_can_grow(int state, growth_regions &g, int index,
const char *what);
bool grow_state0(growth_regions &g, int index,
const RegionRect2i &clip);
bool grow_state1(growth_regions &g, int index,
const RegionRect2i &clip);
void grow_region_rects(
flecs::entity floor_e,
WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g);
Vector<Pair<flecs::entity, flecs::entity_t> > all_items;
void subregions_init(flecs::world w);
void get_subregions(flecs::entity parent,

View File

@@ -102,7 +102,6 @@ grow_job_queue::grow_job_queue(
/* Unlimited growth for squares */
void grow_job_queue::job_initial(struct grow_job *job)
{
int i, j;
flecs::entity base_floor_e = grid_e.world().entity(job->base_floor_id);
flecs::entity grid_floor_e = grid_e.world().entity(job->grid_floor_id);
flecs::log::dbg("create: base_floor: %s", base_floor_e.path().c_str());
@@ -118,10 +117,15 @@ void grow_job_queue::job_initial(struct grow_job *job)
grid_floor_e.set<region_tree>(
{ { job->base_floor_id, job->base_floor_id, job->base_floor_id,
clip_rect.grow(-1), grid_size * grid_size, false, false,
true },
false, true },
Vector<struct region_tree *>(),
nullptr });
struct region_tree *rtree = grid_floor_e.get_mut<region_tree>();
flecs::log::dbg("region rect: %s",
(rtree->region.rect.operator String()).ascii().ptr());
assert(!rtree->region.can_grow);
assert(rtree->region.rect.size.x > 1 || rtree->region.rect.size.y > 1);
assert(rtree->region.rect.get_area() > subregions.size());
create_region_list(rtree, subregions, initial_regions);
grid_floor_e.modified<region_tree>();
grid_floor_e.get_mut<region_tree>()->split(grid_floor_e,
@@ -164,7 +168,6 @@ void grow_job_queue::job_initial(struct grow_job *job)
}
void grow_job_queue::job_common(struct grow_job *job)
{
int i, j;
make_random r(172);
flecs::entity base_floor_e = grid_e.world().entity(job->base_floor_id);
flecs::entity grid_floor_e = grid_e.world().entity(job->grid_floor_id);
@@ -173,8 +176,6 @@ void grow_job_queue::job_common(struct grow_job *job)
flecs::entity parent_e = grid_e.world().entity(job->parent_id);
growth_regions *g = grid_floor_e.get_mut<growth_regions>();
const List<Pair<flecs::entity, float> > &subregions = job->subregions;
const List<Pair<flecs::entity, float> >::Element *fe =
subregions.front();
struct region_tree *base_rtree = grid_floor_e.get_mut<region_tree>(),
*rtree;
@@ -189,8 +190,16 @@ void grow_job_queue::job_common(struct grow_job *job)
parent_e.path().c_str(), g->job_list.size());
return;
}
flecs::log::dbg("region rect: %s",
(rtree->region.rect.operator String()).ascii().ptr());
assert(!rtree->region.can_grow);
assert(rtree->region.rect.size.x > 1 || rtree->region.rect.size.y > 1);
assert(rtree->region.rect.get_area() > subregions.size());
create_region_list(rtree, subregions, region_list);
assert(base_rtree->check(grid_floor_e));
flecs::log::dbg(
"splitting region: %s",
grid_e.world().entity(rtree->region.region_et).path().c_str());
rtree->split(grid_floor_e, region_list);
assert(base_rtree->check(grid_floor_e));
grid_floor_e.modified<region_tree>();
@@ -198,126 +207,11 @@ void grow_job_queue::job_common(struct grow_job *job)
assert(base_rtree->check(grid_floor_e));
rtree->grow(grid_floor_e);
assert(base_rtree->check(grid_floor_e));
rtree->move(grid_floor_e);
assert(base_rtree->check(grid_floor_e));
rtree->dump(grid_floor_e);
grid_floor_e.modified<region_tree>();
#if 0
flecs::log::dbg("common: region count: %d", g->regions.size());
assert(g->regions.size() > 0);
bool restart = false, found = false;
RegionRect2i clip_rect(0, 0, grid_size, grid_size);
for (i = 0; i < (int)g->regions.size(); i++) {
flecs::log::dbg("region %d: %s", i,
grid_e.world()
.entity(g->regions[i].region_et)
.path()
.c_str());
}
int region_index = -1;
for (i = 0; i < (int)g->regions.size(); i++) {
if (g->regions[i].region_et == job->parent_id) {
flecs::log::warn("parent is in regions %d", i);
region_index = i;
if (!g->regions[i].complete) {
g->job_list.push_back(*job);
restart = true;
flecs::log::err(
"parent is in regions %d incomplete",
i);
flecs::log::warn("delay job fo %s (%d jobs)",
grid_e.world()
.entity(job->parent_id)
.path()
.c_str(),
g->job_list.size());
}
found = true;
break;
}
}
if (!found) {
// no parent region yet
g->job_list.push_back(*job);
flecs::log::warn("delay job fo %s (%d jobs)",
parent_e.path().c_str(), g->job_list.size());
restart = true;
}
if (restart)
return;
#endif
#if 0
for (i = 0; i < g->regions.size(); i++)
flecs::log::warn(
"before: region %d: %s", i,
(g->regions[i].rect.operator String()).ascii().ptr());
// growth_regions::region parent_region = g->regions[region_index];
// const List<Pair<flecs::entity, float> >::Element *fe =
// subregions.front();
List<Pair<flecs::entity, float> > region_list = subregions;
g->split_region(grid_floor_e, region_index, region_list);
#endif
// g->regions.remove(region_index);
// clip_rect = parent_region.rect;
// int parent_region_index = g->parent_regions.size();
// g->parent_regions.push_back(parent_region);
/*
while (fe) {
flecs::entity ce = fe->get().first;
float area = fe->get().second;
flecs::log::warn("generating positions for: %s",
ce.path().c_str());
job->grid.filter_candidates(ce, area, clip_rect);
fe = fe->next();
}
job->grid.place_regions_common(parent_e, grid_floor_e,
parent_region_index);
*/
#if 0
for (i = 0; i < g->regions.size(); i++)
flecs::log::warn(
"after: region %d: %s", i,
(g->regions[i].rect.operator String()).ascii().ptr());
flecs::log::dbg("Running grow...");
g->grow_regions(grid_floor_e);
#endif
#if 0
// FIXME: fix this
queries.get_qr().each(
[this, parent_e](
flecs::entity grid_floor_e,
WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g) {
if (g.complete)
return;
g.grow_regions(grid_floor_e);
});
#endif
#if 0
for (i = 0; i < g->regions.size(); i++)
flecs::log::warn(
"after2: region %d: %s", i,
(g->regions[i].rect.operator String()).ascii().ptr());
#endif
#if 0
queries.get_qr().each(
[this, parent_e](
flecs::entity grid_floor_e,
WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g) {
struct grid_misc grd;
// if (g.complete)
// return;
//grd.grow_region_rects(grid_floor_e, fl, g);
grd.update_region_cells(grid_floor_e, parent_e, fl, g);
assert(false);
});
#endif
#if 0
update_region_cells(grid_floor_e);
for (i = 0; i < (int)g->regions.size(); i++)
g->regions.write[i].complete = true;
g->complete = true;
#endif
commit_common_queue();
// assert(false);
}
@@ -396,18 +290,22 @@ void grow_job_queue::create_region_list(
int i, j;
const List<Pair<flecs::entity, float> >::Element *fe =
subregions.front();
bool restart = false, found = false;
make_random r(172);
RegionRect2i clip_rect = rtree->region.rect;
Vector2i current_position = clip_rect.get_center();
Vector2i velocity;
flecs::log::dbg("clip_rect: %s",
(clip_rect.operator String()).ascii().ptr());
assert(clip_rect.size.x > 1 || clip_rect.size.y > 1);
assert(clip_rect.get_area() > subregions.size());
Vector<flecs::entity> regions;
LocalVector<Vector2i> positions;
Vector<int> distances;
LocalVector<float> areas;
// Drunk walk implementation
int speed = MAX(1, grid_size * grid_size / 2 / subregions.size());
int bad_count = 0;
while (fe) {
Vector<Vector2i> position_candidates;
@@ -496,6 +394,12 @@ void grow_job_queue::create_region_list(
bad_count++;
}
if (bad_count >= 100) {
flecs::log::dbg(
"using different algorithm: %s: %s",
(clip_rect.operator String()).ascii().ptr(),
(current_position.operator String())
.ascii()
.ptr());
position_candidates.clear();
int x, y;
for (x = clip_rect.position.x;
@@ -506,6 +410,10 @@ void grow_job_queue::create_region_list(
y++) {
position_candidates.push_back(
Vector2i(x, y));
flecs::log::dbg(
"candidate: %d: %d %d",
position_candidates.size() - 1,
x, y);
}
bad_count = 0;
for (i = 0; i < position_candidates.size(); i++) {
@@ -547,6 +455,7 @@ void grow_job_queue::create_region_list(
flecs::log::dbg("position: %d, %d", positions[i].x,
positions[i].y);
region.complete = false;
region.can_move = true;
region.can_grow = true;
region.can_grow_square = true;
region.parent = rtree->region.region_et;

View File

@@ -1,7 +1,9 @@
#include <core/math/a_star.h>
#include "growth_regions.h"
#include "region_tree.h"
#include "editor_event.h"
#include "queries.h"
#include "building_layout_graph.h"
#include "growth_module.h"
growth_module::growth_module(flecs::world &ecs)
@@ -9,6 +11,18 @@ growth_module::growth_module(flecs::world &ecs)
ecs.module<growth_module>();
ecs.component<growth_regions>();
ecs.component<region_tree>();
ecs.component<WorldEditor::components::internal_wall_east>();
ecs.component<WorldEditor::components::internal_wall_west>();
ecs.component<WorldEditor::components::internal_wall_north>();
ecs.component<WorldEditor::components::internal_wall_south>();
ecs.component<WorldEditor::components::outside_wall_east>();
ecs.component<WorldEditor::components::outside_wall_west>();
ecs.component<WorldEditor::components::outside_wall_north>();
ecs.component<WorldEditor::components::outside_wall_south>();
ecs.component<WorldEditor::components::window_east>();
ecs.component<WorldEditor::components::window_west>();
ecs.component<WorldEditor::components::window_north>();
ecs.component<WorldEditor::components::window_south>();
const String &module_name = "::growth_module";
flecs::entity GraphFilter = ecs.entity("GraphFilter")
.add(flecs::Phase)
@@ -16,11 +30,6 @@ growth_module::growth_module(flecs::world &ecs)
flecs::entity GraphSolve = ecs.lookup("::graph_module::GraphSolve");
assert(GraphSolve.is_valid());
GraphFilter.disable();
#if 0
flecs::entity GraphGridPrepare = ecs.entity("GraphGridPrepare")
.add(flecs::Phase)
.depends_on(GraphSolve);
#endif
ecs.system("RunGrow")
.immediate()
@@ -76,113 +85,8 @@ growth_module::growth_module(flecs::world &ecs)
job_queue.iterate();
});
commit_growth_queue(it.world());
queries.get_mark_cells().each([](flecs::entity e,
const WorldEditor::
components::buildings_layout_grid_cell
&cell) {
int grid_size =
e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
int i;
Vector2i position(cell.index % grid_size,
cell.index / grid_size);
Vector2 west(position.x - 1, position.y);
Vector2 north(position.x, position.y - 1);
Vector2 east(position.x + 1, position.y);
Vector2 south(position.x, position.y + 1);
int west_id = west.x + grid_size * west.y;
int north_id = north.x + grid_size * north.y;
int east_id = east.x + grid_size * east.y;
int south_id = south.x + grid_size * south.y;
std::vector<int> neighbors = {
west_id, north_id, east_id, south_id
};
bool outside = false;
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
String neighbor_cell =
"cell_" + itos(id);
flecs::entity neighbor_e =
e.parent().lookup(
neighbor_cell.ascii()
.ptr());
if (!neighbor_e.is_valid()) {
outside = true;
if (id == west_id) {
e.add<WorldEditor::components::
outside_wall_west>();
e.add<WorldEditor::components::
internal_wall_west>();
} else if (id == east_id) {
e.add<WorldEditor::components::
outside_wall_east>();
e.add<WorldEditor::components::
internal_wall_east>();
} else if (id == north_id) {
e.add<WorldEditor::components::
outside_wall_north>();
e.add<WorldEditor::components::
internal_wall_north>();
} else if (id == south_id) {
e.add<WorldEditor::components::
outside_wall_south>();
e.add<WorldEditor::components::
internal_wall_south>();
}
}
}
bool border = false;
flecs::log::dbg("outside: %d", outside);
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
String neighbor_name =
"cell_" + itos(id);
flecs::entity neighbor_e =
e.parent().lookup(
neighbor_name.ascii()
.ptr());
if (!neighbor_e.is_valid())
continue;
const WorldEditor::components::buildings_layout_grid_cell
*neighbor_cell = neighbor_e.get<
WorldEditor::components::
buildings_layout_grid_cell>();
if (cell.type != neighbor_cell->type) {
border = true;
if (id == west_id)
e.add<WorldEditor::components::
internal_wall_west>();
else if (id == east_id)
e.add<WorldEditor::components::
internal_wall_east>();
else if (id == north_id)
e.add<WorldEditor::components::
internal_wall_north>();
else if (id == south_id)
e.add<WorldEditor::components::
internal_wall_south>();
}
}
if (outside) {
e.add<WorldEditor::components::
outside_wall>();
flecs::log::dbg("outside wall cell %s",
e.path().c_str());
} else
e.add<WorldEditor::components::
final_cell>();
if (border)
e.add<WorldEditor::components::border>();
print_line("outside: " + itos(outside));
print_line("position: " +
(position.operator String()));
print_line("grid size: " + itos(grid_size));
print_line("tile index: " + itos(cell.index));
});
mark_cells(it.world());
mark_doors(it.world());
it.world()
.lookup("::growth_module::GraphFilter")
.disable();
@@ -261,3 +165,472 @@ void growth_module::commit_growth_queue(flecs::world &&ecs)
buildings_layout_grid_queue>();
});
}
void growth_module::mark_cells(flecs::world &&ecs_)
{
struct queries queries(ecs_);
queries.get_mark_cells().each([](flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
flecs::entity room_e;
int grid_size =
e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
int i;
e.each<WorldEditor::components::belongs_room>(
[&room_e](flecs::entity fe) { room_e = fe; });
bool window = true;
if (room_e.is_valid()) {
int room = room_e.get<WorldEditor::components::
buildings_layout_room>()
->room_type;
flecs::log::dbg("room id: %d", room);
window = BuildingLayoutGraph::get_singleton()
->get_room_type_property(room,
"window");
flecs::log::dbg("room id: %d: window: %d", room,
window);
}
Vector2i position(cell.index % grid_size,
cell.index / grid_size);
Vector2 west(position.x - 1, position.y);
Vector2 north(position.x, position.y - 1);
Vector2 east(position.x + 1, position.y);
Vector2 south(position.x, position.y + 1);
Vector2 nw(position.x - 1, position.y - 1);
Vector2 sw(position.x - 1, position.y + 1);
Vector2 ne(position.x + 1, position.y - 1);
Vector2 se(position.x + 1, position.y + 1);
#define CELL_ID(v) (v.x + grid_size * v.y);
int west_id = CELL_ID(west);
int north_id = CELL_ID(north);
int east_id = CELL_ID(east);
int south_id = CELL_ID(south);
int nw_id = CELL_ID(nw);
int sw_id = CELL_ID(sw);
int ne_id = CELL_ID(ne);
int se_id = CELL_ID(se);
std::vector<int> neighbors = { west_id, north_id, east_id,
south_id, nw_id, sw_id,
ne_id, se_id };
std::vector<int> west_corners = { nw_id, sw_id };
std::vector<int> north_corners = { nw_id, ne_id };
std::vector<int> south_corners = { sw_id, se_id };
std::vector<int> east_corners = { ne_id, se_id };
bool outside = false;
int neighbor_flags = 0;
HashMap<int, flecs::entity> neighbor_data;
HashMap<int, bool> neighbor_flags_data;
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
String neighbor_cell = "cell_" + itos(id);
flecs::entity neighbor_e =
e.parent().lookup(neighbor_cell.ascii().ptr());
neighbor_data[id] = neighbor_e;
if (neighbor_e.is_valid()) {
neighbor_flags |= (1 << i);
neighbor_flags_data[id] = true;
}
}
int internal_corner_flags = 0;
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
if ((neighbor_flags & (1 << i)) == 0) {
outside = true;
if (id == west_id) {
e.add<WorldEditor::components::
outside_wall_west>();
e.add<WorldEditor::components::
internal_wall_west>();
if (window)
e.add<WorldEditor::components::
window_west>();
if (neighbor_flags_data.has(nw_id))
internal_corner_flags |=
WorldEditor::components::
internal_corner::
NW;
if (neighbor_flags_data.has(sw_id))
internal_corner_flags |=
WorldEditor::components::
internal_corner::
SW;
} else if (id == east_id) {
e.add<WorldEditor::components::
outside_wall_east>();
e.add<WorldEditor::components::
internal_wall_east>();
if (window)
e.add<WorldEditor::components::
window_east>();
if (neighbor_flags_data.has(ne_id))
internal_corner_flags |=
WorldEditor::components::
internal_corner::
NE;
if (neighbor_flags_data.has(se_id))
internal_corner_flags |=
WorldEditor::components::
internal_corner::
SE;
} else if (id == north_id) {
e.add<WorldEditor::components::
outside_wall_north>();
e.add<WorldEditor::components::
internal_wall_north>();
if (window)
e.add<WorldEditor::components::
window_north>();
if (neighbor_flags_data.has(nw_id))
internal_corner_flags |=
WorldEditor::components::
internal_corner::
NW;
if (neighbor_flags_data.has(ne_id))
internal_corner_flags |=
WorldEditor::components::
internal_corner::
NE;
} else if (id == south_id) {
e.add<WorldEditor::components::
outside_wall_south>();
e.add<WorldEditor::components::
internal_wall_south>();
if (window)
e.add<WorldEditor::components::
window_south>();
if (neighbor_flags_data.has(sw_id))
internal_corner_flags |=
WorldEditor::components::
internal_corner::
SW;
if (neighbor_flags_data.has(se_id))
internal_corner_flags |=
WorldEditor::components::
internal_corner::
SE;
}
}
}
if (internal_corner_flags > 0)
e.set<WorldEditor::components::internal_corner>(
{ internal_corner_flags });
bool border = false;
flecs::log::dbg("outside: %d", outside);
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
String neighbor_name = "cell_" + itos(id);
flecs::entity neighbor_e =
e.parent().lookup(neighbor_name.ascii().ptr());
if (!neighbor_e.is_valid())
continue;
const WorldEditor::components::buildings_layout_grid_cell
*neighbor_cell = neighbor_e.get<
WorldEditor::components::
buildings_layout_grid_cell>();
if (cell.type != neighbor_cell->type) {
border = true;
if (id == west_id)
e.add<WorldEditor::components::
internal_wall_west>();
else if (id == east_id)
e.add<WorldEditor::components::
internal_wall_east>();
else if (id == north_id)
e.add<WorldEditor::components::
internal_wall_north>();
else if (id == south_id)
e.add<WorldEditor::components::
internal_wall_south>();
}
}
if (outside) {
e.add<WorldEditor::components::outside_wall>();
flecs::log::dbg("outside wall cell %s",
e.path().c_str());
} else
e.add<WorldEditor::components::final_cell>();
if (border)
e.add<WorldEditor::components::border>();
print_line("outside: " + itos(outside));
print_line("position: " + (position.operator String()));
print_line("grid size: " + itos(grid_size));
print_line("tile index: " + itos(cell.index));
});
}
static float get_cell_cost(flecs::entity room_e, flecs::entity cell_e)
{
float cost = 1.0f;
if (!room_e.is_valid())
return cost;
int room = room_e.get<WorldEditor::components::buildings_layout_room>()
->room_type;
flecs::log::dbg("room id: %d", room);
bool priv =
BuildingLayoutGraph::get_singleton()->get_room_type_property(
room, "private");
flecs::log::dbg("room id: %d: private: %d", room, priv);
if (priv)
cost += 10000.0f;
if (cell_e.has<WorldEditor::components::border>())
cost += 500.0f;
if (cell_e.has<WorldEditor::components::outside_wall>())
cost += 500.0f;
return cost;
}
static int get_astar_id(Ref<AStar> &astar, int grid_size, int cell_id,
float cost)
{
int astar_id = -1;
Vector2i position(cell_id % grid_size, cell_id / grid_size);
Vector3 pos3(position.x, 0, position.y);
astar_id = astar->get_closest_point(pos3, true);
if (astar_id >= 0 &&
astar->get_point_position(astar_id).distance_squared_to(pos3) <
1.0f)
return astar_id;
astar_id = astar->get_available_point_id();
astar->add_point(astar_id, pos3, cost);
return astar_id;
}
void growth_module::mark_doors(flecs::world &&ecs_)
{
struct queries queries(ecs_);
struct mark_doors_data {
Ref<AStar> astar;
List<const struct region_tree *> regions;
Vector<Vector3> room_points;
HashMap<int, int> id2cell;
HashMap<int, flecs::entity> id2entity;
};
HashMap<flecs::entity_t, struct mark_doors_data> data;
queries.get_mark_cells().each([&data](flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
flecs::entity room_e;
int i;
int grid_size =
e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
if (!data.has(e.parent().id())) {
struct mark_doors_data mdata;
mdata.astar.instance();
const struct region_tree *rtree =
e.parent().get<region_tree>();
rtree->get_leaf_nodes(&mdata.regions);
List<const struct region_tree *>::Element *reg_E =
mdata.regions.front();
while (reg_E) {
const struct region_tree *rt = reg_E->get();
Vector2i center = rt->region.rect.get_center();
Vector3 center3(center.x, 0, center.y);
mdata.room_points.push_back(center3);
flecs::log::dbg("room_point: %s",
(center3.operator String())
.ascii()
.ptr());
reg_E = reg_E->next();
}
data[e.parent().id()] = mdata;
}
e.each<WorldEditor::components::belongs_room>(
[&room_e](flecs::entity fe) { room_e = fe; });
Vector2i position(cell.index % grid_size,
cell.index / grid_size);
Vector2 west(position.x - 1, position.y);
Vector2 north(position.x, position.y - 1);
Vector2 east(position.x + 1, position.y);
Vector2 south(position.x, position.y + 1);
int p0 = get_astar_id(data[e.parent().id()].astar, grid_size,
cell.index, get_cell_cost(room_e, e));
data[e.parent().id()].id2cell[p0] = cell.index;
data[e.parent().id()].id2entity[p0] = e;
#define CELL_ID(v) (v.x + grid_size * v.y);
int west_id = CELL_ID(west);
int north_id = CELL_ID(north);
int east_id = CELL_ID(east);
int south_id = CELL_ID(south);
std::vector<int> neighbors = { west_id, north_id, east_id,
south_id };
bool outside = false;
HashMap<int, flecs::entity> neighbor_data;
HashMap<int, bool> neighbor_flags_data;
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
String neighbor_cell = "cell_" + itos(id);
flecs::entity neighbor_e =
e.parent().lookup(neighbor_cell.ascii().ptr());
if (neighbor_e.is_valid()) {
flecs::entity neighbor_room_e;
neighbor_e.each<
WorldEditor::components::belongs_room>(
[&neighbor_room_e](flecs::entity fe) {
neighbor_room_e = fe;
});
neighbor_flags_data[id] = true;
int p1 = get_astar_id(
data[e.parent().id()].astar, grid_size,
id,
get_cell_cost(neighbor_room_e,
neighbor_e));
assert(p1 >= 0 && p0 >= 0);
data[e.parent().id()].astar->connect_points(
p0, p1, true);
data[e.parent().id()].id2cell[p1] = id;
data[e.parent().id()].id2entity[p1] =
neighbor_e;
}
}
});
List<flecs::entity_t> key_list;
data.get_key_list(&key_list);
List<flecs::entity_t>::Element *ke = key_list.front();
while (ke) {
int j, k;
int grid_size =
ecs_.entity(ke->get())
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
HashMap<flecs::entity_t, List<flecs::entity_t> > exits;
Set<flecs::entity_t> corridoor_exits;
Vector3 xdata(grid_size / 2, 0, grid_size + 1);
int p0 = data[ke->get()].astar->get_closest_point(xdata);
for (j = 0; j < data[ke->get()].room_points.size(); j++) {
int p1 = data[ke->get()].astar->get_closest_point(
data[ke->get()].room_points[j]);
PoolVector<int> path =
data[ke->get()].astar->get_id_path(p0, p1);
PoolVector<int> cell_path;
cell_path.resize(path.size());
String elements;
for (k = 0; k < path.size(); k++)
cell_path.write()[k] =
data[ke->get()].id2cell[path[k]];
for (k = 0; k < cell_path.size(); k++) {
elements += itos(cell_path[k]);
if (k < cell_path.size() - 1)
elements += ", ";
}
for (k = 0; k < cell_path.size() - 1; k++) {
int px = cell_path[k] % grid_size;
int py = cell_path[k] / grid_size;
int next_px = cell_path[k + 1] % grid_size;
int next_py = cell_path[k + 1] / grid_size;
int tx = next_px - px;
int ty = next_py - py;
Vector3 position(px, 0, py),
next_position(next_px, 0, next_py);
int point = data[ke->get()]
.astar->get_closest_point(
position, true),
point_next =
data[ke->get()]
.astar->get_closest_point(
next_position,
true);
data[ke->get()].astar->set_point_weight_scale(
point, 0.5f);
data[ke->get()].astar->set_point_weight_scale(
point_next, 0.5f);
flecs::entity room_e, next_room_e;
flecs::entity cell_e =
data[ke->get()].id2entity[path[k]];
cell_e.each<
WorldEditor::components::belongs_room>(
[&room_e](flecs::entity re) {
room_e = re;
});
flecs::entity next_cell_e =
data[ke->get()].id2entity[path[k + 1]];
next_cell_e.each<
WorldEditor::components::belongs_room>(
[&next_room_e](flecs::entity re) {
next_room_e = re;
});
if (room_e.is_valid() &&
next_room_e.is_valid()) {
if (exits.has(room_e.id()) &&
exits[room_e.id()].find(
next_room_e.id()) !=
nullptr)
continue;
if (exits.has(next_room_e.id()) &&
exits[next_room_e.id()].find(
room_e.id()) != nullptr)
continue;
exits[room_e.id()].push_back(
next_room_e.id());
exits[next_room_e.id()].push_back(
room_e.id());
} else if (room_e.is_valid()) {
if (corridoor_exits.has(room_e.id()))
continue;
corridoor_exits.insert(room_e.id());
} else if (next_room_e.is_valid()) {
if (corridoor_exits.has(
next_room_e.id()))
continue;
corridoor_exits.insert(
next_room_e.id());
}
flecs::log::dbg("path point %d: %d %d", k, tx,
ty);
assert((tx == 0 || ty == 0) &&
(tx != 0 || ty != 0));
if (tx < 0 &&
cell_e.has<WorldEditor::components::
internal_wall_west>()) {
cell_e.add<WorldEditor::components::
internal_door_west>();
next_cell_e.add<
WorldEditor::components::
internal_door_east>();
}
if (tx > 0 &&
cell_e.has<WorldEditor::components::
internal_wall_east>()) {
cell_e.add<WorldEditor::components::
internal_door_east>();
next_cell_e.add<
WorldEditor::components::
internal_door_west>();
}
if (ty < 0 &&
cell_e.has<WorldEditor::components::
internal_wall_north>()) {
cell_e.add<WorldEditor::components::
internal_door_north>();
next_cell_e.add<
WorldEditor::components::
internal_door_south>();
}
if (ty > 0 &&
cell_e.has<WorldEditor::components::
internal_wall_south>()) {
cell_e.add<WorldEditor::components::
internal_door_south>();
next_cell_e.add<
WorldEditor::components::
internal_door_north>();
}
}
flecs::log::dbg("path: %s", elements.ascii().ptr());
}
ke = ke->next();
}
}

View File

@@ -6,6 +6,8 @@
struct growth_module {
void grow_cell(flecs::entity seed_e, int id);
void commit_growth_queue(flecs::world &&world);
void mark_cells(flecs::world &&ecs_);
void mark_doors(flecs::world &&ecs_);
growth_module(flecs::world &ecs);
};

View File

@@ -1,213 +1 @@
#include "growth_regions.h"
#if 0
static void print_can_grow(int state, growth_regions &g, int index,
const char *what)
{
const growth_regions::region &region = g.regions[index];
bool can = false;
if (!strcmp(what, "square"))
can = region.can_grow_square;
else if (!strcmp(what, "rect"))
can = region.can_grow;
if (can)
flecs::log::dbg(
"state: %d: index %d: region can still grow %s %d",
state, index, what, region.remains_area);
else
flecs::log::dbg("state: %d: index %d: region can't grow %s %d",
state, index, what, region.remains_area);
if (region.can_grow_region())
flecs::log::dbg("state %d: index %d: region can still continue",
state, index);
}
bool growth_regions::grow_state0(int index, const RegionRect2i &clip)
{
bool ok = true, ret = false;
RegionRect2i mrect;
growth_regions::region &region = regions.write[index];
mrect = region.rect;
assert(check_region(index, mrect));
mrect = mrect.grow(1);
ok = clip.encloses(mrect);
// if (!ok)
// flecs::log::dbg("state: %d: index %d: out of clip area",
// 0, index);
if (ok) {
ok = check_region(index, mrect);
// if (!ok)
// flecs::log::dbg(
// "state: %d: index %d: check_region failed",
// 0, index);
}
if (ok) {
ret = region.update_region_size(mrect);
// if (!ret)
// flecs::log::dbg(
// "state: %d: index %d: update_region_size failed",
// 0, index);
}
print_can_grow(0, *this, index, "square");
// if (!ret)
// flecs::log::dbg("state %d could not grow region %d: %d",
// 0, index, region.remains_area);
// else
// flecs::log::dbg("state %d could grow region %d: %d", 0,
// index, region.remains_area);
return ret;
}
bool growth_regions::grow_state1(int index, const RegionRect2i &clip)
{
int d;
bool ret = false;
RegionRect2i mrect;
growth_regions::region &region = regions.write[index];
int count = 0;
for (d = 0; d < 4; d++) {
bool ok;
mrect = region.rect;
assert(check_region(index, mrect));
switch (d) {
case 0:
mrect.position.y -= 1;
mrect.size.y += 1;
break;
case 1:
mrect.size.y += 1;
break;
case 2:
mrect.position.x -= 1;
mrect.size.x += 1;
break;
case 3:
mrect.size.x += 1;
break;
}
ok = parent_regions[region.parent_region].rect.encloses(mrect);
if (ok)
ok = clip.encloses(mrect);
if (ok) {
ok = false;
if (mrect.size.y > 0 && mrect.size.x > 0) {
float aspect = (float)mrect.size.x /
(float)mrect.size.y;
ok = (aspect > 0.2f && aspect < 5.0f);
}
}
if (ok)
ok = check_region(index, mrect);
if (ok) {
bool result = region.update_region_size(mrect);
if (result)
count++;
}
}
if (count > 0) {
ret = true;
// flecs::log::dbg(
// "state %d could grow region %d: %d - %d out of %d times",
// 0, index, region.remains_area, count, 4);
}
print_can_grow(1, *this, index, "rect");
// if (!ret)
// flecs::log::dbg(
// "state %d could not grow region rect %d: %d", 0,
// index, region.remains_area);
return ret;
}
#endif
#if 0
void growth_regions::grow_regions(flecs::entity grid_floor_e)
{
int i;
bool grown = true;
int state = 0;
if (complete)
return;
#if 0
int grid_size = grid_floor_e
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
#endif
state = 0;
flecs::log::dbg("growing square");
while (grown) {
grown = false;
int count = 0;
for (i = 0; i < regions.size(); i++) {
growth_regions::region &region = regions.write[i];
const RegionRect2i &clip =
parent_regions[region.parent_region].rect;
RegionRect2i mrect = region.rect;
flecs::log::dbg("grow_region_rects: region %d", i);
if (!region.can_grow_region()) {
flecs::log::dbg("grow_region_rects: skip %d",
i);
continue;
}
mrect = region.rect;
bool result = false;
result = grow_state0(i, clip);
if (result)
count++;
}
if (count > 0) {
grown = true;
flecs::log::dbg("grown squares %d times of %d", count,
regions.size());
}
if (!grown)
flecs::log::dbg(
"grow_region_rects: could not grow more squares");
}
state = 1;
grown = true;
flecs::log::dbg("growing rect");
while (grown) {
grown = false;
int count = 0;
for (i = 0; i < regions.size(); i++) {
growth_regions::region &region = regions.write[i];
const RegionRect2i &clip =
parent_regions[region.parent_region].rect;
RegionRect2i mrect = region.rect;
flecs::log::dbg("grow_region_rects: region %d", i);
if (!region.can_grow_region()) {
flecs::log::dbg("grow_region_rects: skip %d",
i);
continue;
}
mrect = region.rect;
bool result = false;
result = grow_state1(i, clip);
if (result)
count++;
if (!result)
flecs::log::dbg(
"state %d could not grow region %d",
state, i);
else
flecs::log::dbg(
"state %d could grow region %d: %d",
state, i, region.remains_area);
}
if (count > 0) {
grown = true;
flecs::log::dbg("grown rects %d times of %d", count,
regions.size());
}
if (!grown)
flecs::log::dbg(
"grow_region_rects: could not grow any more rects");
}
flecs::log::dbg("grow_region_rects: complete");
complete = true;
flecs::log::dbg("grow_region_rects: %s: done",
grid_floor_e.path().c_str());
}
#endif

View File

@@ -14,6 +14,7 @@ struct region {
RegionRect2i rect;
int remains_area;
bool can_grow_square;
bool can_move;
bool can_grow;
bool complete;
bool can_grow_region() const
@@ -45,55 +46,6 @@ struct region {
struct growth_regions {
List<struct grow_job> job_list;
bool complete;
bool check_region(int index, const RegionRect2i &rect) const;
#if 0
bool check_region(int index, const RegionRect2i &rect) const
{
int i;
bool ret = true;
for (i = 0; i < regions.size(); i++) {
if (i == index)
continue;
if (rect.intersects(regions[i].rect)) {
ret = false;
flecs::log::dbg(
"%d: %s intersects %s", i,
(rect.operator String()).ascii().ptr(),
(regions[i].rect.operator String())
.ascii()
.ptr());
break;
}
}
flecs::log::dbg("check_region: %d -> %d", index, ret);
return ret;
}
#endif
bool update_region_size(int index, RegionRect2i &mrect);
#if 0
bool update_region_size(int index, RegionRect2i &mrect)
{
bool ret = false;
bool ok = check_region(index, mrect);
if (ok)
ret = regions.write[index].update_region_size(mrect);
flecs::log::dbg("update_region_size %d -> %d", index, ret);
return ret;
}
#endif
void create_region(flecs::entity floor_e, flecs::entity seed_e,
flecs::entity parent_e, flecs::entity region_e,
const Vector2i &position, float area,
int parent_index);
flecs::entity create_cell(flecs::entity floor_e, flecs::entity region_e,
int id);
flecs::entity update_cell(flecs::entity floor_e, flecs::entity parent_e,
flecs::entity region_e, int id);
void split_region(flecs::entity grid_floor_e, int region_index,
const List<Pair<flecs::entity, float> > &region_list);
void grow_regions(flecs::entity grid_floor_e);
bool grow_state0(int index, const RegionRect2i &clip);
bool grow_state1(int index, const RegionRect2i &clip);
};
#endif

View File

@@ -9,6 +9,8 @@
void region_tree::split(flecs::entity grid_floor_e,
const List<struct region> &regions)
{
assert((region.rect.size.x > 1 || region.rect.size.y > 1) &&
region.rect.get_area() > regions.size());
assert(children.size() == 0);
const region_tree *base_rtree = grid_floor_e.get<region_tree>();
const List<struct region>::Element *e = regions.front();
@@ -461,6 +463,70 @@ void region_tree::place(flecs::entity grid_floor_e) const
}
}
void region_tree::move(flecs::entity grid_floor_e)
{
struct region_tree *base_rtree = grid_floor_e.get_mut<region_tree>();
assert(base_rtree);
List<struct region_tree *> queue;
List<struct region_tree *> movables;
int count = 0;
Vector2i center;
queue.push_back(base_rtree);
while (!queue.empty()) {
int i;
struct region_tree *item = queue.front()->get();
if (item->is_a_room(grid_floor_e) && !item->region.can_grow &&
item->region.can_move) {
movables.push_back(item);
count++;
center += item->region.rect.get_center();
}
queue.pop_front();
for (i = 0; i < item->children.size(); i++)
queue.push_back(item->children[i]);
}
if (count == 0)
return;
assert(count > 0);
center /= count;
flecs::log::dbg("center: %d %d", center.x, center.y);
while (!movables.empty()) {
struct region_tree *item = movables.front()->get();
movables.pop_front();
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;
} else {
item->region.rect = backup;
item->region.can_move = false;
}
}
}
grid_floor_e.modified<region_tree>();
}
void region_tree::get_rects(List<RegionRect2i> *rect_list) const
{
List<const struct region_tree *> queue;
@@ -481,6 +547,46 @@ void region_tree::get_rects(List<RegionRect2i> *rect_list) const
}
}
void region_tree::get_leaf_nodes(
List<const struct region_tree *> *node_list) const
{
List<const struct region_tree *> 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()) {
node_list->push_back(item);
}
for (i = 0; i < (int)item->children.size(); i++)
queue.push_back(item->children[i]);
}
}
void region_tree::get_leaf_nodes(List<struct region_tree *> *node_list)
{
List<struct region_tree *> queue;
queue.push_back(this);
while (!queue.empty()) {
int i;
struct region_tree *item = queue.front()->get();
queue.pop_front();
if (item->is_leaf()) {
node_list->push_back(item);
}
for (i = 0; i < (int)item->children.size(); i++)
queue.push_back(item->children[i]);
}
}
bool region_tree::is_a_room(flecs::entity grid_floor_e) const
{
return grid_floor_e.world()
.entity(region.region_et)
.has<WorldEditor::components::buildings_layout_room>();
}
bool region_tree::check_candidate(int i, const RegionRect2i &candidate) const
{
int j;

View File

@@ -18,7 +18,11 @@ 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 move(flecs::entity grid_floor_e);
void get_rects(List<RegionRect2i> *rect_list) const;
void get_leaf_nodes(List<const struct region_tree *> *node_list) const;
void get_leaf_nodes(List<struct region_tree *> *node_list);
bool is_a_room(flecs::entity grid_floor_e) const;
private:
bool check_candidate(int i, const RegionRect2i &candidate) const;

View File

@@ -76,6 +76,9 @@ protected:
display_mi[i] = memnew(MeshInstance);
view->call_deferred("add_child", display_mi[i]);
}
ColorRect *nav = memnew(ColorRect);
view->call_deferred("add_child", nav);
nav->set_size(Vector2(100, 100));
}
void build_mesh_data()
{
@@ -127,6 +130,7 @@ protected:
Vector3(x * 4, 0, z * 4));
int matches = 0;
struct pmatch {
int check;
int mask;
String item;
Basis basis;
@@ -134,43 +138,107 @@ protected:
bool exterior;
};
struct pmatch match_data[] = {
{ 1, "outside-wall", Basis(), Vector3(0, 0, -2),
true },
{ 2, "outside-wall",
{ 1, 1 | 256, "outside-wall", Basis(),
Vector3(0, 0, -2), true },
{ 2, 2 | 512, "outside-wall",
Basis().rotated(Vector3(0, 1, 0), Math_PI),
Vector3(0, 0, 2), true },
{ 4, "outside-wall",
{ 4, 4 | 1024, "outside-wall",
Basis().rotated(Vector3(0, 1, 0),
Math_PI / 2),
Vector3(-2, 0, 0), true },
{ 8, "outside-wall",
{ 8, 8 | 2048, "outside-wall",
Basis().rotated(Vector3(0, 1, 0),
-Math_PI / 2),
Vector3(2, 0, 0), true },
{ 2 | 8, "outside-wall-corner",
{ 2 | 8, 2 | 8, "outside-wall-corner",
Basis().rotated(Vector3(0, 1, 0), Math_PI),
Vector3(2, 0, 2), true },
{ 1 | 4, "outside-wall-corner",
{ 1 | 4, 1 | 4, "outside-wall-corner",
Basis().rotated(Vector3(0, 1, 0), 0),
Vector3(-2, 0, -2), true },
{ 1 | 8, "outside-wall-corner",
{ 1 | 8, 1 | 8, "outside-wall-corner",
Basis().rotated(Vector3(0, 1, 0),
-Math_PI / 2),
Vector3(2, 0, -2), true },
{ 2 | 4, "outside-wall-corner",
{ 2 | 4, 2 | 4, "outside-wall-corner",
Basis().rotated(Vector3(0, 1, 0),
Math_PI / 2),
Vector3(-2, 0, 2), true },
{ 16, "internal-wall", Basis(),
{ 16, 16 | 256 | 4096, "internal-wall", Basis(),
Vector3(0, 0, -2), false },
{ 32, "internal-wall",
{ 32, 32 | 512 | 8192, "internal-wall",
Basis().rotated(Vector3(0, 1, 0), Math_PI),
Vector3(0, 0, 2), false },
{ 64, "internal-wall",
{ 64, 64 | 1024 | 16384, "internal-wall",
Basis().rotated(Vector3(0, 1, 0),
Math_PI / 2),
Vector3(-2, 0, 0), false },
{ 128, "internal-wall",
{ 128, 128 | 2048 | 32768, "internal-wall",
Basis().rotated(Vector3(0, 1, 0),
-Math_PI / 2),
Vector3(2, 0, 0), false },
{ 16, 16 | 256, "internal-wall-skirting",
Basis(), Vector3(0, 0, -2), false },
{ 32, 32 | 512, "internal-wall-skirting",
Basis().rotated(Vector3(0, 1, 0), Math_PI),
Vector3(0, 0, 2), false },
{ 64, 64 | 1024, "internal-wall-skirting",
Basis().rotated(Vector3(0, 1, 0),
Math_PI / 2),
Vector3(-2, 0, 0), false },
{ 128, 128 | 2048, "internal-wall-skirting",
Basis().rotated(Vector3(0, 1, 0),
-Math_PI / 2),
Vector3(2, 0, 0), false },
{ 16 | 4096, 16 | 256 | 4096, "internal-door",
Basis(), Vector3(0, 0, -2), false },
{ 32 | 8192, 32 | 512 | 8192, "internal-door",
Basis().rotated(Vector3(0, 1, 0), Math_PI),
Vector3(0, 0, 2), false },
{ 64 | 16384, 64 | 1024 | 16384,
"internal-door",
Basis().rotated(Vector3(0, 1, 0),
Math_PI / 2),
Vector3(-2, 0, 0), false },
{ 128 | 32768, 128 | 2048 | 32768,
"internal-door",
Basis().rotated(Vector3(0, 1, 0),
-Math_PI / 2),
Vector3(2, 0, 0), false },
#if 0
{ 1 | 256, 1 | 256, "external-window",
Basis().rotated(Vector3(0, 1, 0),
-Math_PI / 2),
Vector3(2, 0, 0), false },
{ 16 | 256, 16 | 256, "internal-window",
Basis().rotated(Vector3(0, 1, 0),
-Math_PI / 2),
Vector3(2, 0, 0), false }
#endif
{ 1 | 256, 1 | 256, "outside-window", Basis(),
Vector3(0, 0, -2), true },
{ 2 | 512, 2 | 512, "outside-window",
Basis().rotated(Vector3(0, 1, 0), Math_PI),
Vector3(0, 0, 2), true },
{ 4 | 1024, 4 | 1024, "outside-window",
Basis().rotated(Vector3(0, 1, 0),
Math_PI / 2),
Vector3(-2, 0, 0), true },
{ 8 | 2048, 8 | 2048, "outside-window",
Basis().rotated(Vector3(0, 1, 0),
-Math_PI / 2),
Vector3(2, 0, 0), true },
{ 16 | 256, 16 | 256, "internal-window",
Basis(), Vector3(0, 0, -2), false },
{ 32 | 512, 32 | 512, "internal-window",
Basis().rotated(Vector3(0, 1, 0), Math_PI),
Vector3(0, 0, 2), false },
{ 64 | 1024, 64 | 1024, "internal-window",
Basis().rotated(Vector3(0, 1, 0),
Math_PI / 2),
Vector3(-2, 0, 0), false },
{ 128 | 2048, 128 | 2048, "internal-window",
Basis().rotated(Vector3(0, 1, 0),
-Math_PI / 2),
Vector3(2, 0, 0), false },
@@ -191,13 +259,30 @@ protected:
matches |= 64;
if (e.has<WorldEditor::components::internal_wall_east>())
matches |= 128;
if (e.has<WorldEditor::components::window_north>())
matches |= 256;
if (e.has<WorldEditor::components::window_south>())
matches |= 512;
if (e.has<WorldEditor::components::window_west>())
matches |= 1024;
if (e.has<WorldEditor::components::window_east>())
matches |= 2048;
if (e.has<WorldEditor::components::internal_door_north>())
matches |= 4096;
if (e.has<WorldEditor::components::internal_door_south>())
matches |= 8192;
if (e.has<WorldEditor::components::internal_door_west>())
matches |= 16384;
if (e.has<WorldEditor::components::internal_door_east>())
matches |= 32768;
for (i = 0; i < 2; i++)
item_data[i].items.clear();
for (i = 0; i < (int)sizeof(match_data) /
(int)sizeof(match_data[0]);
i++) {
int check = match_data[i].check;
int mask = match_data[i].mask;
if ((matches & mask) == mask) {
if ((matches & mask) == check) {
int id =
layout_parts->find_item_by_name(
match_data[i].item);

View File

@@ -127,10 +127,27 @@ public:
struct outside_wall_west {};
struct outside_wall_north {};
struct outside_wall_south {};
struct window_east {};
struct window_west {};
struct window_north {};
struct window_south {};
struct internal_door_east {};
struct internal_door_west {};
struct internal_door_north {};
struct internal_door_south {};
struct internal_wall_east {};
struct internal_wall_west {};
struct internal_wall_north {};
struct internal_wall_south {};
struct internal_corner {
enum {
NW = (1 << 0),
NE = (1 << 1),
SE = (1 << 2),
SW = (1 << 3),
};
int flags;
};
struct corridoor {};
struct buildings_layout_grid_floor {
Set<int> cells;