ECS redesign for buildings layout editor

This commit is contained in:
2024-10-07 18:38:46 +03:00
parent 64a66d1c50
commit f62dbbf505
2 changed files with 581 additions and 95 deletions

View File

@@ -64,249 +64,336 @@ elements={
"type": "e1" "type": "e1"
} }
} }
exterior_grid={ grid_layouts={
"default": [ { "default": {
"exterior": {
"floor_0": [ {
"element": "empty", "element": "empty",
"index": 0,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 1,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 2,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 3,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 4,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 5,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 6,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 7,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 8,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 9,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 10,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 11,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 12,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 13,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 14,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 15,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 16,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 17,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 18,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 19,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 20,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 21,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 22,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 23,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 24,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 25,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 26,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 27,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 28,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 29,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 30,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 31,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 32,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 33,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 34,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 35,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 36,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 37,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 38,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 39,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 40,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 41,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 42,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 43,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 44,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 45,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 46,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 47,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 48,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 49,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 50,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 51,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 52,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 53,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 54,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 55,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 56,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 57,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 58,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 59,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 60,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 61,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 62,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 63,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 64,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 65,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 66,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 67,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 68,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 69,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 70,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 71,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "corner",
"index": 72,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "side_window",
"index": 73,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "side_window",
"index": 74,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "side_door",
"index": 75,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "side_window",
"index": 76,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "side_window",
"index": 77,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "side_wall",
"index": 78,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 79,
"rotation": 0 "rotation": 0
}, { }, {
"element": "empty", "element": "empty",
"index": 80,
"rotation": 0 "rotation": 0
} ] } ]
},
"interior": {
}
}
} }

View File

