Added region_tree tests

This commit is contained in:
2024-11-25 15:34:42 +03:00
parent fe876fccca
commit 40183a44a7
20 changed files with 8899 additions and 116 deletions

View File

@@ -3,6 +3,9 @@
#include "world_editor.h"
#include "editor_event.h"
#include "building_layout_graph.h"
#include "grid_misc.h"
#include "grow_job.h"
#include "growth_regions.h"
#include "graph_module.h"
#define MIN_ROOM_SIZE 16 /* 4 * 4 tiles */
@@ -207,6 +210,14 @@ void BuildingLayoutGraph::graph_module::grow_cell(flecs::entity seed_e, int id)
c_e.add<WorldEditor::components::belongs>(
second);
});
int mcount = 0;
seed_e.each<WorldEditor::components::belongs_room>(
[&c_e, &mcount](flecs::entity second) {
assert(mcount == 0);
c_e.add<WorldEditor::components::belongs_room>(
second);
mcount++;
});
floor_e.get_mut<WorldEditor::components::
buildings_layout_grid_floor>()
->size_left--;
@@ -256,15 +267,17 @@ void BuildingLayoutGraph::graph_module::create_floor_components(
assert(!floor_e.has<growth_regions>());
floor_e.set<WorldEditor::components::buildings_layout_grid_floor>(
{ Set<int>(), size.grid_size, size.growth_size });
floor_e.set<growth_regions>(
{ Vector<struct growth_regions::region>(), false });
floor_e.set<growth_regions>({ List<struct grow_job>(), false });
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)
const Vector2i &position, float area,
int parent_index)
{
int i;
struct growth_regions::region r;
@@ -277,6 +290,13 @@ void growth_regions::create_region(flecs::entity floor_e, flecs::entity seed_e,
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>();
@@ -300,9 +320,11 @@ void growth_regions::create_region(flecs::entity floor_e, flecs::entity seed_e,
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>()
@@ -310,8 +332,11 @@ flecs::entity growth_regions::create_cell(flecs::entity floor_e,
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>()
@@ -323,16 +348,178 @@ flecs::entity growth_regions::create_cell(flecs::entity floor_e,
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;
}
bool BuildingLayoutGraph::graph_module::check_region(flecs::entity floor_e,
int index,
const Rect2i &rect) const
flecs::entity growth_regions::update_cell(flecs::entity floor_e,
flecs::entity parent_e,
flecs::entity region_e, int id)
{
const growth_regions *g = floor_e.get<growth_regions>();
return g->check_region(index, rect);
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 BuildingLayoutGraph::graph_module::zones_graph_module(
flecs::world &ecs, const String &module_name)
{
@@ -451,7 +638,8 @@ void BuildingLayoutGraph::graph_module::zones_graph_module(
buildings_layout_floor_index
&rindex) {
if (index.index == rindex.index) {
sum += MAX(rarea.area, MIN_ROOM_SIZE);
sum += MAX(rarea.area, MIN_ROOM_SIZE) *
10 / 8;
assert(sum >= 0.0f);
count_rooms++;
}
@@ -567,6 +755,7 @@ BuildingLayoutGraph::graph_module::graph_module(flecs::world &ecs)
ecs.component<WorldEditor::components::buildings_layout_order>()
.member<int>("index");
ecs.component<WorldEditor::components::belongs>();
ecs.component<WorldEditor::components::belongs_room>();
#if 0
ecs.component<
WorldEditor::components::buildings_layout_commands::command>()
@@ -1072,10 +1261,11 @@ BuildingLayoutGraph::graph_module::graph_module(flecs::world &ecs)
->get_layout_grid_base();
flecs::entity grid_e =
grid_base_e.lookup(graph_e.name());
flecs::log::warn("deleting entity %s",
grid_e.path().c_str());
if (grid_e.is_valid())
if (grid_e.is_valid()) {
flecs::log::warn("deleting entity %s",
grid_e.path().c_str());
grid_e.destruct();
}
it.world().defer_resume();
});
ecs.system<const WorldEditor::components::buildings_layout_grid_size>(

View File

@@ -1,87 +1,235 @@
#ifndef GRAPH_MODULE_H_
#define GRAPH_MODULE_H_
struct growth_regions {
struct region {
flecs::entity_t parent;
flecs::entity_t seed_et;
flecs::entity_t region_et;
Rect2i rect;
int remains_area;
bool can_grow_square;
bool can_grow;
bool complete;
bool can_grow_region() const
{
bool ret = can_grow;
if (remains_area <= 0)
ret = false;
return ret;
#include <core/math/vector2.h>
#include "grid_misc.h"
#include "grow_job.h"
struct RegionRect2i {
Point2i position;
Size2i size;
const Point2i &get_position() const
{
return position;
}
void set_position(const Point2i &p_position)
{
position = p_position;
}
const Size2i &get_size() const
{
return size;
}
void set_size(const Size2i &p_size)
{
size = p_size;
}
int get_area() const
{
return size.width * size.height;
}
_FORCE_INLINE_ Vector2i get_center() const
{
return position + (size / 2);
}
inline bool intersects(const RegionRect2i &p_rect) const
{
if (position.x > (p_rect.position.x + p_rect.size.width - 1)) {
return false;
}
bool update_region_size(Rect2i &mrect)
{
bool ret = false;
int old_area = rect.get_area();
int new_area = mrect.get_area();
int area_diff = new_area - old_area;
if (area_diff > 0) {
rect = mrect;
remains_area -= area_diff;
ret = true;
}
if (remains_area <= 0) {
can_grow_square = false;
can_grow = false;
}
flecs::log::dbg("update_region_size %d -> %d",
area_diff, ret);
return ret;
if ((position.x + size.width - 1) < p_rect.position.x) {
return false;
}
if (position.y > (p_rect.position.y + p_rect.size.height - 1)) {
return false;
}
if ((position.y + size.height - 1) < p_rect.position.y) {
return false;
}
return true;
}
inline bool encloses(const RegionRect2i &p_rect) const
{
return (p_rect.position.x >= position.x) &&
(p_rect.position.y >= position.y) &&
((p_rect.position.x + p_rect.size.x) <=
(position.x + size.x)) &&
((p_rect.position.y + p_rect.size.y) <=
(position.y + size.y));
}
_FORCE_INLINE_ bool has_no_area() const
{
return (size.x <= 0 || size.y <= 0);
}
inline RegionRect2i clip(const RegionRect2i &p_rect) const
{ /// return a clipped rect
RegionRect2i new_rect = p_rect;
if (!intersects(new_rect)) {
return RegionRect2i();
}
new_rect.position.x = MAX(p_rect.position.x, position.x);
new_rect.position.y = MAX(p_rect.position.y, position.y);
Point2 p_rect_end = p_rect.position + p_rect.size;
Point2 end = position + size;
new_rect.size.x =
(int)(MIN(p_rect_end.x, end.x) - new_rect.position.x);
new_rect.size.y =
(int)(MIN(p_rect_end.y, end.y) - new_rect.position.y);
return new_rect;
}
inline RegionRect2i merge(const RegionRect2i &p_rect) const
{ ///< return a merged rect
RegionRect2i new_rect;
new_rect.position.x = MIN(p_rect.position.x, position.x);
new_rect.position.y = MIN(p_rect.position.y, position.y);
new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x,
position.x + size.x);
new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y,
position.y + size.y);
new_rect.size =
new_rect.size - new_rect.position; //make relative again
return new_rect;
};
Vector<struct region> regions;
bool complete;
bool check_region(int index, const Rect2i &rect) const
bool has_point(const Point2 &p_point) 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;
break;
}
if (p_point.x < position.x) {
return false;
}
flecs::log::dbg("check_region: %d -> %d", index, ret);
return ret;
if (p_point.y < position.y) {
return false;
}
if (p_point.x >= (position.x + size.x)) {
return false;
}
if (p_point.y >= (position.y + size.y)) {
return false;
}
return true;
}
bool update_region_size(int index, Rect2i &mrect)
bool operator==(const RegionRect2i &p_rect) const
{
return position == p_rect.position && size == p_rect.size;
}
bool operator!=(const RegionRect2i &p_rect) const
{
return position != p_rect.position || size != p_rect.size;
}
RegionRect2i grow(int p_by) const
{
RegionRect2i g = *this;
g.position.x -= p_by;
g.position.y -= p_by;
g.size.width += p_by * 2;
g.size.height += p_by * 2;
return g;
}
inline RegionRect2i grow_margin(Margin p_margin, int p_amount) const
{
RegionRect2i g = *this;
g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0,
(MARGIN_TOP == p_margin) ? p_amount : 0,
(MARGIN_RIGHT == p_margin) ? p_amount : 0,
(MARGIN_BOTTOM == p_margin) ? p_amount :
0);
return g;
}
inline RegionRect2i grow_individual(int p_left, int p_top, int p_right,
int p_bottom) const
{
RegionRect2i g = *this;
g.position.x -= p_left;
g.position.y -= p_top;
g.size.width += p_left + p_right;
g.size.height += p_top + p_bottom;
return g;
}
_FORCE_INLINE_ RegionRect2i expand(const Vector2i &p_vector) const
{
RegionRect2i r = *this;
r.expand_to(p_vector);
return r;
}
inline void expand_to(const Point2i &p_vector)
{
Point2i begin = position;
Point2i end = position + size;
if (p_vector.x < begin.x) {
begin.x = p_vector.x;
}
if (p_vector.y < begin.y) {
begin.y = p_vector.y;
}
if (p_vector.x > end.x) {
end.x = p_vector.x;
}
if (p_vector.y > end.y) {
end.y = p_vector.y;
}
position = begin;
size = end - begin;
}
operator String() const
{
return String(position) + ", " + String(size);
}
operator Rect2() const
{
return Rect2(position, size);
}
RegionRect2i(const Rect2 &p_r2)
: position(p_r2.position)
, size(p_r2.size)
{
}
RegionRect2i(const Rect2i &p_r2)
: position(p_r2.position)
, size(p_r2.size)
{
}
RegionRect2i()
{
}
RegionRect2i(int p_x, int p_y, int p_width, int p_height)
: position(Point2(p_x, p_y))
, size(Size2(p_width, p_height))
{
}
RegionRect2i(const Point2 &p_pos, const Size2 &p_size)
: position(p_pos)
, size(p_size)
{
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;
}
void create_region(flecs::entity floor_e, flecs::entity seed_e,
flecs::entity parent_e, flecs::entity region_e,
const Vector2i &position, float area);
flecs::entity create_cell(flecs::entity floor_e, flecs::entity region_e,
int id);
};
struct make_random {
int seed;
int next;
make_random(int seed)
: seed(seed)
, next(seed)
{
}
int get()
{
next = next * 1103515245 + 12345;
return (int)((unsigned)next >> 16) % 32768;
}
};
#endif

View File

@@ -0,0 +1,477 @@
#undef NDEBUG
#include <cassert>
#include <core/ustring.h>
#include <core/list.h>
#include "region_tree.h"
void region_tree::split(const List<struct region> &regions)
{
assert(children.size() == 0);
const List<struct region>::Element *e = regions.front();
while (e) {
struct region_tree *child = memnew(struct region_tree);
child->parent = this;
child->region = e->get();
children.push_back(child);
e = e->next();
}
}
const region_tree *region_tree::find(flecs::entity_t which) const
{
int i;
List<const struct region_tree *> queue;
queue.push_back(this);
while (!queue.empty()) {
const struct region_tree *item = queue.front()->get();
if (item->region.region_et == which)
return item;
queue.pop_front();
for (i = 0; i < item->children.size(); i++)
queue.push_back(item->children[i]);
}
return nullptr;
}
region_tree *region_tree::find(flecs::entity_t which)
{
int i;
List<struct region_tree *> queue;
queue.push_back(this);
while (!queue.empty()) {
struct region_tree *item = queue.front()->get();
if (item->region.region_et == which)
return item;
queue.pop_front();
for (i = 0; i < item->children.size(); i++)
queue.push_back(item->children[i]);
}
return nullptr;
}
void region_tree::dump(flecs::entity grid_floor_e) const
{
List<Pair<int, const struct region_tree *> > queue;
queue.push_back({ 0, this });
flecs::log::warn("tree dump:");
while (!queue.empty()) {
int tabs = queue.front()->get().first;
const struct region_tree *item = queue.front()->get().second;
queue.pop_front();
String stabs = "\t";
int i;
for (i = 0; i < tabs; i++)
stabs += "\t";
flecs::log::warn("%sregion: %s", stabs.ascii().ptr(),
grid_floor_e.world()
.entity(item->region.region_et)
.path()
.c_str());
flecs::log::warn(
"%srect: %s", stabs.ascii().ptr(),
(item->region.rect.operator String()).ascii().ptr());
flecs::log::warn("");
for (i = 0; i < item->children.size(); i++)
queue.push_back({ tabs + 1, item->children[i] });
}
}
void region_tree::grow()
{
#ifndef TESTS
List<struct region_tree *> grow_list;
List<struct region_tree *> queue;
List<struct region_tree *>::Element *e, *e1;
if (region.complete)
queue.push_back(this);
while (!queue.empty()) {
int i;
struct region_tree *item = queue.front()->get();
queue.pop_front();
if (item->region.can_grow || item->region.can_grow_square)
continue;
for (i = 0; i < (int)item->children.size(); i++) {
if (item->children[i]->region.can_grow)
grow_list.push_back(item->children[i]);
queue.push_back(item->children[i]);
}
}
flecs::log::warn("grow list: %d", grow_list.size());
e = grow_list.front();
int amount = 0;
while (e) {
struct region_tree *item = e->get();
flecs::log::warn(
"item: %s",
(item->region.rect.operator String()).ascii().ptr());
if (!item->region.can_grow) {
e = e->next();
flecs::log::err("can't grow");
continue;
}
RegionRect2i candidate = item->region.rect.grow(1);
e1 = grow_list.front();
bool ok = true;
while (e1) {
struct region_tree *check_item = e1->get();
if (item != check_item) {
flecs::log::warn("check item: %s candidate: %s",
(check_item->region.rect
.operator String())
.ascii()
.ptr(),
(candidate.operator String())
.ascii()
.ptr());
if (!check_item->check_candidate(candidate)) {
ok = false;
flecs::log::err("check failed");
break;
}
}
e1 = e1->next();
}
if (ok) {
item->update_candidate(candidate);
amount++;
} else {
flecs::log::err("can't update candidate");
}
e = e->next();
}
#if 0
assert(false);
if (region.complete)
queue.push_back(this);
while (!queue.empty()) {
struct region_tree *item = queue.front()->get();
queue.pop_front();
if (item->region.can_grow || item->region.can_grow_square)
continue;
int i, j;
int amount = 0;
amount = 0;
for (i = 0; i < (int)item->children.size(); i++) {
if (item->children[i]->region.can_grow_square) {
RegionRect2i candidate =
item->children[i]->region.rect.grow(1);
if (!item->region.rect.encloses(candidate)) {
item->children.write[i]
->region.can_grow_square =
false;
continue;
}
bool ok = item->check_candidate(i, candidate);
if (ok) {
item->children.write[i]
->update_candidate(candidate);
amount++;
} else
item->children.write[i]
->region.can_grow_square =
false;
}
}
if (amount > 0) /* try again later */
queue.push_back(item);
#if 0
for (i = 0; i < (int)item->children.size(); i++) {
if (!can_grow_square)
item->children.write[i]
->region.can_grow_square =
false;
}
while (can_grow) {
amount = 0;
for (i = 0; i < (int)item->children.size();
i++) {
if (!item->children[i]->region.can_grow)
continue;
int orig_area =
item->children[i]
->region.rect.get_area();
RegionRect2i candidate =
item->children[i]->region.rect;
candidate.size.x += 1;
if (!item->region.rect.encloses(
candidate))
continue;
bool ok = item->check_candidate(
i, candidate);
if (ok) {
item->children.write[i]
->update_candidate(
candidate);
amount++;
}
}
for (i = 0; i < (int)item->children.size();
i++) {
if (!item->children[i]->region.can_grow)
continue;
int orig_area =
item->children[i]
->region.rect.get_area();
RegionRect2i candidate =
item->children[i]->region.rect;
candidate.size.x += 1;
candidate.position.x -= 1;
if (!item->region.rect.encloses(
candidate))
continue;
bool ok = item->check_candidate(
i, candidate);
if (ok) {
item->children.write[i]
->update_candidate(
candidate);
amount++;
}
}
for (i = 0; i < (int)item->children.size();
i++) {
if (!item->children[i]->region.can_grow)
continue;
int orig_area =
item->children[i]
->region.rect.get_area();
RegionRect2i candidate =
item->children[i]->region.rect;
candidate.size.y += 1;
if (!item->region.rect.encloses(
candidate))
continue;
bool ok = item->check_candidate(
i, candidate);
if (ok) {
item->children.write[i]
->update_candidate(
candidate);
amount++;
}
}
for (i = 0; i < (int)item->children.size();
i++) {
if (!item->children[i]->region.can_grow)
continue;
int orig_area =
item->children[i]
->region.rect.get_area();
RegionRect2i candidate =
item->children[i]->region.rect;
candidate.size.y += 1;
candidate.position.y -= 1;
if (!item->region.rect.encloses(
candidate))
continue;
bool ok = item->check_candidate(
i, candidate);
if (ok) {
item->children.write[i]
->update_candidate(
candidate);
amount++;
}
}
for (i = 0; i < (int)item->children.size();
i++) {
if (item->children[i]
->region.remains_area <
-100) {
item->children[i]
->region.can_grow =
false;
item->children[i]
->region.complete =
true;
}
}
if (amount == 0)
can_grow = false;
}
#endif
for (i = 0; i < (int)item->children.size(); i++) {
queue.push_back(item->children[i]);
}
break;
}
#endif
#endif
}
void region_tree::place(flecs::entity grid_floor_e) const
{
#ifndef TESTS
int i, j;
List<const struct region_tree *> queue;
int grid_size = grid_floor_e
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
for (i = region.rect.position.x;
i < region.rect.position.x + region.rect.size.x; i++)
for (j = region.rect.position.y;
j < region.rect.position.y + region.rect.size.y; j++) {
int cell_id = i + grid_size * j;
String cname = "cell_" + itos(cell_id);
flecs::entity cell_e =
grid_floor_e.lookup(cname.ascii().ptr());
if (cell_e.is_valid())
cell_e.destruct();
}
queue.push_back(this);
while (!queue.empty()) {
const struct region_tree *item = queue.front()->get();
queue.pop_front();
if (item->is_leaf()) {
const RegionRect2i &rect = item->region.rect;
for (i = rect.position.x;
i < rect.position.x + rect.size.x; i++)
for (j = rect.position.x;
j < rect.position.x + rect.size.x; j++) {
int cell_id = i + grid_size * j;
update_cell(grid_floor_e,
item->region.parent,
item->region.region_et,
cell_id);
}
}
for (i = 0; i < (int)item->children.size(); i++) {
queue.push_back(item->children[i]);
}
}
#endif
}
void region_tree::get_rects(List<RegionRect2i> *rect_list) const
{
#ifndef TESTS
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->children.size() == 0) {
flecs::log::warn("rect: %s",
(item->region.rect.operator String())
.ascii()
.ptr());
rect_list->push_back(item->region.rect);
}
for (i = 0; i < (int)item->children.size(); i++)
queue.push_back(item->children[i]);
}
#endif
}
bool region_tree::check_candidate(int i, const RegionRect2i &candidate) const
{
int j;
bool ok = true;
#ifndef TESTS
if (!region.rect.encloses(candidate))
return false;
for (j = 0; j < children.size(); j++) {
if (i == j)
continue;
if (candidate.intersects(children[j]->region.rect)) {
ok = false;
break;
}
if (candidate.encloses(children[j]->region.rect)) {
ok = false;
break;
}
if (children[j]->region.rect.encloses(candidate)) {
ok = false;
break;
}
if (children[j]->region.rect.intersects(candidate)) {
ok = false;
break;
}
}
#endif
return ok;
}
bool region_tree::check_candidate(const RegionRect2i &candidate) const
{
bool ok = true;
#ifndef TESTS
if (parent && !parent->region.rect.encloses(candidate))
return false;
if (candidate.intersects(region.rect))
ok = false;
if (candidate.encloses(region.rect))
ok = false;
if (region.rect.encloses(candidate))
ok = false;
if (region.rect.intersects(candidate))
ok = false;
#endif
return ok;
}
flecs::entity region_tree::update_cell(flecs::entity grid_floor_e,
flecs::entity_t parent_et,
flecs::entity_t region_et, int id) const
{
flecs::entity region_e = grid_floor_e.world().entity(region_et);
flecs::entity parent_e = grid_floor_e.world().entity(parent_et);
flecs::log::dbg("create_cell: %s %d", region_e.path().c_str(), id);
#ifndef TESTS
String pname("cell_" + itos(id));
flecs::entity cell_e = grid_floor_e.lookup(pname.ascii().ptr());
if (!cell_e.is_valid()) {
flecs::log::warn("creating new cell %s", pname.ascii().ptr());
cell_e = grid_floor_e.world()
.entity(pname.ascii().ptr())
.child_of(grid_floor_e);
assert(cell_e.is_valid());
}
// assert(cell_e.has<WorldEditor::components::belongs>(parent_e));
/* already there */
grid_floor_e
.get_mut<WorldEditor::components::buildings_layout_grid_floor>()
->cells.insert(id);
grid_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);
}
#else
flecs::entity cell_e;
#endif
return cell_e;
}
void region_tree::update_candidate(const RegionRect2i &candidate)
{
#if 0
int orig_area = region.rect.get_area();
region.rect = candidate;
int new_area = candidate.get_area();
int avalue = MAX(0, new_area - orig_area);
region.remains_area -= avalue;
#endif
}

View File

@@ -0,0 +1,29 @@
/* ~/godot-projects/streaming_world/src/modules/stream/ui/region_tree.h */
#ifndef REGION_TREE_H_
#define REGION_TREE_H_
#include "growth_regions.h"
struct region_tree {
struct region region;
Vector<struct region_tree *> children;
struct region_tree *parent;
void split(const List<struct region> &regions);
const struct region_tree *find(flecs::entity_t which) const;
struct region_tree *find(flecs::entity_t which);
bool is_leaf() const
{
return children.size() == 0;
}
void dump(flecs::entity grid_floor_e) const;
void grow();
void place(flecs::entity grid_floor_e) const;
void get_rects(List<RegionRect2i> *rect_list) const;
private:
bool check_candidate(int i, const RegionRect2i &candidate) const;
bool check_candidate(const RegionRect2i &candidate) const;
flecs::entity update_cell(flecs::entity grid_floor_e,
flecs::entity_t parent_et,
flecs::entity_t region_et, int id) const;
void update_candidate(const RegionRect2i &candidate);
};
#endif // REGION_TREE_H_