Added region_tree tests
This commit is contained in:
@@ -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> > ®ion_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>(
|
||||
|
||||
@@ -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
|
||||
477
src/modules/stream/ui/region_tree.cpp
Normal file
477
src/modules/stream/ui/region_tree.cpp
Normal 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> ®ions)
|
||||
{
|
||||
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
|
||||
}
|
||||
29
src/modules/stream/ui/region_tree.h
Normal file
29
src/modules/stream/ui/region_tree.h
Normal 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> ®ions);
|
||||
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_
|
||||
Reference in New Issue
Block a user