@@ -14,6 +14,7 @@
#include <scene/gui/button.h> #include <scene/gui/button.h>
#include <scene/gui/menu_button.h> #include <scene/gui/menu_button.h>
#include <editor/editor_node.h> #include <editor/editor_node.h>
#include <flecs/flecs.h>
#include "editor_event.h" #include "editor_event.h"
#include "building_layout_editor.h" #include "building_layout_editor.h"
@@ -36,10 +37,43 @@ template <class T> T *get_as_node(const String &path)
return ret; return ret;
} }
template <class T>
void select_control_item(const String &path, const String &item)
{
int i;
T *ctl = get_as_node<T>(path);
int selected = -1;
for (i = 0; i < ctl->get_item_count(); i++)
if (ctl->get_item_text(i) == item) {
selected = i;
break;
}
if (selected >= 0) {
ctl->select(selected);
print_line("selected: " + item);
}
}
template <class T> void select_control_item(T *ctl, const String &item)
{
int i;
int selected = -1;
for (i = 0; i < ctl->get_item_count(); i++)
if (ctl->get_item_text(i) == item) {
selected = i;
break;
}
if (selected >= 0) {
ctl->select(selected);
print_line("selected: " + item);
}
}
#define ELEMENT_SOCKETS 16 #define ELEMENT_SOCKETS 16
class ElementData { class ElementData {
public: flecs::world ecs;
static ElementData *singleton; static ElementData *singleton;
public:
static ElementData *get_singleton() static ElementData *get_singleton()
{ {
if (!singleton) if (!singleton)
@@ -66,13 +100,37 @@ public:
String element; String element;
int rotation; int rotation;
}; };
Vector<struct grid_cell> grid; struct grid_layouts {};
struct grid_layout {
int floor_count;
};
struct grid_layout_exterior {};
struct grid_layout_interior {};
struct grid_floor {};
struct grid_floor_item {
int index;
String element;
int rotation;
};
struct grid_floor_item_node {
Spatial *node;
};
protected: protected:
ElementData() ElementData()
{ {
grid.resize(grid_size * grid_size); ecs.component<struct grid_layouts>();
grid.fill({ "empty", 0 }); ecs.component<struct grid_layout>();
ecs.component<struct grid_layout_exterior>();
ecs.component<struct grid_layout_interior>();
ecs.component<struct grid_floor>();
ecs.component<struct grid_floor_item>();
ecs.component<struct grid_floor_item_node>();
flecs::entity e = ecs.entity("grid_layouts");
e.add<grid_layouts>();
create_new_layout("default");
create_new_exterior_floor("default");
create_new_interior_floor("default");
load_data(); load_data();
struct grid_element_type t_empty; struct grid_element_type t_empty;
struct grid_element e_empty; struct grid_element e_empty;
@@ -81,34 +139,370 @@ protected:
e_empty.type = "empty"; e_empty.type = "empty";
element_type["empty"] = t_empty; element_type["empty"] = t_empty;
elements["empty"] = e_empty; elements["empty"] = e_empty;
ecs.observer<struct grid_floor_item_node>()
.event(flecs::OnRemove)
.each([](flecs::entity em,
struct grid_floor_item_node &s) {
if (s.node)
s.node->queue_delete();
s.node = nullptr;
});
} }
HashMap<String, struct grid_element_type> element_type; HashMap<String, struct grid_element_type> element_type;
HashMap<String, struct grid_element> elements; HashMap<String, struct grid_element> elements;
public: public:
void create_new_layout(const String &key)
{
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
flecs::entity layout =
ecs.entity(key.ascii().ptr()).child_of(top);
// one floor by default
layout.set<grid_layout>({ 0 });
flecs::entity extr = ecs.entity("exterior").child_of(layout);
extr.add<grid_layout_exterior>();
flecs::entity intr = ecs.entity("interior").child_of(layout);
intr.add<grid_layout_interior>();
}
void create_new_exterior_floor(const String &key)
{
int i;
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
flecs::entity layout = top.lookup(key.ascii().ptr());
assert(layout.is_valid());
struct grid_layout *l = layout.get_mut<grid_layout>();
int floor = l->floor_count;
flecs::entity ext = layout.lookup("exterior");
assert(ext.is_valid());
flecs::entity fl =
ecs.entity(("floor_" + itos(floor)).ascii().ptr())
.child_of(ext);
assert(fl.is_valid());
for (i = 0; i < grid_size * grid_size; i++) {
flecs::entity item =
ecs.entity(("item_" + itos(i)).ascii().ptr())
.child_of(fl);
item.set<grid_floor_item>({ i, "empty", 0 });
}
l->floor_count++;
}
void create_new_interior_floor(const String &key)
{
int i;
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
flecs::entity layout = top.lookup(key.ascii().ptr());
assert(layout.is_valid());
struct grid_layout *l = layout.get_mut<grid_layout>();
int floor = l->floor_count;
flecs::entity intr = layout.lookup("interior");
assert(intr.is_valid());
flecs::entity fl =
ecs.entity(("floor_" + itos(floor)).ascii().ptr())
.child_of(intr);
assert(fl.is_valid());
for (i = 0; i < grid_size * grid_size; i++) {
flecs::entity item =
ecs.entity(("item_" + itos(i)).ascii().ptr())
.child_of(fl);
item.set<grid_floor_item>({ i, "empty", 0 });
}
l->floor_count++;
}
inline int constexpr get_grid_size() inline int constexpr get_grid_size()
{ {
return grid_size; return grid_size;
} }
inline const String &get_grid_element(int i) const inline flecs::entity get_grid_entity(const String &key, bool exterior,
int fl, int i) const
{ {
assert(i >= 0 && i < grid_size * grid_size); flecs::entity top = ecs.lookup("grid_layouts");
return grid[i].element; assert(top.is_valid());
flecs::entity layout = top.lookup(key.ascii().ptr());
assert(layout.is_valid());
struct grid_layout *l = layout.get_mut<grid_layout>();
int floor_count = l->floor_count;
assert(fl >= 0 && fl < floor_count);
flecs::entity base;
if (exterior)
base = layout.lookup("exterior");
else
base = layout.lookup("interior");
assert(base.is_valid());
String floor_key = "floor_" + itos(fl);
String item_key = "item_" + itos(i);
flecs::entity item_data = base.lookup(
(floor_key + "::" + item_key).ascii().ptr());
if (!item_data.is_valid())
print_error("lookup failed: " + floor_key +
"::" + item_key);
assert(item_data.is_valid());
return item_data;
} }
inline int get_grid_rotation(int i) const inline const String &get_grid_element(const String &key, bool exterior,
int fl, int i) const
{ {
assert(i >= 0 && i < grid_size * grid_size); flecs::entity item_data = get_grid_entity(key, exterior, fl, i);
return grid[i].rotation; const String &element =
item_data.get<grid_floor_item>()->element;
return element;
} }
void set_grid_element(int i, const String &element) inline int get_grid_rotation(const String &key, bool exterior, int fl,
int i) const
{ {
assert(i >= 0 && i < grid_size * grid_size); flecs::entity item_data = get_grid_entity(key, exterior, fl, i);
grid.write[i].element = element; int rotation = item_data.get<grid_floor_item>()->rotation;
return rotation;
} }
void set_grid_rotation(int i, int rotation) void set_grid_element(const String &key, bool exterior, int fl, int i,
const String &element)
{ {
assert(i >= 0 && i < grid_size * grid_size); flecs::entity item_data = get_grid_entity(key, exterior, fl, i);
grid.write[i].rotation = rotation; item_data.get_mut<grid_floor_item>()->element = element;
}
void set_grid_rotation(const String &key, bool exterior, int fl, int i,
int rotation)
{
flecs::entity item_data = get_grid_entity(key, exterior, fl, i);
item_data.get_mut<grid_floor_item>()->rotation = rotation;
}
Spatial *get_grid_node(const String &key, bool exterior, int fl, int i)
{
flecs::entity item_data = get_grid_entity(key, exterior, fl, i);
if (!item_data.has<struct grid_floor_item_node>()) {
Spatial *sp = memnew(Spatial);
get_as_node<Spatial>("%bg_floor")
->call_deferred("add_child", sp);
item_data.set<struct grid_floor_item_node>({ sp });
int x = i % grid_size;
int z = i / grid_size;
int rotation = get_grid_rotation(key, exterior, fl, i);
sp->set_transform(Transform(
Basis().rotated(Vector3(0, 1, 0),
Math_PI * rotation / 2.0f),
Vector3((x - 4) * 4, 0, (z - 4) * 4) -
get_as_node<Spatial>("%bg_floor")
->get_transform()
.origin));
}
return item_data.get<struct grid_floor_item_node>()->node;
}
int get_closest_node_on_floor(const String &key, bool exterior, int fl,
const Vector3 &position)
{
int i;
String full_key = "grid_layouts::" + key;
if (exterior)
full_key += "::exterior";
else
full_key += "::interior";
String floor_key = "floor_" + itos(fl);
full_key += "::" + floor_key;
flecs::entity floor_e = ecs.lookup(full_key.ascii().ptr());
assert(floor_e.is_valid());
int selected = -1;
float dst = Math_INF;
for (i = 0; i < grid_size * grid_size; i++) {
Spatial *node = get_grid_node(key, exterior, fl, i);
Vector3 pos = node->get_transform().origin;
float mdst = position.distance_squared_to(pos);
if (dst > mdst) {
dst = mdst;
selected = i;
}
}
return selected;
}
void get_grid_layouts_key_list(List<String> *keys)
{
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
flecs::query_builder<const struct grid_layout> qb =
ecs.query_builder<const struct grid_layout>().with(
flecs::ChildOf, top);
flecs::query<const struct grid_layout> q = qb.build();
q.each([keys](flecs::entity e, const struct grid_layout &data) {
keys->push_back(String(e.name()));
});
}
void serialize_layouts(Dictionary &store)
{
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
top.children([this, &store](flecs::entity l) {
Dictionary layout, exterior_layout, interior_layout;
if (l.has<struct grid_layout>()) {
flecs::entity intr = l.lookup("interior");
assert(intr.is_valid());
flecs::entity extr = l.lookup("exterior");
assert(extr.is_valid());
intr.children([this, &interior_layout](
flecs::entity intr_fl) {
if (intr_fl.has<struct grid_floor>()) {
Array items;
intr_fl.children([&items](
flecs::entity
floor_item) {
if (floor_item.has<
struct grid_floor_item>()) {
const struct grid_floor_item *item =
floor_item
.get<struct grid_floor_item>();
Dictionary sitem;
sitem["index"] =
item->index;
sitem["element"] =
item->element;
sitem["rotation"] =
item->rotation;
items.push_back(
sitem);
}
});
String floor_key(
intr_fl.name());
interior_layout[floor_key] =
items;
}
});
extr.children([this, &exterior_layout](
flecs::entity extr_fl) {
Array items;
extr_fl.children([&items](
flecs::entity
floor_item) {
if (floor_item.has<
struct grid_floor_item>()) {
const struct grid_floor_item *item =
floor_item.get<
struct grid_floor_item>();
Dictionary sitem;
sitem["index"] =
item->index;
sitem["element"] =
item->element;
sitem["rotation"] =
item->rotation;
items.push_back(sitem);
}
});
String floor_key(extr_fl.name());
exterior_layout[floor_key] = items;
});
layout["interior"] = interior_layout;
layout["exterior"] = exterior_layout;
}
String layout_name(l.name());
store[layout_name] = layout;
});
}
void unserialize_layouts(const Dictionary &store)
{
int i;
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
// delete all layouts
top.children([this](flecs::entity l) { l.destruct(); });
List<Variant> layout_keys;
store.get_key_list(&layout_keys);
List<Variant>::Element *e;
e = layout_keys.front();
while (e) {
String layout_name = e->get();
flecs::entity layout =
ecs.entity(layout_name.ascii().ptr())
.child_of(top);
layout.set<grid_layout>({ 0 });
flecs::entity extr =
ecs.entity("exterior").child_of(layout);
extr.add<grid_layout_exterior>();
flecs::entity intr =
ecs.entity("interior").child_of(layout);
intr.add<grid_layout_interior>();
Dictionary store_layout = store[e->get()];
Dictionary store_interior = store_layout["interior"];
Dictionary store_exterior = store_layout["exterior"];
List<Variant>::Element *ve;
List<Variant> interior_keys;
List<Variant> exterior_keys;
store_interior.get_key_list(&interior_keys);
store_exterior.get_key_list(&exterior_keys);
for (ve = interior_keys.front(); ve; ve = ve->next()) {
String floor_key = ve->get();
if (floor_key.begins_with("floor_")) {
flecs::entity floor_e =
ecs.entity(floor_key.ascii()
.ptr())
.child_of(intr);
assert(floor_e.is_valid());
floor_e.add<struct grid_floor>();
const Array &floor_interior =
store_interior[floor_key];
for (i = 0; i < floor_interior.size();
i++) {
const Dictionary &item =
floor_interior[i];
int index = item["index"];
String element =
item["element"];
int rotation = item["rotation"];
String item_key =
"item_" + itos(index);
flecs::entity item_e =
ecs.entity(item_key.ascii()
.ptr())
.child_of(
floor_e);
item_e.set<grid_floor_item>(
{ index, element,
rotation });
}
struct grid_layout *l = layout.get_mut<
struct grid_layout>();
l->floor_count++;
}
}
for (ve = exterior_keys.front(); ve; ve = ve->next()) {
String floor_key = ve->get();
if (floor_key.begins_with("floor_")) {
flecs::entity floor_e =
ecs.entity(floor_key.ascii()
.ptr())
.child_of(extr);
assert(floor_e.is_valid());
floor_e.add<struct grid_floor>();
const Array &floor_exterior =
store_exterior[floor_key];
for (i = 0; i < floor_exterior.size();
i++) {
const Dictionary &item =
floor_exterior[i];
int index = item["index"];
String element =
item["element"];
int rotation = item["rotation"];
String item_key =
"item_" + itos(index);
flecs::entity item_e =
ecs.entity(item_key.ascii()
.ptr())
.child_of(
floor_e);
item_e.set<grid_floor_item>(
{ index, element,
rotation });
}
struct grid_layout *l = layout.get_mut<
struct grid_layout>();
l->floor_count++;
}
}
e = e->next();
}
} }
void get_element_type_key_list(List<String> *keys) void get_element_type_key_list(List<String> *keys)
{ {
@@ -243,20 +637,12 @@ public:
e = e->next(); e = e->next();
} }
// TODO: support multiple layouts; // TODO: support multiple layouts;
Array default_grid; serialize_layouts(conf_exterior_grid);
default_grid.resize(grid_size * grid_size);
for (i = 0; i < grid_size * grid_size; i++) {
Dictionary item;
item["element"] = grid[i].element;
item["rotation"] = grid[i].rotation;
default_grid[i] = item;
}
conf_exterior_grid["default"] = default_grid;
config.set_value("buildings_layout", "element_types", config.set_value("buildings_layout", "element_types",
conf_element_types); conf_element_types);
config.set_value("buildings_layout", "elements", conf_elements); config.set_value("buildings_layout", "elements", conf_elements);
config.set_value("buildings_layout", "exterior_grid", config.set_value("buildings_layout", "grid_layouts",
conf_exterior_grid); conf_exterior_grid);
config.save("res://astream/blayout.conf"); config.save("res://astream/blayout.conf");
} }
@@ -266,7 +652,7 @@ public:
ConfigFile config; ConfigFile config;
Dictionary conf_element_types; Dictionary conf_element_types;
Dictionary conf_elements; Dictionary conf_elements;
Dictionary conf_exterior_grid; Dictionary conf_grid_layouts;
List<Variant> keys; List<Variant> keys;
List<Variant>::Element *e; List<Variant>::Element *e;
elements.clear(); elements.clear();
@@ -276,8 +662,8 @@ public:
"buildings_layout", "element_types", Dictionary()); "buildings_layout", "element_types", Dictionary());
conf_elements = config.get_value("buildings_layout", "elements", conf_elements = config.get_value("buildings_layout", "elements",
Dictionary()); Dictionary());
conf_exterior_grid = config.get_value( conf_grid_layouts = config.get_value(
"buildings_layout", "exterior_grid", Dictionary()); "buildings_layout", "grid_layouts", Dictionary());
conf_element_types.get_key_list(&keys); conf_element_types.get_key_list(&keys);
e = keys.front(); e = keys.front();
while (e) { while (e) {
@@ -311,6 +697,8 @@ public:
set_element_mesh_name(key, i, mesh_names[i]); set_element_mesh_name(key, i, mesh_names[i]);
e = e->next(); e = e->next();
} }
unserialize_layouts(conf_grid_layouts);
#if 0
if (conf_exterior_grid.has("default")) { if (conf_exterior_grid.has("default")) {
Array default_grid = conf_exterior_grid["default"]; Array default_grid = conf_exterior_grid["default"];
if (default_grid.size() == grid_size * grid_size) { if (default_grid.size() == grid_size * grid_size) {
@@ -323,6 +711,7 @@ public:
} }
} }
} }
#endif
} }
}; };
ElementData *ElementData::singleton = nullptr; ElementData *ElementData::singleton = nullptr;
@@ -331,7 +720,6 @@ class LayoutEditor : public Object {
GDCLASS(LayoutEditor, Object) GDCLASS(LayoutEditor, Object)
BuildingLayoutEditor *editor; BuildingLayoutEditor *editor;
String grid_elements; String grid_elements;
Vector<Spatial *> grid_nodes;
int current_cell; int current_cell;
public: public:
@@ -364,37 +752,30 @@ public:
int grid_size = int grid_size =
ElementData::get_singleton()->get_grid_size(); ElementData::get_singleton()->get_grid_size();
assert(grid_size > 0); assert(grid_size > 0);
grid_nodes.resize(grid_size * grid_size); const String layout_key = "default";
bool exterior = true;
int floor = 0;
for (i = 0; i < grid_size * grid_size; i++) { for (i = 0; i < grid_size * grid_size; i++) {
int x = i % grid_size; Spatial *node =
int z = i / grid_size; ElementData::get_singleton()
Spatial *node = memnew(Spatial); ->get_grid_node(layout_key,
int rotation = ElementData::get_singleton() exterior, floor,
->get_grid_rotation(i); i);
get_as_node<Spatial>("%bg_floor") String element =
->call_deferred("add_child", node); ElementData::get_singleton()
node->set_transform(Transform( ->get_grid_element(layout_key,
Basis().rotated(Vector3(0, 1, 0), exterior,
Math_PI * rotation / floor, i);
2.0f),
Vector3((x - 4) * 4, 0, (z - 4) * 4) -
get_as_node<Spatial>("%bg_floor")
->get_transform()
.origin));
String element = ElementData::get_singleton()
->get_grid_element(i);
editor->visualize_element_at(element, node); editor->visualize_element_at(element, node);
grid_nodes.write[i] = node;
print_line("element: " + element); print_line("element: " + element);
} }
assert(grid_nodes.size() > 0);
} }
editor->get_viewport()->get_camera()->set_global_translation( editor->get_viewport()->get_camera()->set_global_translation(
Vector3(-14, 23, 32)); Vector3(-14, 23, 32));
List<String> element_keys; List<String> element_keys;
List<String>::Element *e; List<String>::Element *e;
ElementData::get_singleton()->get_element_type_key_list( ElementData::get_singleton()->get_element_key_list(
&element_keys); &element_keys);
e = element_keys.front(); e = element_keys.front();
get_as_node<OptionButton>(grid_elements)->clear(); get_as_node<OptionButton>(grid_elements)->clear();
@@ -415,7 +796,6 @@ public:
} }
void event_signal_handler(const String &event, const Array &args) void event_signal_handler(const String &event, const Array &args)
{ {
int i;
print_line("event: " + event); print_line("event: " + event);
if (event == "mouse_press") { if (event == "mouse_press") {
Vector2 position = args[0]; Vector2 position = args[0];
@@ -441,40 +821,71 @@ public:
Math::stepify(proj.z, 4.0f))); Math::stepify(proj.z, 4.0f)));
get_as_node<Spatial>("%refcube") get_as_node<Spatial>("%refcube")
->set_global_transform(xf); ->set_global_transform(xf);
float dst = Math_INF; String layout_key = "default";
int selected = -1; bool exterior = true;
for (i = 0; i < grid_nodes.size(); i++) { int floor = 0;
assert(grid_nodes[i]->is_inside_tree()); int selected =
Vector3 o = ElementData::get_singleton()
grid_nodes[i] ->get_closest_node_on_floor(
->get_global_transform() layout_key, exterior,
.origin; floor, xf.origin);
float mdst = o.distance_squared_to(
xf.origin);
if (dst > mdst) {
selected = i;
dst = mdst;
}
}
if (selected >= 0) { if (selected >= 0) {
current_cell = selected; current_cell = selected;
get_as_node<Spatial>("%refcube") get_as_node<Spatial>("%refcube")
->set_global_transform( ->set_global_transform(
grid_nodes[current_cell] ElementData::get_singleton()
->get_grid_node(
layout_key,
exterior,
floor,
current_cell)
->get_global_transform()); ->get_global_transform());
print_line( print_line(
"cell: " + itos(current_cell) + "cell: " + itos(current_cell) +
"pos: " + "pos: " +
(grid_nodes[current_cell] (ElementData::get_singleton()
->get_grid_node(
layout_key,
exterior,
floor,
current_cell)
->get_global_transform() ->get_global_transform()
.origin .origin
.operator String())); .operator String()));
String element =
ElementData::get_singleton()
->get_grid_element(
layout_key,
exterior, floor,
current_cell);
select_control_item<OptionButton>(
"%grid_elements", element);
} }
} }
} }
} }
void select_grid_element(int index)
{
String layout_key = "default";
bool exterior = true;
int floor = 0;
print_line("selected: " + itos(current_cell) + " " +
itos(index));
const String &element =
get_as_node<OptionButton>("%grid_elements")
->get_item_text(index);
ElementData::get_singleton()->set_grid_element(
layout_key, exterior, floor, current_cell, element);
editor->visualize_element_at(
element,
ElementData::get_singleton()->get_grid_node(
layout_key, exterior, floor, current_cell));
}
static void _bind_methods() static void _bind_methods()
{ {
ClassDB::bind_method(D_METHOD("select_grid_element", "index"),
&LayoutEditor::select_grid_element);
} }
}; };
@@ -588,7 +999,7 @@ public:
} }
void select_element(int element) void select_element(int element)
{ {
int i, j; int i;
print_line("selected element: " + itos(element)); print_line("selected element: " + itos(element));
String item = get_as_node<ItemList>("%element_list") String item = get_as_node<ItemList>("%element_list")
->get_item_text(element); ->get_item_text(element);
@@ -614,27 +1025,13 @@ public:
ElementData::get_singleton()->set_element_type( ElementData::get_singleton()->set_element_type(
current_element, b->get_item_text(0)); current_element, b->get_item_text(0));
} }
int selected = 0;
for (i = 0; i < used_socket_count; i++) { for (i = 0; i < used_socket_count; i++) {
String selected_mesh = String selected_mesh =
ElementData::get_singleton() ElementData::get_singleton()
->get_element_mesh_name(current_element, ->get_element_mesh_name(current_element,
i); i);
selected = 0; select_control_item<OptionButton>(
for (j = 0; mesh_select_buttons[i], selected_mesh);
j < mesh_select_buttons[i]->get_item_count();
j++) {
String mesh_item =
mesh_select_buttons[i]->get_item_text(
j);
if (mesh_item == selected_mesh) {
selected = j;
break;
}
}
print_line(itos(i) +
": selecting mesh: " + itos(selected));
mesh_select_buttons[i]->select(selected);
} }
editor->visualize_element_type(type, current_element); editor->visualize_element_type(type, current_element);
} }
@@ -1186,6 +1583,8 @@ void BuildingLayoutEditor::visualize_element_at(const String &element,
return; return;
const String &element_type = const String &element_type =
ElementData::get_singleton()->get_element_type(element); ElementData::get_singleton()->get_element_type(element);
for (i = 0; i < node->get_child_count(); i++)
node->get_child(i)->queue_delete();
for (i = 0; i < ELEMENT_SOCKETS; i++) { for (i = 0; i < ELEMENT_SOCKETS; i++) {
Transform xform = Transform xform =
ElementData::get_singleton()->get_element_type_socket( ElementData::get_singleton()->get_element_type_socket(