Files
streaming_world/src/modules/stream/ui/grow_job.cpp
2024-12-02 16:32:52 +03:00

630 lines
18 KiB
C++

#include "base_data.h"
#include "world_editor.h"
#include "grid_misc.h"
#include "graph_module.h"
#include "queries.h"
#include "region_tree.h"
#include "grow_job.h"
static inline int get_floor_index(flecs::entity e)
{
return e.get<WorldEditor::components::buildings_layout_floor_index>()
->index;
}
static inline flecs::entity get_grid_floor(flecs::entity grid_e,
flecs::entity graph_floor_e)
{
assert(grid_e.is_valid());
assert(graph_floor_e.is_valid());
int floor_index = get_floor_index(graph_floor_e);
String floor_name = "floor_" + itos(floor_index);
// flecs::log::dbg("floor: %s", floor_name.ascii().ptr());
flecs::entity floor_e = grid_e.lookup(floor_name.ascii().ptr());
assert(floor_e.is_valid());
return floor_e;
}
grow_job_queue::grow_job_queue(
flecs::entity grid_e, struct subregions &subregions,
const WorldEditor::components::buildings_layout_grid_size &size,
const String &module_name)
: grid_e(grid_e)
, grid_size(size.grid_size)
, subregions(subregions)
, module_name(module_name)
{
const List<Pair<int, flecs::entity_t> >::Element *me;
List<Pair<flecs::entity_t, flecs::entity_t> > job_create_queue;
me = size.floors.front();
while (me) {
// graph entity
job_create_queue.push_back(
{ me->get().second, me->get().second });
flecs::entity_t base_floor_et =
job_create_queue.front()->get().second;
flecs::entity base_floor_e =
grid_e.world().entity(base_floor_et);
flecs::entity grid_floor_e =
get_grid_floor(grid_e, base_floor_e);
grid_floor_e.get_mut<growth_regions>()->job_list =
List<grow_job>();
me = me->next();
}
while (!job_create_queue.empty()) {
// graph entity
flecs::entity_t et = job_create_queue.front()->get().first;
// parent graph entity
flecs::entity_t base_floor_et =
job_create_queue.front()->get().second;
job_create_queue.pop_front();
flecs::entity base_floor_e =
grid_e.world().entity(base_floor_et);
flecs::log::dbg("job_queue: base_floor: %s",
base_floor_e.path().c_str());
flecs::entity grid_floor_e =
get_grid_floor(grid_e, base_floor_e);
flecs::log::dbg("job_queue: grid_floor: %s",
grid_floor_e.path().c_str());
assert(!subregions.sub_subregions.empty());
if (subregions.sub_subregions.has(et) &&
!subregions.sub_subregions[et].empty()) {
flecs::log::dbg(
"subregions for: %s",
grid_e.world().entity(et).path().c_str());
struct grow_job job;
if (grid_floor_e.get<growth_regions>()->job_list.empty())
job.job_type = grow_job::INITIAL;
else
job.job_type = grow_job::COMMON;
job.parent_id = et;
job.base_floor_id = base_floor_et;
job.grid_floor_id = grid_floor_e.id();
job.subregions =
subregions.sub_subregions[job.parent_id];
grid_floor_e.get_mut<growth_regions>()
->job_list.push_back(job);
List<Pair<flecs::entity, float> >::Element *se =
job.subregions.front();
while (se) {
job_create_queue.push_back(
{ se->get().first.id(),
base_floor_et });
se = se->next();
}
grid_floor_e.modified<growth_regions>();
} else
flecs::log::dbg(
"no subregions for: %s",
grid_e.world().entity(et).path().c_str());
}
}
/* 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());
flecs::log::dbg("create: grid_floor: %s", grid_floor_e.path().c_str());
growth_regions *g = grid_floor_e.get_mut<growth_regions>();
RegionRect2i clip_rect(1, 1, grid_size - 2, grid_size - 2);
const List<Pair<flecs::entity, float> > &subregions = job->subregions;
List<struct region> initial_regions;
if (subregions.size() == 0) {
flecs::log::err("nothing to do");
return;
}
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 },
Vector<struct region_tree *>(),
nullptr });
struct region_tree *rtree = grid_floor_e.get_mut<region_tree>();
create_region_list(rtree, subregions, initial_regions);
grid_floor_e.modified<region_tree>();
grid_floor_e.get_mut<region_tree>()->split(grid_floor_e,
initial_regions);
assert(rtree->check(grid_floor_e));
grid_floor_e.modified<region_tree>();
grid_floor_e.get<region_tree>()->dump(grid_floor_e);
grid_floor_e.get_mut<region_tree>()->grow(grid_floor_e, true);
grid_floor_e.modified<region_tree>();
grid_floor_e.get<region_tree>()->dump(grid_floor_e);
// grid_floor_e.get<region_tree>()->place(grid_floor_e);
List<RegionRect2i> rects;
List<RegionRect2i>::Element *e, *e1;
grid_floor_e.get<region_tree>()->get_rects(&rects);
e = rects.front();
bool ok = true;
while (e) {
e1 = rects.front();
while (e1) {
if (e->get() == e1->get()) {
e1 = e1->next();
continue;
}
if (e->get().intersects(e1->get()))
ok = false;
if (e->get().encloses(e1->get()))
ok = false;
if (e1->get().intersects(e->get()))
ok = false;
if (e1->get().encloses(e->get()))
ok = false;
if (!ok)
break;
e1 = e1->next();
}
e = e->next();
}
assert(rtree->check(grid_floor_e));
}
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);
flecs::log::dbg("create: base_floor: %s", base_floor_e.path().c_str());
flecs::log::dbg("create: grid_floor: %s", grid_floor_e.path().c_str());
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;
List<struct region> region_list;
base_rtree->dump(grid_floor_e);
flecs::log::warn("search for: %s %lx", parent_e.path().c_str(),
job->parent_id);
rtree = base_rtree->find(job->parent_id);
if (!rtree) {
g->job_list.push_back(*job);
flecs::log::warn("delay job fo %s (%d jobs)",
parent_e.path().c_str(), g->job_list.size());
return;
}
create_region_list(rtree, subregions, region_list);
assert(base_rtree->check(grid_floor_e));
rtree->split(grid_floor_e, region_list);
assert(base_rtree->check(grid_floor_e));
grid_floor_e.modified<region_tree>();
rtree->dump(grid_floor_e);
assert(base_rtree->check(grid_floor_e));
rtree->grow(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);
}
void grow_job_queue::commit_common_queue()
{
grid_e.world()
.query_builder<
WorldEditor::components::buildings_layout_grid_floor,
WorldEditor::components::buildings_layout_grid_queue>()
.each([this](flecs::entity e,
WorldEditor::components::buildings_layout_grid_floor
&fl,
WorldEditor::components::buildings_layout_grid_queue
&queue) {
List<Pair<flecs::entity_t, int> >::Element *me =
queue.queue.front();
while (me) {
flecs::entity seed_e =
e.world().entity(me->get().first);
int id = me->get().second;
if (!fl.cells.has(id)) {
flecs::log::err("bad cell %d", id);
assert(false);
}
// fl.cells.insert(id);
flecs::entity floor_e = seed_e.parent();
String c_name = "cell_" + itos(id);
flecs::entity c_e =
floor_e.lookup(c_name.ascii().ptr());
if (c_e.is_valid() &&
c_e.has<WorldEditor::components::
buildings_layout_grid_cell>()) {
// flecs::log::dbg("cell: %s: %s",
// e.path().c_str(),
// c_e.path().c_str());
String type =
seed_e.get<WorldEditor::components::
buildings_layout_grid_cell>()
->type;
c_e.set<WorldEditor::components::
buildings_layout_grid_cell>(
{ type, id });
seed_e.each<
WorldEditor::components::belongs>(
[&c_e](flecs::entity second) {
c_e.add<WorldEditor::components::
belongs>(
second);
});
seed_e.each<WorldEditor::components::
belongs_room>(
[&c_e](flecs::entity second) {
c_e.add<WorldEditor::components::
belongs_room>(
second);
});
floor_e.modified<
WorldEditor::components::
buildings_layout_grid_floor>();
} else {
flecs::log::err("bad cell %s",
c_name.ascii().ptr());
assert(false);
}
me = me->next();
}
queue.queue.clear();
e.remove<WorldEditor::components::
buildings_layout_grid_queue>();
});
}
void grow_job_queue::create_region_list(
region_tree *rtree, const List<Pair<flecs::entity, float> > &subregions,
List<struct region> &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;
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;
if (positions.empty()) {
int target_distance =
(int)(Math::sqrt(fe->get().second) * 0.7f) + 1;
positions.push_back(current_position);
distances.push_back(target_distance);
regions.push_back(fe->get().first);
areas.push_back(fe->get().second);
fe = fe->next();
if (!fe)
break;
}
for (i = 0; i < (int)positions.size(); i++) {
int which = r.get() % 12;
switch (which) {
case 1:
velocity = { 0, 1 };
break;
case 3:
velocity = { 1, 0 };
break;
case 5:
velocity = { 0, -1 };
break;
case 7:
velocity = { -1, 0 };
break;
}
if (clip_rect.has_point(current_position + velocity)) {
position_candidates.push_back(current_position +
velocity);
current_position += velocity;
}
}
int target_distance =
(int)(Math::sqrt(fe->get().second) * 0.7f) + 1;
assert(fe);
if (bad_count > 100)
target_distance = 1;
bool any_match = false;
for (i = 0; i < position_candidates.size(); i++) {
bool bad = false;
assert(fe);
for (j = 0; j < (int)positions.size(); j++) {
Vector2i l =
position_candidates[i] - positions[j];
int distance =
l.x * l.x + l.y * l.y - distances[j];
if (distance < target_distance) {
bad = true;
break;
}
}
assert(fe);
if (!bad) {
assert(fe);
positions.push_back(position_candidates[i]);
distances.push_back(target_distance);
regions.push_back(fe->get().first);
areas.push_back(fe->get().second);
any_match = true;
bad_count = 0;
if (fe) {
fe = fe->next();
if (fe)
target_distance =
(int)(Math::sqrt(
fe->get()
.second) *
0.7f) +
1;
}
}
if (!fe)
break;
}
if (!any_match) {
flecs::log::err(
"No match found: %s: %s",
(clip_rect.operator String()).ascii().ptr(),
(current_position.operator String())
.ascii()
.ptr());
bad_count++;
}
if (bad_count >= 100) {
position_candidates.clear();
int x, y;
for (x = clip_rect.position.x;
x < clip_rect.position.x + clip_rect.size.x; x++)
for (y = clip_rect.position.y;
y <
clip_rect.position.y + clip_rect.size.y;
y++) {
position_candidates.push_back(
Vector2i(x, y));
}
bad_count = 0;
for (i = 0; i < position_candidates.size(); i++) {
bool bad = false;
assert(fe);
for (j = 0; j < (int)positions.size(); j++) {
Vector2i l = position_candidates[i] -
positions[j];
int distance = l.x * l.x + l.y * l.y -
distances[j];
if (distance > 0) {
bad = true;
break;
}
}
assert(fe);
if (!bad) {
assert(fe);
positions.push_back(
position_candidates[i]);
distances.push_back(target_distance);
regions.push_back(fe->get().first);
areas.push_back(fe->get().second);
any_match = true;
bad_count = 0;
if (fe)
fe = fe->next();
}
if (!fe)
break;
}
}
assert(bad_count < 2000);
}
flecs::log::dbg("grid_size %d", grid_size);
for (i = 0; i < (int)positions.size(); i++) {
struct region region;
flecs::log::dbg("region: %s", regions[i].path().c_str());
flecs::log::dbg("position: %d, %d", positions[i].x,
positions[i].y);
region.complete = false;
region.can_grow = true;
region.can_grow_square = true;
region.parent = rtree->region.region_et;
region.rect = RegionRect2i(positions[i], Vector2i(1, 1));
region.region_et = regions[i].id();
region.remains_area = MAX(1, (areas[i] / 16));
/* setting seed uninitialized */
region_list.push_back(region);
}
}
void grow_job_queue::iterate()
{
assert(grid_e.is_valid());
assert(this);
flecs::query<growth_regions> q =
grid_e.world().query_builder<growth_regions>().build();
q.each([this](flecs::entity e, growth_regions &g) {
flecs::log::warn("pre floor: %s", e.path().c_str());
});
q.each([this](flecs::entity e, growth_regions &g) {
flecs::log::warn("floor: %s", e.path().c_str());
flecs::log::warn("job count: %d", g.job_list.size());
while (!g.job_list.empty()) {
List<struct grow_job>::Element *job_e =
g.job_list.front();
assert(job_e);
flecs::entity base_floor_e = grid_e.world().entity(
job_e->get().base_floor_id);
assert(base_floor_e.is_valid());
flecs::entity grid_floor_e = grid_e.world().entity(
job_e->get().grid_floor_id);
assert(grid_floor_e.is_valid());
flecs::log::dbg("inerate: create: base_floor: %s",
base_floor_e.path().c_str());
flecs::log::dbg("iterate: create: grid_floor: %s",
grid_floor_e.path().c_str());
switch (job_e->get().job_type) {
case grow_job::INITIAL:
flecs::log::dbg("initial");
job_initial(&job_e->get());
{
const region_tree *rtree =
e.get<region_tree>();
assert(!rtree ||
(rtree &&
rtree->check(grid_floor_e)));
}
break;
case grow_job::COMMON:
flecs::log::dbg("common");
job_common(&job_e->get());
{
const region_tree *rtree =
e.get<region_tree>();
assert(!rtree ||
(rtree &&
rtree->check(grid_floor_e)));
}
break;
default:
assert(false);
break;
}
g.job_list.pop_front();
// if (common_count > 0)
// break;
}
g.job_list.clear();
flecs::query<region_tree> qm =
grid_e.world().query_builder<region_tree>().build();
qm.each([this](flecs::entity em, region_tree &rt) {
assert(rt.check(em));
});
qm.each([this](flecs::entity em, region_tree &rt) {
rt.place(em);
});
flecs::log::dbg(
"processed jobs (created region initial positions): %d",
g.job_list.size());
});
}