Converted buildings loading to flecs

This commit is contained in:
2025-04-17 19:30:39 +03:00
parent fd23aa6287
commit dd00a41024
22 changed files with 845 additions and 812 deletions

View File

@@ -2,8 +2,10 @@ ARCH=$(patsubst aarch64,arm64,$(shell uname -m))
BLENDER = ../../blender-3.6.20-linux-x64/blender BLENDER = ../../blender-3.6.20-linux-x64/blender
SERVER = src/godot/bin/godot_server.x11.opt.tools.$(ARCH) SERVER = src/godot/bin/godot_server.x11.opt.tools.$(ARCH)
EDITOR_PLATFORM=x11es EDITOR_PLATFORM=x11es
EDITOR2_PLATFORM=x11
DEMO_PLATFORMS=x11 x11es DEMO_PLATFORMS=x11 x11es
EDITOR = src/godot/bin/godot.$(EDITOR_PLATFORM).opt.tools.$(ARCH) EDITOR = src/godot/bin/godot.$(EDITOR_PLATFORM).opt.tools.$(ARCH)
EDITOR2 = src/godot/bin/godot.$(EDITOR2_PLATFORM).opt.tools.$(ARCH)
.PHONY: all godot-editor-main export export-models export-clothes \ .PHONY: all godot-editor-main export export-models export-clothes \
export-clean export-linux-demo export-windows-demo \ export-clean export-linux-demo export-windows-demo \
@@ -28,12 +30,13 @@ $(foreach pt,$(DEMO_PLATFORMS),$(eval $(call build_godot_platform,$(pt))))
godot-main: $(GODOT_MAIN_TARGETS) godot-editor-main godot-server-main godot-main: $(GODOT_MAIN_TARGETS) godot-editor-main godot-server-main
godot-server-main: $(SERVER) godot-server-main: $(SERVER)
godot-editor-main: $(EDITOR) godot-editor-main: $(EDITOR) $(EDITOR2)
$(SERVER): patch #$(SERVER): patch
cd src/godot; \ # cd src/godot; \
scons platform=server arch=$(ARCH) target=release_debug tools=yes custom_modules=../modules -j16 # scons platform=server arch=$(ARCH) target=release_debug tools=yes custom_modules=../modules -j16
$(eval $(call build_godot,server,release_debug,yes,$(SERVER),patch)) $(eval $(call build_godot,server,release_debug,yes,$(SERVER),patch))
$(eval $(call build_godot,x11es,release_debug,yes,$(EDITOR),patch)) $(eval $(call build_godot,x11es,release_debug,yes,$(EDITOR),patch))
$(eval $(call build_godot,x11,release_debug,yes,$(EDITOR2),patch))
patch: ./src/godot/scene/animation/skeleton_ik.cpp patch: ./src/godot/scene/animation/skeleton_ik.cpp
cd ./src/godot && git reset --hard HEAD && rm -Rf platform/x11es && for p in ../patches/*.patch; do git apply $$p; done cd ./src/godot && git reset --hard HEAD && rm -Rf platform/x11es && for p in ../patches/*.patch; do git apply $$p; done
sed -e 's/ERR_FAIL_COND_V(-1 == p_task->root_bone, false);//g' -i ./src/godot/scene/animation/skeleton_ik.cpp sed -e 's/ERR_FAIL_COND_V(-1 == p_task->root_bone, false);//g' -i ./src/godot/scene/animation/skeleton_ik.cpp

View File

@@ -27,7 +27,7 @@ flags/repeat=true
flags/filter=true flags/filter=true
flags/mipmaps=true flags/mipmaps=true
flags/anisotropic=false flags/anisotropic=false
flags/srgb=2 flags/srgb=1
process/fix_alpha_border=true process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false

View File

@@ -54,3 +54,6 @@ transform = Transform( 1.7, 0, 0, 0, 1, 0, 0, 0, 1.2, 0, 0, 2.03699 )
[node name="2" type="Spatial" parent="LOD"] [node name="2" type="Spatial" parent="LOD"]
visible = false visible = false
[node name="BuildingLayoutInstance" type="BuildingLayoutInstance" parent="."]
size = 8

View File

@@ -17,6 +17,10 @@ boot_splash/minimum_display_time=4
settings/fps/force_fps=60 settings/fps/force_fps=60
[display]
window/vsync/use_vsync=false
[input] [input]
forward={ forward={
@@ -87,5 +91,5 @@ portals/optimize/remove_danglers=false
gles3/shaders/shader_compilation_mode=2 gles3/shaders/shader_compilation_mode=2
gles3/shaders/shader_compilation_mode.mobile=2 gles3/shaders/shader_compilation_mode.mobile=2
gles3/shaders/max_simultaneous_compiles=4 gles3/shaders/max_simultaneous_compiles=4
limits/buffers/immediate_buffer_size_kb=4096
limits/buffers/blend_shape_max_buffer_size_kb=8192 limits/buffers/blend_shape_max_buffer_size_kb=8192
limits/buffers/immediate_buffer_size_kb=4096

View File

@@ -0,0 +1,20 @@
#include "building_grid_instance.h"
#include "buildings_data.h"
AABB BuildingGridInstance::get_aabb() const
{
return AABB();
}
PoolVector<Face3> BuildingGridInstance::get_faces(uint32_t p_usage_flags) const
{
return PoolVector<Face3>();
}
BuildingGridInstance::BuildingGridInstance()
{
}
BuildingGridInstance::~BuildingGridInstance()
{
}

View File

@@ -0,0 +1,17 @@
/* ~/godot-projects/streaming_world/src/modules/stream/building_grid_instance.h */
#ifndef BUILDING_GRID_INSTANCE_H_
#define BUILDING_GRID_INSTANCE_H_
#include <flecs.h>
#include <scene/3d/visual_instance.h>
class BuildingGridInstance : public GeometryInstance {
GDCLASS(BuildingGridInstance, GeometryInstance)
flecs::entity e;
public:
virtual AABB get_aabb() const;
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
BuildingGridInstance();
~BuildingGridInstance();
};
#endif // BUILDING_GRID_INSTANCE_H_

View File

@@ -0,0 +1,97 @@
#include <scene/3d/area.h>
#include <scene/3d/collision_shape.h>
#include "building_layout_instance.h"
BuildingLayoutInstance::BuildingLayoutInstance()
: GeometryInstance()
, size(0)
, level(0)
{
}
BuildingLayoutInstance::~BuildingLayoutInstance()
{
}
void BuildingLayoutInstance::_notification(int which)
{
switch (which) {
case NOTIFICATION_ENTER_TREE:
break;
case NOTIFICATION_EXIT_TREE:
break;
}
}
void BuildingLayoutInstance::_get_property_list(List<PropertyInfo> *p_list) const
{
int i, j;
p_list->push_back(PropertyInfo(Variant::INT, "size", PROPERTY_HINT_NONE,
"", PROPERTY_USAGE_DEFAULT));
p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "walls",
PROPERTY_HINT_NONE, "",
PROPERTY_USAGE_DEFAULT));
}
bool BuildingLayoutInstance::_get(const StringName &name, Variant &val) const
{
int i;
if (name == "size") {
val = size;
return true;
} else if (name == "walls") {
PoolVector<int> mfloors;
mfloors.resize(size);
mfloors.fill(0);
if (floors.size() < 2) {
val = mfloors;
return true;
}
for (i = 0; i < floors.size(); i += 2) {
int cell_index = floors[i];
int cell_data = floors[i + 1];
if (cell_index >= 0 && cell_index < mfloors.size())
continue;
if (cell_data & (1 << 0))
mfloors.write()[cell_index] = 1;
else
mfloors.write()[cell_index] = 0;
}
return true;
}
return false;
}
bool BuildingLayoutInstance::_set(const StringName &name, const Variant &val)
{
int i;
if (name == "size") {
size = val;
property_list_changed_notify();
return true;
#if 0
} else if (name == "walls") {
PoolVector<int> mfloors = val;
floors.resize(mfloors.size());
for (i = 0; i < mfloors.size(); i++) {
if (mfloors[i] > 0)
floors.ptrw()[i] |= (1 << 0);
else
floors.ptrw()[i] &= ~(1 << 0);
}
return true;
#endif
}
return false;
}
AABB BuildingLayoutInstance::get_aabb() const
{
return AABB();
}
PoolVector<Face3>
BuildingLayoutInstance::get_faces(uint32_t p_usage_flags) const
{
return PoolVector<Face3>();
}

View File

@@ -0,0 +1,21 @@
#include <scene/3d/visual_instance.h>
class BuildingLayoutInstance : public GeometryInstance {
GDCLASS(BuildingLayoutInstance, GeometryInstance)
public:
BuildingLayoutInstance();
~BuildingLayoutInstance();
protected:
void _notification(int which);
void _get_property_list(List<PropertyInfo> *p_list) const;
bool _get(const StringName &name, Variant &val) const;
bool _set(const StringName &name, const Variant &val);
Vector<int> floors;
int size;
int level;
public:
virtual AABB get_aabb() const;
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
};

View File

@@ -9,13 +9,14 @@
#include <scene/resources/packed_scene.h> #include <scene/resources/packed_scene.h>
#include <scene/3d/spatial.h> #include <scene/3d/spatial.h>
#include <scene/3d/mesh_instance.h> #include <scene/3d/mesh_instance.h>
#include <scene/3d/camera.h>
#include <scene/main/viewport.h>
#include "from_string.h" #include "from_string.h"
#include "base_data.h" #include "base_data.h"
#include "buildings_data.h" #include "buildings_data.h"
BuildingsData *BuildingsData::singleton;
static ConfigFile config; static ConfigFile config;
static ConfigFile custom_layouts;
struct scene_data { struct scene_data {
Ref<PackedScene> packed_scene; Ref<PackedScene> packed_scene;
String path; String path;
@@ -42,43 +43,206 @@ struct CBuildingInstance {
Node *node; Node *node;
}; };
struct CBuildingData {
struct BuildingsData::building building;
};
struct CSceneData { struct CSceneData {
struct scene_data sd; struct scene_data sd;
}; };
#if 0
void BuildingsData::load_tile(std::tuple<int, int> key)
{
int i;
const std::vector<String> &items = tiles[key];
for (i = 0; i < (int)items.size(); i++) {
print_verbose("load item: " + itos(i) + ": key: " + (items[i]) +
": " /* + data()->get_building(items[i]).id */);
const String &bkey = items[i];
flecs::entity eb = get_building_entity(bkey);
if (eb.is_valid()) {
if (!eb.has<BuildingsData::CBuildingLoaded>())
eb.add<BuildingsData::CBuildingLoad>();
}
}
}
#endif
BuildingsData::BuildingsData() BuildingsData::BuildingsData()
: undo_log_size(64) : undo_log_size(64)
{ {
flecs::world ecs_ = ecs();
ecs_.component<CBuildingStats>();
ecs_.component<CBuildingData>();
ecs_.component<CBTypeResidental>();
ecs_.component<CBCustomLayout>();
ecs_.component<CBuildingEdited>();
ecs_.component<CBuildingTileData>();
ecs_.component<CBuildingsEye>();
bool deferred = ecs_.is_deferred();
if (deferred)
ecs_.defer_suspend();
ecs_.set<CBuildingStats>({ 0 });
ecs_.set<CBuildingTileData>({});
assert(ecs_.has<CBuildingStats>());
load_data(); load_data();
ecs_.query_builder<const CBuildingData>().build().each(
[](flecs::entity e, const CBuildingData &bd) {
print_line("created: " + bd.building.key + " / " +
String(e.name()));
});
if (deferred)
ecs_.defer_resume();
print_line("loaded buildings: " +
itos(ecs().get<CBuildingStats>()->created_entities));
assert(ecs().get<CBuildingStats>()->created_entities > 0);
fill_door_locations(); fill_door_locations();
build_building_aabbs(); build_building_aabbs();
ecs().observer<CBuildingInstance>() ecs_.observer<CBuildingInstance>()
.event(flecs::OnRemove) .event(flecs::OnRemove)
.each([](flecs::entity e, CBuildingInstance &bi) { .each([](flecs::entity e, CBuildingInstance &bi) {
if (bi.node) { if (bi.node) {
bi.node->queue_delete(); bi.node->queue_delete();
bi.node = nullptr; bi.node = nullptr;
print_line("instance destroyed for " + bi.key); // print_line("instance destroyed for " + bi.key);
} }
}); });
ecs_.observer<CBuildingEdited>()
.event(flecs::OnAdd)
.with<CBuildingData>()
.run([&](flecs::iter &it) {
flecs::query<const CBuildingData> q =
it.world()
.query_builder<const CBuildingData>()
.with<CBuildingEdited>()
.build();
if (it.next()) {
flecs::entity qe = it.entity(0);
q.each([qe](flecs::entity e,
const CBuildingData &d) {
if (e != qe)
e.remove<CBuildingEdited>();
});
print_line("Selected building " +
String(qe.name()));
// it.fini();
}
});
ecs_.system("UpdateEye").kind(flecs::OnUpdate).run([&](flecs::iter &it) {
Viewport *viewport = SceneTree::get_singleton()
->get_current_scene()
->get_viewport();
int i, j, l;
int tile_size = config.get_value("world", "tile_size");
int view_distance = config.get_value("world", "view_distance");
assert(tile_size > 0);
Transform xform =
viewport->get_camera()->get_global_transform();
Vector3 eye = xform.origin;
int tile_x = int(eye.x / tile_size);
int tile_z = int(eye.z / tile_size);
bool need_update = true;
if (it.world().has<CBuildingsEye>()) {
int old_x = it.world().get<CBuildingsEye>()->tile_x;
int old_z = it.world().get<CBuildingsEye>()->tile_z;
if (old_x == tile_x && old_z == tile_z)
need_update = false;
}
it.world().set<CBuildingsEye>({ xform, tile_x, tile_z });
if (need_update)
return;
if (!it.world().has<CBuildingTileData>())
return;
CBuildingTileData *td = it.world().get_mut<CBuildingTileData>();
it.world()
.query_builder<CBuildingData>()
.without<CBuildingLoaded>()
.without<CBuildingLoad>()
.with<CBuildingTile>()
.build()
.each([&](flecs::entity e, const CBuildingData &bd) {
const CBuildingTile *bt =
e.get<CBuildingTile>();
std::tuple<int, int> tile = bt->tile;
int t_x = std::get<0>(tile);
int t_z = std::get<1>(tile);
if (t_x > tile_x - view_distance &&
t_x < tile_x + view_distance &&
t_z > tile_z - view_distance &&
t_z < tile_z + view_distance) {
if (e.is_valid()) {
e.add<BuildingsData::
CBuildingLoad>();
}
}
});
it.world()
.query_builder<CBuildingData>()
.with<CBuildingLoaded>()
.with<CBuildingTile>()
.without<CBuildingUnload>()
.build()
.each([&](flecs::entity e, const CBuildingData &bd) {
const CBuildingTile *bt =
e.get<CBuildingTile>();
std::tuple<int, int> tile = bt->tile;
int erase_distance = view_distance + 1;
int ed2 = erase_distance * erase_distance;
int t_x = std::get<0>(tile);
int t_z = std::get<1>(tile);
int d1 = t_x - tile_x;
int d2 = t_z - tile_z;
if (d1 * d1 > ed2 || d2 * d2 > ed2)
if (e.is_valid()) {
e.add<BuildingsData::
CBuildingUnload>();
}
});
});
ecs_.system<const CBuildingData>("LoadData")
.kind(flecs::OnUpdate)
.without<CBuildingLoaded>()
.with<CBuildingLoad>()
.write<CBuildingLoaded>()
.each([&](flecs::entity e, const CBuildingData &bd) {
e.world().defer_suspend();
bool debug = false;
// if (bd.building.key.begins_with("road__"))
// debug = true;
String id = bd.building.id;
if (debug)
print_verbose("add to scene id: " + id);
if (!has_scene(id))
create_scene_data(id, bd.building.key);
else
add_scene_item(id, bd.building.key);
if (debug)
print_verbose("added to scene id: " + id);
e.add<CBuildingLoaded>();
e.remove<CBuildingLoad>();
e.world().defer_resume();
});
ecs_.system<const CBuildingData>("UnloadData")
.kind(flecs::OnUpdate)
.with<CBuildingUnload>()
.with<CBuildingLoaded>()
.write<CBuildingLoaded>()
.each([&](flecs::entity e, const CBuildingData &bd) {
bool debug = false;
// if (bd.building.key.begins_with("road__"))
// debug = true;
String id = bd.building.key;
if (debug)
print_verbose("removed from scene id: " + id);
if (has_scene(id))
remove_scene_item(id, bd.building.key);
e.remove<CBuildingLoaded>();
e.remove<CBuildingUnload>();
});
} }
BuildingsData::~BuildingsData() BuildingsData::~BuildingsData()
{ {
} }
BuildingsData *BuildingsData::get_singleton()
{
if (!singleton)
singleton = memnew(BuildingsData);
return singleton;
}
void BuildingsData::build_building_aabbs() void BuildingsData::build_building_aabbs()
{ {
building_aabbs.clear(); building_aabbs.clear();
@@ -130,14 +294,14 @@ bool BuildingsData::has_building(const String &key)
String ename = "base:" + key; String ename = "base:" + key;
flecs::entity e = lookup(ename.ascii().ptr()); flecs::entity e = lookup(ename.ascii().ptr());
if (!e.is_valid()) if (!e.is_valid())
print_line("no key: " + key); print_verbose("no key: " + key);
else else
print_line("has building with parent: " + print_verbose("has building with parent: " +
String(e.parent().name())); String(e.parent().name()));
return e.is_valid(); return e.is_valid();
} }
String BuildingsData::get_closest_building(const Transform &xform) String BuildingsData::get_closest_building(const Transform &xform) const
{ {
float dst = Math_INF; float dst = Math_INF;
String rkey; String rkey;
@@ -154,18 +318,30 @@ String BuildingsData::get_closest_building(const Transform &xform)
}); });
return rkey; return rkey;
} }
flecs::entity
void BuildingsData::cleanup() BuildingsData::get_closest_building_entity(const Transform &xform) const
{ {
if (singleton) { float dst = Math_INF;
singleton->~BuildingsData(); String rkey;
Memory::free_static(singleton, false); flecs::entity qe;
singleton = nullptr; // int id = -1;
} ecs().each([xform, &rkey, &dst, &qe](flecs::entity e,
const CBuildingData &d) {
Vector3 o = xform.origin;
Vector3 m = d.building.xform.origin;
float mdst = o.distance_squared_to(m);
if (dst > mdst && !d.building.key.begins_with("road__")) {
dst = mdst;
rkey = d.building.key;
qe = e;
}
});
return qe;
} }
void BuildingsData::read_buildings_json(const String &buildings_path) void BuildingsData::read_buildings_json(const String &buildings_path)
{ {
assert(ecs().has<CBuildingStats>());
String buildings_json = FileAccess::get_file_as_string(buildings_path); String buildings_json = FileAccess::get_file_as_string(buildings_path);
Variant json_v; Variant json_v;
String es; String es;
@@ -213,7 +389,7 @@ void BuildingsData::save_buildings_json(const String &buildings_path)
fa->close(); fa->close();
Dictionary json; Dictionary json;
int index = 0; int index = 0;
ecs().each([&index, &json](const CBuildingData &b) { ecs().each([&index, &json](flecs::entity e, const CBuildingData &b) {
String key = b.building.key; String key = b.building.key;
/* do not save roadside generated stuff */ /* do not save roadside generated stuff */
if (!key.begins_with("road::") && !key.begins_with("road__")) { if (!key.begins_with("road::") && !key.begins_with("road__")) {
@@ -321,6 +497,7 @@ void BuildingsData::filter_generated_stuff()
void BuildingsData::load_data() void BuildingsData::load_data()
{ {
assert(ecs().has<CBuildingStats>());
Error result = config.load("res://config/stream.conf"); Error result = config.load("res://config/stream.conf");
ERR_FAIL_COND_MSG(result != OK, "Failed to load config"); ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
Dictionary buildings_data = Dictionary buildings_data =
@@ -336,7 +513,7 @@ void BuildingsData::load_data()
e = keys.front(); e = keys.front();
while (e) { while (e) {
String key = e->get(); String key = e->get();
print_line(key + ": " + buildings_data[key]); // print_line(key + ": " + buildings_data[key]);
e = e->next(); e = e->next();
} }
String buildings_path = config.get_value("buildings", "buildings_path"); String buildings_path = config.get_value("buildings", "buildings_path");
@@ -459,6 +636,19 @@ bool BuildingsData::has_scene(const String &key) const
return e.is_valid(); return e.is_valid();
} }
flecs::entity BuildingsData::get_building_entity(const String &key) const
{
flecs::query_builder<const CBuildingData> qb =
ecs().query_builder<const CBuildingData>();
flecs::query<const CBuildingData> q = qb.build();
uint64_t key_hash = key.hash64();
flecs::entity em = q.find([key_hash](const CBuildingData &bd) {
// print_line("search: " + bd.building.key);
return bd.building.key.hash64() == key_hash;
});
return em;
}
void BuildingsData::remove_scene_item(const String &key, const String &bkey) void BuildingsData::remove_scene_item(const String &key, const String &bkey)
{ {
flecs::entity e = ecs().lookup(key.ascii().ptr()); flecs::entity e = ecs().lookup(key.ascii().ptr());
@@ -502,28 +692,33 @@ void BuildingsData::add_scene_item(const String &key, const String &bkey)
CSceneData *d = e.get_mut<CSceneData>(); CSceneData *d = e.get_mut<CSceneData>();
assert(d); assert(d);
String ename = "bi:" + bkey; String ename = "bi:" + bkey;
print_line("creating entity: " + ename + " on top of: " + key); // print_line("creating entity: " + ename + " on top of: " + key);
flecs::entity ce = e.lookup(ename.ascii().ptr()); flecs::entity ce = e.lookup(ename.ascii().ptr());
if (ce.is_valid()) if (ce.is_valid())
ce.destruct(); ce.destruct();
ce = ecs().entity(ename.ascii().ptr()).child_of(e); ce = ecs().entity(ename.ascii().ptr()).child_of(e);
ce.set<CBuildingInstance>({ bkey, nullptr }); ce.set<CBuildingInstance>({ bkey, nullptr });
print_line("child name: " + String(ce.name())); // print_line("child name: " + String(ce.name()));
} }
void BuildingsData::create_scene_data(const String &key, const String &bkey) void BuildingsData::create_scene_data(const String &key, const String &bkey)
{ {
if (!has_scene(key)) { if (!has_scene(key)) {
flecs::entity e = ecs().entity(key.ascii().ptr()); flecs::entity e = ecs().entity(key.ascii().ptr());
// print_line("scene key: " + key);
assert(building_data.has(key));
String path = building_data[key]; String path = building_data[key];
// print_line("path: " + path);
assert(path.length() > 5); assert(path.length() > 5);
print_line("Requesting " + (bkey) + " " + path); print_line("Requesting " + (bkey) + " " + path);
assert(!pending_scene.has(path));
struct scene_data sd; struct scene_data sd;
sd.path = path; sd.path = path;
sd.loader = ResourceLoader::load_interactive( sd.loader = ResourceLoader::load_interactive(
path, "PackedScene", true); path, "PackedScene", true);
assert(sd.loader.is_valid()); assert(sd.loader.is_valid());
e.set<CSceneData>({ sd }); e.set<CSceneData>({ sd });
pending_scene.insert(path);
assert(e.get_mut<CSceneData>()); assert(e.get_mut<CSceneData>());
String ename = "bi:" + bkey; String ename = "bi:" + bkey;
flecs::entity ce = e.lookup(ename.ascii().ptr()); flecs::entity ce = e.lookup(ename.ascii().ptr());
@@ -532,7 +727,7 @@ void BuildingsData::create_scene_data(const String &key, const String &bkey)
ce = ecs().entity(ename.ascii().ptr()); ce = ecs().entity(ename.ascii().ptr());
ce.child_of(e); ce.child_of(e);
ce.set<CBuildingInstance>({ bkey, nullptr }); ce.set<CBuildingInstance>({ bkey, nullptr });
print_line("child name: " + String(ce.name())); // print_line("child name: " + String(ce.name()));
} }
} }
@@ -571,7 +766,7 @@ int BuildingsData::scene_get_item_count(const String &key) const
it.fini(); it.fini();
}); });
// assert(result == d->sd.buildings.size()); // assert(result == d->sd.buildings.size());
print_line("scene_get_item_count: " + itos(result)); // print_line("scene_get_item_count: " + itos(result));
return result; return result;
} }
List<String> BuildingsData::scene_get_items(const String &key) const List<String> BuildingsData::scene_get_items(const String &key) const
@@ -700,11 +895,14 @@ int BuildingsData::get_building_count() const
flecs::query<const CBuildingData> q = flecs::query<const CBuildingData> q =
ecs().query<const CBuildingData>(); ecs().query<const CBuildingData>();
int result; int result;
result = q.count();
#if 0
q.run([&result](flecs::iter &it) { q.run([&result](flecs::iter &it) {
it.next(); it.next();
result = it.count(); result = it.count();
it.fini(); it.fini();
}); });
#endif
return result; return result;
} }
@@ -728,6 +926,7 @@ BuildingsData::get_building(const String &building_key)
String BuildingsData::create_building(const Dictionary &dict) String BuildingsData::create_building(const Dictionary &dict)
{ {
assert(ecs().has<CBuildingStats>());
struct building b; struct building b;
building::from_dict(&b, dict); building::from_dict(&b, dict);
return create_building(b); return create_building(b);
@@ -736,13 +935,29 @@ String BuildingsData::create_building(const Dictionary &dict)
String BuildingsData::create_building(const struct building &building) String BuildingsData::create_building(const struct building &building)
{ {
assert(building.key.length() > 0); assert(building.key.length() > 0);
assert(ecs().has<CBuildingStats>());
String ename = "base:" + building.key; String ename = "base:" + building.key;
print_line("create_building: " + ename); // print_line("create_building: " + ename);
flecs::entity e = ecs().lookup(ename.ascii().ptr()); flecs::entity e = ecs().lookup(ename.ascii().ptr());
assert(!e.is_valid()); assert(!e.is_valid());
e = ecs().entity(ename.ascii().ptr()); e = ecs().entity(ename.ascii().ptr());
e.set<CBuildingData>({ building });
assert(e.is_valid()); assert(e.is_valid());
int tile_size = config.get_value("world", "tile_size");
assert(tile_size > 0);
e.set<CBuildingData>({ building });
int tile_x = building.xform.origin.x / tile_size;
int tile_z = building.xform.origin.z / tile_size;
std::tuple<int, int> tile = { tile_x, tile_z };
e.set<CBuildingTile>({ tile });
CBuildingTileData *td = ecs().get_mut<CBuildingTileData>();
if (td->tiles.find(tile) != td->tiles.end())
td->tiles[tile].push_back(e);
else
td->tiles[tile] = { e };
ecs().get_mut<CBuildingStats>()->created_entities++;
ecs().modified<CBuildingStats>();
if (building.id.begins_with("residental-"))
e.add<CBTypeResidental>();
print_line("create_building: " + ename + " created"); print_line("create_building: " + ename + " created");
return building.key; return building.key;
@@ -779,7 +994,7 @@ bool BuildingsData::destroy_building(const String &key)
{ {
assert(key.length() > 0); assert(key.length() > 0);
String ename = "base:" + key; String ename = "base:" + key;
print_line("destroy_building: " + ename); // print_line("destroy_building: " + ename);
flecs::entity e = ecs().lookup(ename.ascii().ptr()); flecs::entity e = ecs().lookup(ename.ascii().ptr());
assert(e.is_valid()); assert(e.is_valid());
e.destruct(); e.destruct();

View File

@@ -1,7 +1,9 @@
#ifndef BUILDINGS_DATA_H #ifndef BUILDINGS_DATA_H
#define BUILFINGS_DATA_H #define BUILFINGS_DATA_H
#include <unordered_map>
#include <vector> #include <vector>
#include <core/reference.h> #include <core/reference.h>
#include <flecs.h>
class PackedScene; class PackedScene;
class ResourceInteractiveLoader; class ResourceInteractiveLoader;
class BuildingsData { class BuildingsData {
@@ -21,10 +23,49 @@ public:
Dictionary to_dict() const; Dictionary to_dict() const;
String line_name; String line_name;
}; };
Set<String> pending_scene;
/* Scene objects data */ /* Scene objects data */
//private: //private:
// HashMap<String, struct scene_data> scenes; // HashMap<String, struct scene_data> scenes;
struct CBuildingData {
struct BuildingsData::building building;
};
struct CBTypeResidental {};
struct CBCustomLayout {
int size;
Vector<int> floors;
};
struct CBuildingStats {
int created_entities;
};
struct CBuildingsEye {
Transform cam_xform;
int tile_x;
int tile_z;
};
struct CBuildingTileData {
using tile_key_t = std::tuple<int, int>;
struct tile_hash
: public std::unary_function<key_t, std::size_t> {
std::size_t operator()(const tile_key_t &k) const
{
return std::get<0>(k) ^ std::get<1>(k);
}
};
using tile_map_t = std::unordered_map<
const tile_key_t, std::vector<flecs::entity>, tile_hash>;
tile_map_t tiles;
tile_map_t loaded_tiles;
};
struct CBuildingTile {
std::tuple<int, int> tile;
};
struct CBuildingLoad {};
struct CBuildingUnload {};
struct CBuildingLoaded {};
struct CBuildingEdited {};
public: public:
void get_scene_keys_list(List<String> *keys) const; void get_scene_keys_list(List<String> *keys) const;
bool has_scene(const String &key) const; bool has_scene(const String &key) const;
@@ -113,7 +154,6 @@ public:
int undo_log_size; int undo_log_size;
BuildingsData(); BuildingsData();
virtual ~BuildingsData(); virtual ~BuildingsData();
static BuildingsData *singleton;
public: public:
void read_buildings_json(const String &buildings_path); void read_buildings_json(const String &buildings_path);
@@ -128,8 +168,9 @@ public:
void update_building_transform(const String &key, void update_building_transform(const String &key,
const Transform &xform); const Transform &xform);
bool has_building(const String &key); bool has_building(const String &key);
String get_closest_building(const Transform &xform); String get_closest_building(const Transform &xform) const;
static BuildingsData *get_singleton(); flecs::entity get_closest_building_entity(const Transform &xform) const;
static void cleanup(); flecs::entity get_building_entity(const String &key) const;
void load_tile(int x, int z);
}; };
#endif #endif

View File

@@ -67,6 +67,8 @@ void BuildingsEditor::event_handler(const String &event,
handle_create_building(); handle_create_building();
else if (event == "button:delete_building") else if (event == "button:delete_building")
delete_building_handler(); delete_building_handler();
else if (event == "button:edit_layout")
create_layout_editor();
else if (event == "result:get_closest_building") { else if (event == "result:get_closest_building") {
select_building(args[0], args[3], args[4]); select_building(args[0], args[3], args[4]);
if (get_buildings_editor_mode() == 2 /* rotate */) { if (get_buildings_editor_mode() == 2 /* rotate */) {
@@ -249,8 +251,26 @@ void BuildingsEditor::mouse_press(const Vector2 &position)
case 0: { case 0: {
/* select */ /* select */
Transform xform(Basis(), proj); Transform xform(Basis(), proj);
editor->editor_command("get_closest_building", flecs::entity e =
varray(xform)); BaseData::get_singleton()
->get()
.get_mut<BuildingsData>()
->get_closest_building_entity(xform);
assert(e.is_valid());
e.add<BuildingsData::CBuildingEdited>();
const BuildingsData::CBuildingData *b =
e.get<BuildingsData::CBuildingData>();
print_line("selected: " + b->building.id);
select_building(b->building.xform, b->building.key,
b->building.id);
if (get_buildings_editor_mode() == 2 /* rotate */) {
/* move rot cursor too */
get_as_node<Spatial>("%building_rot_cursor")
->set_global_transform(
selected_building_xform);
}
// editor->editor_command("get_closest_building",
// varray(xform));
} break; } break;
case 1: { case 1: {
/* move */ /* move */
@@ -417,3 +437,8 @@ const Node *BuildingsEditor::scene() const
const Node *ret = editor->get_tree()->get_current_scene(); const Node *ret = editor->get_tree()->get_current_scene();
return ret; return ret;
} }
void BuildingsEditor::create_layout_editor()
{
assert(false);
}

View File

@@ -37,5 +37,6 @@ public:
template <class T> const T *get_as_node(const String &path) const; template <class T> const T *get_as_node(const String &path) const;
Node *scene(); Node *scene();
const Node *scene() const; const Node *scene() const;
void create_layout_editor();
}; };
#endif #endif

View File

@@ -1,3 +1,5 @@
#undef NDEBUG
#include <cassert>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <core/os/memory.h> #include <core/os/memory.h>
@@ -14,8 +16,61 @@
#include "editor_event.h" #include "editor_event.h"
#include "game_event.h" #include "game_event.h"
#include "persistent_data.h" #include "persistent_data.h"
#include "buildings_data.h"
#include "npc.h" #include "npc.h"
static ConfigFile npcconf;
NPC::NPC(flecs::world &ecs)
{
ecs.module<NPC>();
ecs.component<struct NPCBase>();
ecs.observer<NPCControl>()
.event(flecs::OnSet)
.each([&](flecs::iter &it, size_t i,
struct NPCControl &control) {
if (control.command_id == NPCControl::CMD_PRESIM) {
generate_random_npcs(it.world());
simulate_past(it.world());
}
it.entity(i).destruct();
});
}
/* should be run on new game */
void NPC::simulate_past(flecs::world ecs)
{
int i;
Error err = npcconf.load("res://config/npc.conf");
assert(err == OK);
#if 0
for (i = 0; i < 100000; i++) {
if (npcconf.has_section("npc/" + itos(i))) {
String name = npcconf.get_value("npc/" + itos(i),
"name", "Nobody");
int age =
npcconf.get_value("npc/" + itos(i), "age", 18);
String sex = npcconf.get_value("npc/" + itos(i), "name",
"male");
flecs::entity e =
}
}
#endif
// assert(false);
}
void NPC::generate_random_npcs(flecs::world ecs)
{
flecs::query<const BuildingsData::CBuildingData> query =
ecs.query_builder<const BuildingsData::CBuildingData>()
.with<BuildingsData::CBTypeResidental>()
.build();
query.each([](flecs::entity e, const BuildingsData::CBuildingData &bd) {
print_line(String(e.name()));
print_line("id: " + bd.building.id);
});
}
#if 0
class NPCSaveData : public PersistentData::SaveHandler { class NPCSaveData : public PersistentData::SaveHandler {
public: public:
NPC *npc; NPC *npc;
@@ -39,58 +94,6 @@ struct NPCBase {
int id; int id;
}; };
struct NPCSkeleton {
String skeleton_path;
};
struct NPCNode {
Skeleton *skeleton;
};
struct NPCLocation {
Transform global_location, local_position;
};
struct NPCTarget {
Transform target;
};
struct NPCTargetKey {
String location_key;
};
struct NPCBackgroundMotion {
float speed;
};
struct NPCBody {
/* TODO: implement */
void *nothing;
};
struct NPCAnimation {
/* TODO: implement */
void *nothing;
};
struct NPCResidence {
String residence_key;
};
struct NPCOccupation {
/* building key */
String occupation_key;
// index in building's job list
int job_type;
int start_hour;
int end_hour;
// bit field from mon to sun
int week_days;
};
/* Assign leisure on the go depending on
character mood and stats */
struct NPCLeisure {
String leisure_key;
};
struct module { struct module {
module(flecs::world &ecs) module(flecs::world &ecs)
{ {
@@ -105,70 +108,12 @@ struct module {
ecs.component<struct NPCResidence>(); ecs.component<struct NPCResidence>();
ecs.component<struct NPCOccupation>(); ecs.component<struct NPCOccupation>();
ecs.component<struct NPCLeisure>(); ecs.component<struct NPCLeisure>();
ecs.observer<struct NPCSkeleton>()
.event(flecs::OnSet)
.with<struct NPCBase>()
.with<struct NPCLocation>()
.write<struct NPCNode>()
.each([](flecs::entity e, const NPCSkeleton &s) {
Ref<SkeletonData> skeleton_data;
String path = s.skeleton_path;
if (e.has<NPCNode>()) {
if (e.get<NPCNode>()->skeleton) {
e.get_mut<NPCNode>()
->skeleton
->queue_delete();
e.get_mut<NPCNode>()->skeleton =
nullptr;
e.remove<NPCNode>();
}
}
Node *root = SceneTree::get_singleton()
->get_current_scene();
if (!root) {
print_error("No scene");
return;
}
skeleton_data = ResourceLoader::load(
path, "SkeletonData");
if (skeleton_data.is_valid()) {
Skeleton *skeleton = memnew(Skeleton);
skeleton_data->load_skeleton(skeleton);
e.set<NPCNode>({ skeleton });
root->call_deferred("add_child",
skeleton);
} else
print_error(
"ERROR: Could not load skeleton: " +
path);
});
ecs.observer<struct NPCSkeleton>()
.event(flecs::OnRemove)
.write<struct NPCNode>()
.each([](flecs::entity e, const NPCSkeleton &s) {
if (e.has<NPCNode>()) {
if (e.get<NPCNode>()->skeleton) {
e.get_mut<NPCNode>()
->skeleton
->queue_delete();
e.get_mut<NPCNode>()->skeleton =
nullptr;
e.remove<NPCNode>();
}
}
});
/* moving NPC despawned NPC */
ecs.system<NPCBase>("Update").each(
[](flecs::entity e, NPCBase &b) {
// TODO: implement;
});
} }
}; };
} }
NPC::NPC() void NPC::create()
{ {
flecs::world ecs = BaseData::get_singleton()->get(); flecs::world ecs = BaseData::get_singleton()->get();
ecs.import <NPCModule::module>(); ecs.import <NPCModule::module>();
@@ -176,10 +121,12 @@ NPC::NPC()
if (base.is_valid()) { if (base.is_valid()) {
/* create components for top level */ /* create components for top level */
} }
#if 0
EditorEvent::get_singleton()->event.add_listener( EditorEvent::get_singleton()->event.add_listener(
this, &NPC::editor_event_handler); this, &NPC::editor_event_handler);
GameEvent::get_singleton()->event.add_listener( GameEvent::get_singleton()->event.add_listener(
this, &NPC::game_event_handler); this, &NPC::game_event_handler);
#endif
} }
NPC *NPC::get_singleton() NPC *NPC::get_singleton()
@@ -202,70 +149,13 @@ void NPC::update(float delta)
{ {
} }
flecs::entity NPC::foreground_character(int id)
{
String ch_name = "ch_" + itos(id);
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity base = ecs.lookup("characters");
flecs::entity ch = base.lookup(ch_name.ascii().ptr());
if (!ch.is_valid())
ch = ecs.entity(ch_name.ascii().ptr()).child_of(base);
assert(ch.is_valid());
if (!ch.has<NPCModule::NPCBase>())
ch.set<NPCModule::NPCBase>({ id });
return ch;
}
void NPC::background_character(int id)
{
String ch_name = "ch_" + itos(id);
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity base = ecs.lookup("characters");
flecs::entity ch = base.lookup(ch_name.ascii().ptr());
assert(ch.is_valid());
/* remove all components */
std::vector<flecs::entity_t> keep_components = {
ecs.component<NPCModule::NPCBase>()
};
ch.each([&ch, keep_components](flecs::entity_t c) {
if (std::find(keep_components.begin(), keep_components.end(),
c) == keep_components.end())
ch.remove(c);
});
}
void NPC::get_character_list(List<int> *character_list)
{
Error err;
DirAccess *d = DirAccess::open("res://character/config", &err);
d->list_dir_begin();
String conf_path;
while ((conf_path = d->get_next()) != "") {
ConfigFile config;
config.load(conf_path);
int id = config.get_value("base", "id");
}
d->list_dir_end();
}
void NPC::editor_event_handler(const String &event, const Vector<Variant> &args) void NPC::editor_event_handler(const String &event, const Vector<Variant> &args)
{ {
if (event == "npc_foreground") { /* not implemented */
int npc_id = args[0];
foreground_character(npc_id);
} else if (event == "npc_background") {
int npc_id = args[0];
background_character(npc_id);
}
} }
void NPC::game_event_handler(const String &event, const Vector<Variant> &args) void NPC::game_event_handler(const String &event, const Vector<Variant> &args)
{ {
if (event == "npc_foreground") { /* not implemented */
int npc_id = args[0];
foreground_character(npc_id);
} else if (event == "npc_background") {
int npc_id = args[0];
background_character(npc_id);
}
} }
#endif

View File

@@ -1,23 +1,37 @@
#ifndef NPC_H_ #ifndef NPC_H_
#define NPC_H_ #define NPC_H_
class ConfigFile; #include <flecs.h>
class NPC { struct NPC {
static NPC *singleton; NPC(flecs::world &ecs);
NPC(); struct NPCBase {
int id;
int age; // days
};
struct NPCSexMale {};
struct NPCSexFemale {};
struct NPCControl {
enum {
CMD_IDLE = 0,
CMD_PRESIM = 1,
CMD_LOAD = 2,
CMD_SAVE = 3,
CMD_SIM = 4,
};
int command_id;
};
void simulate_past(flecs::world ecs);
void generate_random_npcs(flecs::world ecs);
#if 0
public: public:
static NPC *get_singleton(); static void create();
static void cleanup(); static void cleanup();
virtual ~NPC(); virtual ~NPC();
void update(float delta);
flecs::entity foreground_character(int id);
void background_character(int id);
static void get_character_list(List<int> *character_list);
private: private:
void editor_event_handler(const String &event, void editor_event_handler(const String &event,
const Vector<Variant> &args); const Vector<Variant> &args);
void game_event_handler(const String &event, void game_event_handler(const String &event,
const Vector<Variant> &args); const Vector<Variant> &args);
#endif
}; };
#endif #endif

View File

@@ -10,6 +10,8 @@
#include "npc/importer.h" #include "npc/importer.h"
#include "npc/skeleton_data.h" #include "npc/skeleton_data.h"
#include "base_data.h" #include "base_data.h"
#include "building_grid_instance.h"
#include "buildings/building_layout_instance.h"
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
static void _editor_init() static void _editor_init()
@@ -30,6 +32,8 @@ void register_stream_types()
ClassDB::register_class<BuildingLayoutEditor>(); ClassDB::register_class<BuildingLayoutEditor>();
ClassDB::register_class<MainTabs>(); ClassDB::register_class<MainTabs>();
ClassDB::register_class<SkeletonData>(); ClassDB::register_class<SkeletonData>();
ClassDB::register_class<BuildingGridInstance>();
ClassDB::register_class<BuildingLayoutInstance>();
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
ClassDB::APIType prev_api = ClassDB::get_current_api(); ClassDB::APIType prev_api = ClassDB::get_current_api();
ClassDB::set_current_api(ClassDB::API_EDITOR); ClassDB::set_current_api(ClassDB::API_EDITOR);

View File

@@ -431,15 +431,20 @@ void RoadLinesEditor::move_cursor_to_point()
set_ui_cursor_position(xform.origin); set_ui_cursor_position(xform.origin);
} }
static inline BuildingsData *bd()
{
BuildingsData *ret =
BaseData::get_singleton()->get().get_mut<BuildingsData>();
assert(ret);
return ret;
}
void RoadLinesEditor::move_cursor_to_closest_building() void RoadLinesEditor::move_cursor_to_closest_building()
{ {
print_line("move_cursor_to_closest_building"); print_line("move_cursor_to_closest_building");
Vector3 pt = get_cursor_position(); Vector3 pt = get_cursor_position();
const String &key = const String &key = bd()->get_closest_building(Transform(Basis(), pt));
BuildingsData::get_singleton()->get_closest_building( const Transform &xform = bd()->get_building(key).xform;
Transform(Basis(), pt));
const Transform &xform =
BuildingsData::get_singleton()->get_building(key).xform;
set_cursor_position(xform.origin); set_cursor_position(xform.origin);
Spatial *cursor = get_as_node<Spatial>(cursor_name); Spatial *cursor = get_as_node<Spatial>(cursor_name);
if (!cursor->is_visible()) if (!cursor->is_visible())
@@ -1120,8 +1125,7 @@ class EdgeEditorHandler {
continue; continue;
} }
const AABB &aabb_building = const AABB &aabb_building =
BuildingsData::get_singleton() bd()->building_aabbs[buildings[i].id];
->building_aabbs[buildings[i].id];
Transform building_rot( Transform building_rot(
Basis().rotated( Basis().rotated(
Vector3(0, 1, 0), Vector3(0, 1, 0),
@@ -1302,10 +1306,9 @@ class EdgeEditorHandler {
String lot_id = side.lot_type; String lot_id = side.lot_type;
if (side.buildings.size() > 1) { if (side.buildings.size() > 1) {
const AABB &aabb_lot = const AABB &aabb_lot =
BuildingsData::get_singleton() bd()->building_aabbs
->building_aabbs ["lot-" +
["lot-" + lot_id];
lot_id];
bool pack_result = bool pack_result =
pack_buildings( pack_buildings(
aabb_lot, aabb_lot,
@@ -1372,10 +1375,9 @@ class EdgeEditorHandler {
String lot_id = side.lot_type; String lot_id = side.lot_type;
if (side.buildings.size() > 1) { if (side.buildings.size() > 1) {
const AABB &aabb_lot = const AABB &aabb_lot =
BuildingsData::get_singleton() bd()->building_aabbs
->building_aabbs ["lot-" +
["lot-" + lot_id];
lot_id];
bool pack_result = bool pack_result =
pack_buildings( pack_buildings(
aabb_lot, aabb_lot,

View File

@@ -487,6 +487,21 @@ struct LotPacker {
Vector<String> buildings; Vector<String> buildings;
float area; float area;
}; };
inline BuildingsData *bd()
{
BuildingsData *ret = BaseData::get_singleton()
->get()
.get_mut<BuildingsData>();
assert(ret);
return ret;
}
const inline BuildingsData *bd() const
{
const BuildingsData *ret =
BaseData::get_singleton()->get().get<BuildingsData>();
assert(ret);
return ret;
}
Vector<struct config_buildings> lot_buildings_residental, Vector<struct config_buildings> lot_buildings_residental,
lot_buildings_commercial, lot_buildings_industrial; lot_buildings_commercial, lot_buildings_industrial;
void get_building_list(const String &varname, void get_building_list(const String &varname,
@@ -502,8 +517,7 @@ struct LotPacker {
for (j = 0; j < entries.size(); j++) { for (j = 0; j < entries.size(); j++) {
String bname = entries[j]; String bname = entries[j];
cb.buildings.push_back(bname); cb.buildings.push_back(bname);
AABB aabb = BuildingsData::get_singleton() AABB aabb = get_building_type_aabb(bname);
->building_aabbs[bname];
cb.area += aabb.size.x * aabb.size.z; cb.area += aabb.size.x * aabb.size.z;
print_line("config building: " + bname); print_line("config building: " + bname);
} }
@@ -826,18 +840,22 @@ out_bad:
} }
bool tmp_found = false; bool tmp_found = false;
int office_count = 0; int office_count = 0;
AABB get_building_aabb(const String &key) AABB get_building_aabb(const String &key) const
{ {
const struct BuildingsData::building &b = const struct BuildingsData::building &b =
BuildingsData::get_singleton()->get_building(key); bd()->get_building(key);
const AABB &building_aabb = const AABB &building_aabb = bd()->building_aabbs[b.id];
BuildingsData::get_singleton()->building_aabbs[b.id]; return building_aabb;
}
AABB get_building_type_aabb(const String &building) const
{
const AABB &building_aabb = bd()->building_aabbs[building];
return building_aabb; return building_aabb;
} }
Transform get_building_transform(const String &key) Transform get_building_transform(const String &key)
{ {
const struct BuildingsData::building &b = const struct BuildingsData::building &b =
BuildingsData::get_singleton()->get_building(key); bd()->get_building(key);
return b.xform; return b.xform;
} }
AABB get_aabb_transformed(const String &key) AABB get_aabb_transformed(const String &key)
@@ -863,8 +881,7 @@ out_bad:
.each([&](flecs::entity e, Lot &lot_) { .each([&](flecs::entity e, Lot &lot_) {
assert(e.get<Lot>()->polygon.points.size() > 0); assert(e.get<Lot>()->polygon.points.size() > 0);
List<String> buildings; List<String> buildings;
BuildingsData::get_singleton() bd()->get_building_keys_list(&buildings);
->get_building_keys_list(&buildings);
List<String>::Element *be = buildings.front(); List<String>::Element *be = buildings.front();
e.get_mut<Lot>()->polygon.update_aabb(); e.get_mut<Lot>()->polygon.update_aabb();
if (e.has<PreOccupied>()) if (e.has<PreOccupied>())
@@ -872,8 +889,7 @@ out_bad:
while (be) { while (be) {
const String &key = be->get(); const String &key = be->get();
const struct BuildingsData::building &b = const struct BuildingsData::building &b =
BuildingsData::get_singleton() bd()->get_building(key);
->get_building(key);
if (key.begins_with("road__")) { if (key.begins_with("road__")) {
be = be->next(); be = be->next();
continue; continue;
@@ -935,8 +951,7 @@ out_bad:
lb.buildings[i]; lb.buildings[i];
const String &key = mp.second; const String &key = mp.second;
const struct BuildingsData::building &b = const struct BuildingsData::building &b =
BuildingsData::get_singleton() bd()->get_building(key);
->get_building(key);
Rect2 building_rect = Rect2 building_rect =
get_rect_transformed(key); get_rect_transformed(key);
Rect2 lot_rect = Rect2 lot_rect =
@@ -1096,19 +1111,19 @@ out_bad:
lot.polygon.update_aabb(); lot.polygon.update_aabb();
}); });
} }
#if 0
float get_required_area(const Vector<String> &buildings) const float get_required_area(const Vector<String> &buildings) const
{ {
float ret = 0.0f; float ret = 0.0f;
int i; int i;
for (i = 0; i < (int)buildings.size(); i++) { for (i = 0; i < (int)buildings.size(); i++) {
const String &building = buildings[i]; const String &building = buildings[i];
const AABB &building_aabb = const AABB &building_aabb = get_building_aabb(building);
BuildingsData::get_singleton()
->building_aabbs[building];
ret += building_aabb.size.x * building_aabb.size.z; ret += building_aabb.size.x * building_aabb.size.z;
} }
return ret; return ret;
} }
#endif
int get_selected_building(const Lot &lot, int get_selected_building(const Lot &lot,
Vector<struct config_buildings> &lbs) Vector<struct config_buildings> &lbs)
{ {
@@ -1200,9 +1215,8 @@ out_bad:
const String &building = const String &building =
buildings[i]; buildings[i];
const AABB &building_aabb = const AABB &building_aabb =
BuildingsData::get_singleton() get_building_type_aabb(
->building_aabbs building);
[building];
AABB result = pack_item( AABB result = pack_item(
e, e,
building_aabb, building_aabb,

View File

@@ -86,22 +86,27 @@ struct RoadLinesProcessing {
String road_center_mesh_path, road_mid_mesh_path, String road_center_mesh_path, road_mid_mesh_path,
road_sidewalk_mesh_path; road_sidewalk_mesh_path;
int debug_flags; int debug_flags;
static struct RoadLinesProcessing *singleton;
static RoadLinesProcessing *get_singleton()
{
if (!singleton)
singleton = memnew(RoadLinesProcessing);
return singleton;
}
DebugGeo *dbg; DebugGeo *dbg;
ConfigFile config; static ConfigFile config;
RoadLinesProcessing() RoadLinesProcessing()
: dbg(nullptr) : dbg(nullptr)
{ {
singleton = this;
Error err = config.load("res://config/stream.conf"); Error err = config.load("res://config/stream.conf");
assert(err == OK); assert(err == OK);
} }
RoadLinesProcessing &operator=(const RoadLinesProcessing &other)
{
dbg = other.dbg;
debug_flags = other.debug_flags;
edges = other.edges;
nodes = other.nodes;
road_center_mesh_path = other.road_center_mesh_path;
road_mid_mesh_path = other.road_mid_mesh_path;
road_sidewalk_mesh_path = other.road_sidewalk_mesh_path;
side_refs = other.side_refs;
wedges = other.wedges;
return *this;
}
void create_nodes(const std::vector<Vector3> &road_lines_nodes) void create_nodes(const std::vector<Vector3> &road_lines_nodes)
{ {
@@ -125,23 +130,37 @@ struct RoadLinesProcessing {
xform = xform * rot; xform = xform * rot;
return xform; return xform;
} }
inline BuildingsData *bd()
{
BuildingsData *ret = BaseData::get_singleton()
->get()
.get_mut<BuildingsData>();
assert(ret);
return ret;
}
inline const BuildingsData *bd() const
{
const BuildingsData *ret =
BaseData::get_singleton()->get().get<BuildingsData>();
assert(ret);
return ret;
}
void create_building_structure(const BuildingsData::building &b) void create_building_structure(const BuildingsData::building &b)
{ {
assert(b.key.begins_with("road__")); assert(b.key.begins_with("road__"));
assert(b.id.length() > 0); assert(b.id.length() > 0);
assert(b.key.length() > 0); assert(b.key.length() > 0);
if (BuildingsData::get_singleton()->has_building(b.key)) { if (bd()->has_building(b.key)) {
BuildingsData::get_singleton()->remove_scene_item( bd()->remove_scene_item(b.id, b.key);
b.id, b.key); bd()->destroy_building(b.key);
BuildingsData::get_singleton()->destroy_building(b.key);
} }
BuildingsData::get_singleton()->create_building(b); bd()->create_building(b);
if (!BuildingsData::get_singleton()->has_scene(b.id)) if (!bd()->has_scene(b.id))
BuildingsData::get_singleton()->create_scene_data( bd()->create_scene_data(b.id, b.key);
b.id, b.key);
else else
BuildingsData::get_singleton()->add_scene_item(b.id, bd()->add_scene_item(b.id, b.key);
b.key);
print_line("created building: " + b.key + " " + b.id); print_line("created building: " + b.key + " " + b.id);
print_line("at: " + (b.xform.origin.operator String())); print_line("at: " + (b.xform.origin.operator String()));
print_line("created ok"); print_line("created ok");
@@ -414,394 +433,6 @@ out2:;
/* FIXME: need to generate lots from wedges, not lines (because intersections) /* FIXME: need to generate lots from wedges, not lines (because intersections)
and join lots on the same line segment if they are adjacent and of similar depth and join lots on the same line segment if they are adjacent and of similar depth
and not too narrow */ and not too narrow */
void update_lot_depths()
{
#if 0
int i, j, k;
struct line_check {
struct side_ref side;
Vector3 normal;
float depth;
Vector3 startp;
AABB rect;
};
LocalVector<struct line_check> check_lines;
RoadLinesProcessing *r = RoadLinesProcessing::get_singleton();
if (r->nodes.size() == 0)
return;
if (r->nodes.empty())
goto out_skip_end;
// dbg->set_material_override(dbg_mat);
if (!dbg &&
VisualServer::get_singleton()->is_render_loop_enabled()) {
dbg = memnew(DebugGeo);
SceneTree::get_singleton()
->get_current_scene()
->call_deferred("add_child", dbg);
}
print_line("wedges size:" + itos(r->nodes.size()));
dbg->clear();
dbg->begin(Mesh::PRIMITIVE_LINES);
dbg->set_color(Color(1, 0, 0, 1));
dbg->set_color(Color(1, 0, 0, 1));
for (i = 0; i < (int)r->nodes.size(); i++) {
const std::vector<struct wedge> &ws = wedges[i];
int wsize = ws.size();
for (j = 0; j < wsize; j++) {
const struct wedge &w = wedges[i][j];
struct RoadLinesData::road_edge_side mside1 =
RoadLinesData::get_singleton()
->get_line_edge_side(
w.side1_ref.line_key,
w.side1_ref.edge,
w.side1_ref.side);
struct RoadLinesData::road_edge_side mside2 =
RoadLinesData::get_singleton()
->get_line_edge_side(
w.side2_ref.line_key,
w.side2_ref.edge,
w.side2_ref.side);
Vector3 d1 = (w.p[1] - w.p[0]).normalized();
Vector3 d2 = (w.p[2] - w.p[1]).normalized();
Vector3 n1 = (w.p[0] - w.y[0]).normalized();
Vector3 n2 = (w.p[1] - w.y[1]).normalized();
Vector3 n3 = (w.p[2] - w.y[2]).normalized();
mside1.lot_depth_eff =
MAX(mside1.lot_depth_eff, 200.0f);
mside2.lot_depth_eff =
MAX(mside2.lot_depth_eff, 200.0f);
assert(mside1.lot_depth_eff > 0.001);
assert(mside2.lot_depth_eff > 0.001);
struct line_check lc1, lc2;
int nlanes1 = w.width1 / 5.0f;
int nlanes2 = w.width2 / 5.0f;
float m = (w.p[1] - w.y[1]).length() /
(w.p[0] - w.y[0]).length();
lc1.side = w.side1_ref;
lc1.depth = mside1.lot_depth_eff;
lc1.normal = n1;
lc1.startp = w.p[0] + (w.width1 - 4.0f) * n1;
lc1.rect.position = lc1.startp;
lc1.rect.size = Vector3();
lc1.rect.expand_to(lc1.startp + n1 * lc1.depth);
lc2.side = w.side2_ref;
lc2.depth = MIN(mside1.lot_depth_eff,
mside2.lot_depth_eff);
lc2.normal = n2;
Vector3 x = n2 * (w.width2 - 4.0f) * m;
lc2.startp = w.p[1] + x;
lc2.rect.position = lc2.startp;
lc2.rect.size = Vector3();
lc2.rect.expand_to(lc2.startp + n2 * lc2.depth);
check_lines.push_back(lc1);
check_lines.push_back(lc2);
}
}
assert(check_lines.size() > 0);
for (i = 0; i < (int)check_lines.size(); i++) {
for (j = 0; j < (int)r->nodes.size(); j++) {
const std::vector<struct wedge> &ws = wedges[j];
int wsize = ws.size();
for (k = 0; k < wsize; k++) {
const struct wedge &w = ws[k];
Vector3 p0 = check_lines[i].startp;
Vector3 p1 =
p0 +
check_lines[i].normal *
check_lines[i].depth;
Vector3 p2 = w.p[0];
Vector3 p3 = w.p[1];
Vector3 s, t;
/* samey segments do not intersect */
if (p0.is_equal_approx(p2) &&
p1.is_equal_approx(p3))
continue;
if (p0.is_equal_approx(p3) &&
p1.is_equal_approx(p2))
continue;
/* segments which share a point do not intersect */
if (p0.is_equal_approx(p2))
continue;
if (p0.is_equal_approx(p3))
continue;
if (p1.is_equal_approx(p3))
continue;
if (p1.is_equal_approx(p2))
continue;
assert(!p0.is_equal_approx(p1) &&
!p2.is_equal_approx(p3));
Geometry::get_closest_points_between_segments(
p0, p1, p2, p3, s, t);
if (s.is_equal_approx(p0))
continue;
if (s.is_equal_approx(p1))
continue;
if (t.is_equal_approx(p2))
continue;
if (t.is_equal_approx(p3))
continue;
assert(!s.is_equal_approx(p0));
assert(!s.is_equal_approx(p1));
assert(!t.is_equal_approx(p2));
assert(!t.is_equal_approx(p3));
Vector3 mx(t.x, s.y, t.z);
if (!s.is_equal_approx(mx))
continue;
if (Math::abs(s.y - t.y) < 5.0f) {
if (s.is_equal_approx(mx)) {
float l1 =
p0.distance_to(
s);
check_lines[i]
.depth = MIN(
check_lines[i]
.depth,
l1);
}
}
}
}
}
for (i = 0; i < (int)check_lines.size(); i++) {
Vector3 p0 = check_lines[i].startp;
Vector3 p1 = p0 + check_lines[i].normal *
check_lines[i].depth;
assert(p0.distance_squared_to(p1) > 0.001f);
dbg->set_color(Color(1, 0, 0, 1));
dbg->add_vertex(p0);
dbg->add_vertex(p0 + Vector3(0, 100, 0));
dbg->add_vertex(p1);
dbg->add_vertex(p1 + Vector3(0, 100, 0));
dbg->set_color(Color(0, 0, 1, 1));
dbg->add_vertex(p0);
dbg->add_vertex(p1);
for (j = 0; j < (int)check_lines.size(); j++) {
if (i == j)
continue;
Vector3 p2 = check_lines[j].startp;
Vector3 p3 = p2 + check_lines[j].normal *
check_lines[j].depth;
Vector3 s, t;
/* samey segments do not intersect */
if (p0.is_equal_approx(p2) &&
p1.is_equal_approx(p3))
continue;
if (p0.is_equal_approx(p3) &&
p1.is_equal_approx(p2))
continue;
/* segments which share a point do not intersect */
if (p0.is_equal_approx(p2))
continue;
if (p0.is_equal_approx(p3))
continue;
if (p1.is_equal_approx(p3))
continue;
if (p1.is_equal_approx(p2))
continue;
assert(!p0.is_equal_approx(p1) &&
!p2.is_equal_approx(p3));
Geometry::get_closest_points_between_segments(
p0, p1, p2, p3, s, t);
if (s.is_equal_approx(p0))
continue;
if (s.is_equal_approx(p1))
continue;
if (t.is_equal_approx(p2))
continue;
if (t.is_equal_approx(p3))
continue;
assert(!s.is_equal_approx(p0));
assert(!s.is_equal_approx(p1));
assert(!t.is_equal_approx(p2));
assert(!t.is_equal_approx(p3));
Vector3 mx(t.x, s.y, t.z);
if (!s.is_equal_approx(mx))
continue;
if (Math::abs(s.y - t.y) < 5.0f) {
if (s.is_equal_approx(mx)) {
dbg->set_color(
Color(0, 1, 0, 1));
dbg->add_vertex(
s +
Vector3(-0.5, 15, 0));
dbg->add_vertex(s + Vector3(0.5,
100,
0));
float l1 = p0.distance_to(s);
float l2 = p2.distance_to(t);
check_lines[i].depth = MIN(
check_lines[i].depth,
l1);
check_lines[j].depth = MIN(
check_lines[j].depth,
l2);
}
}
}
}
dbg->end();
dbg->clear();
dbg->begin(Mesh::PRIMITIVE_LINES);
dbg->set_color(Color(1, 0, 0, 1));
for (i = 0; i < (int)check_lines.size(); i++) {
Vector3 p0 = check_lines[i].startp;
Vector3 p1 = p0 + check_lines[i].normal *
check_lines[i].depth;
assert(p0.distance_squared_to(p1) > 0.001f);
dbg->set_color(Color(1, 0, 0, 1));
dbg->add_vertex(p0);
dbg->add_vertex(p0 + Vector3(0, 100, 0));
dbg->add_vertex(p1);
dbg->add_vertex(p1 + Vector3(0, 100, 0));
dbg->set_color(Color(0, 0, 1, 1));
dbg->add_vertex(p0);
dbg->add_vertex(p1);
struct side_ref &side1 = check_lines[i].side;
struct RoadLinesData::road_edge_side mside1 =
RoadLinesData::get_singleton()
->get_line_edge_side(side1.line_key,
side1.edge,
side1.side);
mside1.lot_depth_eff = check_lines[i].depth;
mside1.lot_depth = mside1.lot_depth_eff;
int bad_count = 0;
int lot_points = mside1.lot_points.size();
assert(lot_points == 0 || lot_points == 2);
for (j = 0; j < mside1.lot_points.size(); j++) {
if (!mside1.lot_points[j].is_equal_approx(p0))
bad_count++;
if (!mside1.lot_points[j].is_equal_approx(p1))
bad_count++;
}
if (bad_count < 2) {
mside1.lot_points.push_back(p0);
mside1.lot_points.push_back(p1);
}
if (side1.side == 0)
RoadLinesData::get_singleton()
->set_line_edge_left(side1.line_key,
side1.edge,
mside1);
else
RoadLinesData::get_singleton()
->set_line_edge_right(side1.line_key,
side1.edge,
mside1);
}
dbg->end();
dbg->begin(Mesh::PRIMITIVE_LINES);
dbg->set_color(Color(0, 1, 1, 1));
{
List<String> line_keys;
List<String>::Element *line_e;
RoadLinesData *rld = RoadLinesData::get_singleton();
rld->get_road_lines_key_list(&line_keys);
line_e = line_keys.front();
while (line_e) {
const String &key = line_e->get();
print_line("line: " + key);
int edges = rld->get_line_edge_count(key);
for (i = 0; i < edges; i++) {
RoadLinesData::road_edge_side left =
rld->get_line_edge_left(key, i);
RoadLinesData::road_edge_side right =
rld->get_line_edge_right(key,
i);
print_line("edge: " + itos(i) +
" left: lot: " +
itos(left.lot));
print_line("edge: " + itos(i) +
" right: lot: " +
itos(right.lot));
print_line(
"lot_points: left: " +
itos(left.lot_points.size()));
print_line(
"lot_points: right: " +
itos(right.lot_points.size()));
for (j = 0;
j < (int)left.lot_points.size();
j++) {
dbg->add_vertex(
left.lot_points[j] +
Vector3(0, 20, 0));
dbg->add_vertex(
left.lot_points[j] +
Vector3(0, 200, 0));
}
if (left.lot_points.size() == 6) {
int index[] = { 0, 1, 1, 3,
3, 5, 5, 4 };
for (j = 0; j < 8; j++) {
dbg->add_vertex(
left.lot_points
[index[j]] +
Vector3(0, 25,
0));
print_line(
itos(j) + ": " +
left.lot_points[index[j]]
.
operator String());
}
assert(false);
} else if (left.lot_points.size() ==
4) {
int index[] = { 0, 1, 1, 3,
3, 2, 2, 0 };
for (j = 0; j < 8; j++)
dbg->add_vertex(
left.lot_points
[index[j]] +
Vector3(0, 25,
0));
}
for (j = 0;
j < (int)right.lot_points.size();
j++) {
dbg->add_vertex(
right.lot_points[j] +
Vector3(0, 20, 0));
dbg->add_vertex(
right.lot_points[j] +
Vector3(0, 200, 0));
}
if (right.lot_points.size() == 6) {
dbg->add_vertex(
right.lot_points[0] +
Vector3(0, 25, 0));
dbg->add_vertex(
right.lot_points[1] +
Vector3(0, 25, 0));
dbg->add_vertex(
right.lot_points[1] +
Vector3(0, 25, 0));
dbg->add_vertex(
right.lot_points[3] +
Vector3(0, 25, 0));
dbg->add_vertex(
right.lot_points[3] +
Vector3(0, 25, 0));
dbg->add_vertex(
right.lot_points[2] +
Vector3(0, 25, 0));
dbg->add_vertex(
right.lot_points[2] +
Vector3(0, 25, 0));
dbg->add_vertex(
right.lot_points[0] +
Vector3(0, 25, 0));
}
}
line_e = line_e->next();
}
}
dbg->end();
out_skip_end:;
#endif
}
void create_structures() void create_structures()
{ {
List<String> keys; List<String> keys;
@@ -852,13 +483,13 @@ out_skip_end:;
->get() ->get()
.query_builder<Lot>() .query_builder<Lot>()
.build() .build()
.each([&](flecs::entity e, Lot &lot) { .each([&](flecs::entity ev, Lot &lot) {
BaseData::get_singleton() BaseData::get_singleton()
->get() ->get()
.query_builder<Lot>() .query_builder<Lot>()
.build() .build()
.each([&](flecs::entity we, Lot &wlot) { .each([&](flecs::entity we, Lot &wlot) {
if (e != we) { if (ev != we) {
lot.polygon lot.polygon
.update_aabb(); .update_aabb();
wlot.polygon wlot.polygon
@@ -868,7 +499,7 @@ out_skip_end:;
.length() > .length() >
100000.0f * 100000.0f *
1000000.0f) 1000000.0f)
e.destruct(); ev.destruct();
else if (wlot.polygon else if (wlot.polygon
.aabb .aabb
.size .size
@@ -890,7 +521,7 @@ out_skip_end:;
.area()) .area())
we.destruct(); we.destruct();
else else
e.destruct(); ev.destruct();
} }
} }
}); });
@@ -899,12 +530,11 @@ out_skip_end:;
->get() ->get()
.query_builder<Lot>() .query_builder<Lot>()
.build() .build()
.each([&](flecs::entity e, const Lot &lot) { .each([&](flecs::entity em, const Lot &lot) {
List<Pair<AABB, String> > lot_data; List<Pair<AABB, String> > lot_data;
Lot::get_lot_data(e, &lot_data); Lot::get_lot_data(em, &lot_data);
List<Pair<AABB, String> >::Element *lot_e = List<Pair<AABB, String> >::Element *lot_e =
lot_data.front(); lot_data.front();
int ccount = 0;
while (lot_e) { while (lot_e) {
Pair<AABB, String> data = lot_e->get(); Pair<AABB, String> data = lot_e->get();
Vector3 center = data.first.position; Vector3 center = data.first.position;
@@ -924,8 +554,8 @@ out_skip_end:;
data.first. data.first.
operator String()); operator String());
for (j = 0; for (j = 0;
j < j < (int)lot.polygon.points
lot.polygon.points.size(); .size();
j++) j++)
print_line( print_line(
"polygon: " + "polygon: " +
@@ -942,11 +572,11 @@ out_skip_end:;
->get() ->get()
.query_builder<Lot>() .query_builder<Lot>()
.build() .build()
.each([&](flecs::entity e, const Lot &lot) { .each([&](flecs::entity ev, const Lot &lot) {
List<Pair<AABB, String> > lot_data; List<Pair<AABB, String> > lot_data;
List<Transform> lot_xform; List<Transform> lot_xform;
Lot::get_lot_data(e, &lot_data); Lot::get_lot_data(ev, &lot_data);
Lot::get_lot_rotations(e, &lot_xform); Lot::get_lot_rotations(ev, &lot_xform);
List<Pair<AABB, String> >::Element *lot_e = List<Pair<AABB, String> >::Element *lot_e =
lot_data.front(); lot_data.front();
List<Transform>::Element *lotx_e = List<Transform>::Element *lotx_e =
@@ -955,7 +585,7 @@ out_skip_end:;
while (lot_e) { while (lot_e) {
Pair<AABB, String> data = lot_e->get(); Pair<AABB, String> data = lot_e->get();
String key = "road__lot__" + String key = "road__lot__" +
String(e.path()) + "_" + String(ev.path()) + "_" +
itos(ccount); itos(ccount);
key = key.replace("#", "_"); key = key.replace("#", "_");
BuildingsData::building b; BuildingsData::building b;
@@ -1290,7 +920,8 @@ out_skip_end:;
{ {
int i, j; int i, j;
Contours *contours = Contours::get_singleton(); Contours *contours = Contours::get_singleton();
RoadLinesProcessing *r = RoadLinesProcessing::get_singleton(); // RoadLinesProcessing *r = BaseData::get_singleton() ->get() .get_mut<RoadLinesProcessing>();
RoadLinesProcessing *r = this;
if (r->nodes.size() == 0) if (r->nodes.size() == 0)
return; return;
struct wedge_data { struct wedge_data {
@@ -1393,13 +1024,6 @@ out_skip_end:;
~RoadLinesProcessing() ~RoadLinesProcessing()
{ {
} }
static void cleanup()
{
if (singleton) {
memfree(singleton);
singleton = nullptr;
}
}
void set_debug_flags(int debug_flags) void set_debug_flags(int debug_flags)
{ {
this->debug_flags = debug_flags; this->debug_flags = debug_flags;
@@ -1490,11 +1114,11 @@ out_skip_end:;
} }
d->end(); d->end();
} }
RoadLinesProcessing::get_singleton()->create_structures(); create_structures();
print_line("ROAD SETUP DONE"); print_line("ROAD SETUP DONE");
} }
}; };
RoadLinesProcessing *RoadLinesProcessing::singleton; ConfigFile RoadLinesProcessing::config;
class RoadMeshProcessing { class RoadMeshProcessing {
struct mesh_data { struct mesh_data {
@@ -1513,11 +1137,41 @@ class RoadMeshProcessing {
} }
} }
}; };
struct wedge_paths {
Vector3 path1[3];
Vector3 path2[3];
};
struct lane {
Vector3 p[3];
String use_mesh; /** use mesh namefor this lane */
Transform xform1, xform2; /** rotations for ends
of this wedge start and end */
Transform xform_m1, xform_m2; /** rotations for middle point of
wedge for end and start of segment */
float l_seg1[3]; /** start segment scale */
float l_seg2[3]; /** end segment scale */
};
HashMap<String, struct mesh_data> road_meshes; HashMap<String, struct mesh_data> road_meshes;
MergeGroup *road_mgroup; MergeGroup *road_mgroup;
std::vector<MeshInstance *> nodes_mi; std::vector<MeshInstance *> nodes_mi;
public: public:
RoadMeshProcessing &operator=(const RoadMeshProcessing &other)
{
road_meshes = other.road_meshes;
road_mgroup = other.road_mgroup;
nodes_mi = other.nodes_mi;
return *this;
}
#if 0
RoadMeshProcessing &operator=(const RoadMeshProcessing &&other)
{
road_meshes = std::move(other.road_meshes);
road_mgroup = std::move(other.road_mgroup);
nodes_mi = std::move(other.nodes_mi);
return *this;
}
#endif
void load_road_mesh(const String &category, const String &name, void load_road_mesh(const String &category, const String &name,
const String &path) const String &path)
{ {
@@ -1542,10 +1196,6 @@ public:
} }
road_meshes[category + "/" + name] = md; road_meshes[category + "/" + name] = md;
} }
struct wedge_paths {
Vector3 path1[3];
Vector3 path2[3];
};
void get_paths(struct wedge_paths &paths, const struct wedge &w) void get_paths(struct wedge_paths &paths, const struct wedge &w)
{ {
Vector3 p1 = w.y[0] - w.y[1]; Vector3 p1 = w.y[0] - w.y[1];
@@ -1561,16 +1211,6 @@ public:
paths.path2[1] = p2a; paths.path2[1] = p2a;
paths.path2[2] = p3a; paths.path2[2] = p3a;
} }
struct lane {
Vector3 p[3];
String use_mesh; /** use mesh namefor this lane */
Transform xform1, xform2; /** rotations for ends
of this wedge start and end */
Transform xform_m1, xform_m2; /** rotations for middle point of
wedge for end and start of segment */
float l_seg1[3]; /** start segment scale */
float l_seg2[3]; /** end segment scale */
};
/** /**
* @brief transform mesh segment using start rotation @xform1 * @brief transform mesh segment using start rotation @xform1
* ane end rotation @xform2 * ane end rotation @xform2
@@ -1599,9 +1239,11 @@ public:
assert(vertices.size() > 0); assert(vertices.size() > 0);
assert(indices.size() > 0); assert(indices.size() > 0);
float dlen = xform1.origin.distance_to(xform2.origin); float dlen = xform1.origin.distance_to(xform2.origin);
#if 0
float offt = 0.0f; float offt = 0.0f;
if (dlen > start_offset) if (dlen > start_offset)
offt = start_offset; offt = start_offset;
#endif
int id; int id;
Vector3 dir = xform2.origin - xform1.origin; Vector3 dir = xform2.origin - xform1.origin;
dir = dir.normalized(); dir = dir.normalized();
@@ -2004,7 +1646,9 @@ public:
assert(out_surfaces[h].size() >= assert(out_surfaces[h].size() >=
ArrayMesh::ARRAY_MAX); ArrayMesh::ARRAY_MAX);
float sideroad_l = 3.0f; float sideroad_l = 3.0f;
#if 0
float lot_depth1 = mside1.lot_depth; float lot_depth1 = mside1.lot_depth;
#endif
if (k == params.nlanes && if (k == params.nlanes &&
mside1.lot > 0) { /* sidewalk */ mside1.lot > 0) { /* sidewalk */
Vector3 dir = lanes[k].xform_m1.origin - Vector3 dir = lanes[k].xform_m1.origin -
@@ -2197,7 +1841,10 @@ public:
void create_road_meshes(Node *base) void create_road_meshes(Node *base)
{ {
int i; int i;
RoadLinesProcessing *r = RoadLinesProcessing::get_singleton(); RoadLinesProcessing *r =
BaseData::get_singleton()
->get()
.get_mut<RoadLinesProcessing>();
clear_road_meshes(); clear_road_meshes();
road_mgroup = memnew(MergeGroup); road_mgroup = memnew(MergeGroup);
road_mgroup->set_param(MergeGroup::PARAM_GROUP_SIZE, 16); road_mgroup->set_param(MergeGroup::PARAM_GROUP_SIZE, 16);
@@ -2217,38 +1864,33 @@ public:
nodes_mi.push_back(mi); nodes_mi.push_back(mi);
} }
} }
static RoadMeshProcessing *singleton;
static RoadMeshProcessing *get_singleton()
{
if (!singleton)
singleton = memnew(RoadMeshProcessing);
return singleton;
}
RoadMeshProcessing() RoadMeshProcessing()
: road_mgroup(nullptr) : road_mgroup(nullptr)
{ {
singleton = this; BaseData::get_singleton()->get().ensure<RoadLinesProcessing>();
}
static void cleanup()
{
if (singleton) {
memdelete(singleton);
singleton = nullptr;
}
} }
}; };
RoadMeshProcessing *RoadMeshProcessing::singleton;
void RoadProcessing::road_setup(Node *target, int debug_flags) void RoadProcessing::road_setup(Node *target, int debug_flags)
{ {
RoadLinesProcessing::get_singleton()->set_debug_flags(debug_flags); BaseData::get_singleton()->get().ensure<RoadLinesProcessing>();
RoadLinesProcessing::get_singleton()->road_setup(); BaseData::get_singleton()->get().ensure<RoadMeshProcessing>();
RoadMeshProcessing::get_singleton()->create_road_meshes(target); RoadLinesProcessing *r =
BaseData::get_singleton()->get().get_mut<RoadLinesProcessing>();
r->set_debug_flags(debug_flags);
r->road_setup();
BaseData::get_singleton()
->get()
.get_mut<RoadMeshProcessing>()
->create_road_meshes(target);
} }
void RoadProcessing::remove_road_meshes(Node *target) void RoadProcessing::remove_road_meshes(Node *target)
{ {
RoadMeshProcessing::get_singleton()->clear_road_meshes(); BaseData::get_singleton()
->get()
.get_mut<RoadMeshProcessing>()
->clear_road_meshes();
} }
void RoadProcessing::load_data() void RoadProcessing::load_data()
@@ -2258,30 +1900,31 @@ void RoadProcessing::load_data()
ConfigFile config; ConfigFile config;
Error result = config.load("res://config/stream.conf"); Error result = config.load("res://config/stream.conf");
ERR_FAIL_COND_MSG(result != OK, "Failed to load config"); ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
RoadMeshProcessing::get_singleton()->load_road_mesh( BaseData::get_singleton()->get().ensure<RoadMeshProcessing>();
"common", "center", config.get_value("road", "center_mesh")); RoadMeshProcessing *rmp =
RoadMeshProcessing::get_singleton()->load_road_mesh( BaseData::get_singleton()->get().get_mut<RoadMeshProcessing>();
"common", "mid", config.get_value("road", "mid_mesh")); assert(rmp);
RoadMeshProcessing::get_singleton()->load_road_mesh( rmp->load_road_mesh("common", "center",
"common", "sidewalk", config.get_value("road", "center_mesh"));
config.get_value("road", "sidewalk_mesh")); rmp->load_road_mesh("common", "mid",
RoadMeshProcessing::get_singleton()->load_road_mesh( config.get_value("road", "mid_mesh"));
"common", "sidewalk_start", rmp->load_road_mesh("common", "sidewalk",
config.get_value("road", "sidewalk_start_mesh")); config.get_value("road", "sidewalk_mesh"));
RoadMeshProcessing::get_singleton()->load_road_mesh( rmp->load_road_mesh("common", "sidewalk_start",
"common", "sidewalk_end", config.get_value("road", "sidewalk_start_mesh"));
config.get_value("road", "sidewalk_end_mesh")); rmp->load_road_mesh("common", "sidewalk_end",
RoadMeshProcessing::get_singleton()->load_road_mesh( config.get_value("road", "sidewalk_end_mesh"));
"common", "sidewalk_sideroad", rmp->load_road_mesh("common", "sidewalk_sideroad",
config.get_value("road", "sidewalk_sideroad_mesh")); config.get_value("road", "sidewalk_sideroad_mesh"));
RoadMeshProcessing::get_singleton()->load_road_mesh( rmp->load_road_mesh("common", "lot",
"common", "lot", config.get_value("road", "lot_mesh")); config.get_value("road", "lot_mesh"));
} }
void RoadDebug::_notification(int which) void RoadDebug::_notification(int which)
{ {
int i, j; int i, j;
RoadLinesProcessing *r = RoadLinesProcessing::get_singleton(); RoadLinesProcessing *r =
BaseData::get_singleton()->get().get_mut<RoadLinesProcessing>();
std::unordered_map<int, RoadLinesProcessing::edgedata>::iterator it; std::unordered_map<int, RoadLinesProcessing::edgedata>::iterator it;
switch (which) { switch (which) {
case NOTIFICATION_ENTER_TREE: case NOTIFICATION_ENTER_TREE:
@@ -2379,6 +2022,6 @@ void RoadDebug::_notification(int which)
} }
void RoadProcessing::cleanup() void RoadProcessing::cleanup()
{ {
RoadLinesProcessing::cleanup(); BaseData::get_singleton()->get().remove<RoadLinesProcessing>();
RoadMeshProcessing::cleanup(); BaseData::get_singleton()->get().remove<RoadMeshProcessing>();
} }

View File

@@ -17,9 +17,17 @@
#include "base_data.h" #include "base_data.h"
#include "npc/npc.h" #include "npc/npc.h"
#include "stream.h" #include "stream.h"
static inline BuildingsData *bd()
{
BuildingsData *ret =
BaseData::get_singleton()->get().get_mut<BuildingsData>();
assert(ret);
return ret;
}
#define data() (BuildingsData::get_singleton()) #define data() (bd())
#if 0
void StreamWorld::create_tilemap() void StreamWorld::create_tilemap()
{ {
tiles.clear(); tiles.clear();
@@ -41,6 +49,7 @@ void StreamWorld::create_tilemap()
nullptr); nullptr);
print_verbose("Tile count: " + itos(tiles.size())); print_verbose("Tile count: " + itos(tiles.size()));
} }
#endif
void StreamWorld::update_view() void StreamWorld::update_view()
{ {
@@ -80,6 +89,7 @@ void StreamWorld::update_view()
current_x = world_extent + 1; current_x = world_extent + 1;
current_z = world_extent + 1; current_z = world_extent + 1;
} }
#if 0
eye = viewer->get_global_transform().origin; eye = viewer->get_global_transform().origin;
int tile_x = int(eye.x / tile_size); int tile_x = int(eye.x / tile_size);
int tile_z = int(eye.z / tile_size); int tile_z = int(eye.z / tile_size);
@@ -122,9 +132,10 @@ void StreamWorld::update_view()
it++; it++;
} }
current_x = tile_x; current_x = tile_x;
current_z = tile_z; current_z = tile_z;
} }
#endif
} }
void StreamWorld::viewer_dead() void StreamWorld::viewer_dead()
@@ -141,6 +152,7 @@ void StreamWorld::terrain_dead()
set_process(false); set_process(false);
} }
#if 0
void StreamWorld::load_tile(int tx, int ty) void StreamWorld::load_tile(int tx, int ty)
{ {
int i; int i;
@@ -151,6 +163,11 @@ void StreamWorld::load_tile(int tx, int ty)
": " /* + data()->get_building(items[i]).id */); ": " /* + data()->get_building(items[i]).id */);
const String &bkey = items[i]; const String &bkey = items[i];
load_building(bkey); load_building(bkey);
flecs::entity eb = data()->get_building_entity(bkey);
if (eb.is_valid()) {
if (!eb.has<BuildingsData::CBuildingLoaded>())
eb.add<BuildingsData::CBuildingLoad>();
}
} }
} }
@@ -163,52 +180,39 @@ void StreamWorld::erase_tile(int tx, int ty)
print_verbose("unload item: " + itos(i) + ": key: " + items[i] + print_verbose("unload item: " + itos(i) + ": key: " + items[i] +
": " /* + data()->get_building(items[i]).id */); ": " /* + data()->get_building(items[i]).id */);
const String &bkey = items[i]; const String &bkey = items[i];
unload_building(bkey); flecs::entity eb = data()->get_building_entity(bkey);
if (eb.is_valid()) {
if (eb.has<BuildingsData::CBuildingLoaded>())
eb.add<BuildingsData::CBuildingUnload>();
print_verbose("Removing key:" + bkey);
}
} }
} }
#endif
void StreamWorld::load_building(const String &key) void StreamWorld::load_building(const String &key)
{ {
request_item(0, key); flecs::entity eb = data()->get_building_entity(key);
// print_line("key: " + bkey);
if (!eb.is_valid()) {
print_error("ERROR: Entity does not exist: " + key);
return;
}
if (!eb.has<BuildingsData::CBuildingLoaded>())
eb.add<BuildingsData::CBuildingLoad>();
} }
void StreamWorld::unload_building(const String &key) void StreamWorld::unload_building(const String &key)
{ {
request_item(1, key); flecs::entity eb = data()->get_building_entity(key);
} // print_line("key: " + bkey);
if (!eb.is_valid()) {
void StreamWorld::request_item(int type, const String &bkey) print_error("ERROR: Entity does not exist: " + key);
{
bool debug = false;
/* bkey can contain "::"'s so need to replae them with underscores */
String ekey = bkey;
if (bkey.begins_with("road__")) {
print_verbose("loading building: " + ekey);
debug = true;
}
String id = data()->get_building(ekey).id;
if (debug)
print_verbose("building id: " + id);
if (id == "empty")
return; return;
switch (type) {
case 0:
if (debug)
print_verbose("add to scene id: " + id);
if (!data()->has_scene(id))
data()->create_scene_data(id, ekey);
else
data()->add_scene_item(id, ekey);
if (debug)
print_verbose("added to scene id: " + id);
break;
case 1: {
print_verbose("Removing key:" + ekey);
if (data()->has_scene(id)) {
data()->remove_scene_item(id, ekey);
}
} break;
} }
if (eb.has<BuildingsData::CBuildingLoaded>())
eb.add<BuildingsData::CBuildingUnload>();
print_verbose("Removing key:" + key);
} }
void StreamWorld::update_items() void StreamWorld::update_items()
@@ -395,7 +399,9 @@ void StreamWorld::run_command(const String &command,
RoadProcessing::road_setup(this, args[0]); RoadProcessing::road_setup(this, args[0]);
else else
RoadProcessing::road_setup(this, 0); RoadProcessing::road_setup(this, 0);
#if 0
create_tilemap(); create_tilemap();
#endif
update_view(); update_view();
data()->scene_update(); data()->scene_update();
update_items(); update_items();
@@ -419,7 +425,9 @@ void StreamWorld::run_command(const String &command,
terrain->set_generator(gen); terrain->set_generator(gen);
update_items(); update_items();
RoadProcessing::road_setup(this, 0); RoadProcessing::road_setup(this, 0);
#if 0
create_tilemap(); create_tilemap();
#endif
update_view(); update_view();
update_items(); update_items();
assert(false); assert(false);
@@ -460,7 +468,9 @@ void StreamWorld::_notification(int which)
nullptr); nullptr);
assert(false); assert(false);
#endif #endif
#if 0
create_tilemap(); create_tilemap();
#endif
set_process(true); set_process(true);
if (Engine::get_singleton()->is_editor_hint()) if (Engine::get_singleton()->is_editor_hint())
break; break;
@@ -516,14 +526,17 @@ StreamWorld::StreamWorld()
, initialized(false) , initialized(false)
, frame_count(0) , frame_count(0)
{ {
BaseData::get_singleton()->get().component<BuildingsData>();
Error result = config.load("res://config/stream.conf"); Error result = config.load("res://config/stream.conf");
ERR_FAIL_COND_MSG(result != OK, "Failed to load config"); ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
BaseData::get_singleton()->get().ensure<BuildingsData>();
RoadProcessing::load_data(); RoadProcessing::load_data();
world_extent = config.get_value("world", "world_extent"); world_extent = config.get_value("world", "world_extent");
tile_size = config.get_value("world", "tile_size"); tile_size = config.get_value("world", "tile_size");
ERR_FAIL_COND_MSG(tile_size <= 0 || world_extent <= 0 || ERR_FAIL_COND_MSG(tile_size <= 0 || world_extent <= 0 ||
world_extent <= tile_size, world_extent <= tile_size,
"Failed to configure world"); "Failed to configure world");
#if 0
create_tilemap(); create_tilemap();
tile_map_t::iterator map_it = tiles.begin(); tile_map_t::iterator map_it = tiles.begin();
while (map_it != tiles.end()) { while (map_it != tiles.end()) {
@@ -534,11 +547,11 @@ StreamWorld::StreamWorld()
itos(tile_buildings.size())); itos(tile_buildings.size()));
map_it++; map_it++;
} }
#endif
view_distance = config.get_value("world", "view_distance"); view_distance = config.get_value("world", "view_distance");
NPC *npc = NPC::get_singleton(); BaseData::get_singleton()->get().import <NPC>();
if (!npc) { flecs::entity npcctrl = BaseData::get_singleton()->get().entity();
assert(false); npcctrl.set<NPC::NPCControl>({ NPC::NPCControl::CMD_PRESIM });
}
initialized = true; initialized = true;
} }
void StreamWorld::cleanup() void StreamWorld::cleanup()

View File

@@ -16,6 +16,7 @@ private:
VoxelLodTerrain *terrain; VoxelLodTerrain *terrain;
Node *current_scene; Node *current_scene;
ConfigFile config; ConfigFile config;
#if 0
using tile_key_t = std::tuple<int, int>; using tile_key_t = std::tuple<int, int>;
struct tile_hash : public std::unary_function<key_t, std::size_t> { struct tile_hash : public std::unary_function<key_t, std::size_t> {
std::size_t operator()(const tile_key_t &k) const std::size_t operator()(const tile_key_t &k) const
@@ -28,6 +29,7 @@ private:
Vector3 eye; Vector3 eye;
tile_map_t tiles; tile_map_t tiles;
tile_map_t loaded_tiles; tile_map_t loaded_tiles;
#endif
int world_extent; int world_extent;
int tile_size; int tile_size;
@@ -36,15 +38,14 @@ private:
int current_x, current_z; int current_x, current_z;
int frame_count; int frame_count;
void _notification(int which); void _notification(int which);
void create_tilemap(); // void create_tilemap();
void update_view(); void update_view();
void viewer_dead(); void viewer_dead();
void terrain_dead(); void terrain_dead();
void load_tile(int tx, int ty); // void load_tile(int tx, int ty);
void erase_tile(int tx, int ty); // void erase_tile(int tx, int ty);
void load_building(const String &key); void load_building(const String &key);
void unload_building(const String &key); void unload_building(const String &key);
void request_item(int type, const String &key);
void update_items(); void update_items();
void remove_building(const String &key); void remove_building(const String &key);
void remove_generated_stuff(); void remove_generated_stuff();

View File

@@ -18,6 +18,14 @@
#include "signal_handler.h" #include "signal_handler.h"
#include "terrain_editor.h" #include "terrain_editor.h"
static inline BuildingsData *bd()
{
BuildingsData *ret =
BaseData::get_singleton()->get().get_mut<BuildingsData>();
assert(ret);
return ret;
}
void TerrainEditor::exit() void TerrainEditor::exit()
{ {
if (active) if (active)
@@ -358,15 +366,13 @@ end:;
case 2001: { case 2001: {
List<String> building_keys; List<String> building_keys;
List<String>::Element *e; List<String>::Element *e;
BuildingsData::get_singleton()->get_building_keys_list( bd()->get_building_keys_list(&building_keys);
&building_keys); bd()->build_building_aabbs();
BuildingsData::get_singleton()->build_building_aabbs();
e = building_keys.front(); e = building_keys.front();
while (e) { while (e) {
const String &key = e->get(); const String &key = e->get();
const BuildingsData::building &b = const BuildingsData::building &b =
BuildingsData::get_singleton() bd()->get_building(key);
->get_building(key);
float i, j; float i, j;
print_line("building type: " + b.id); print_line("building type: " + b.id);
print_line("building key: " + b.key); print_line("building key: " + b.key);
@@ -376,8 +382,7 @@ end:;
"building elevation: " + "building elevation: " +
String::num(imgmapper->get_height_full( String::num(imgmapper->get_height_full(
b.xform.origin))); b.xform.origin)));
AABB aabb = BuildingsData::get_singleton() AABB aabb = bd()->building_aabbs[b.id];
->building_aabbs[b.id];
print_line("building AABB: " + print_line("building AABB: " +
(aabb.operator String())); (aabb.operator String()));
float max_elevation_c = -Math_INF, float max_elevation_c = -Math_INF,
@@ -458,9 +463,7 @@ end:;
// assert(Math::abs(max_elevation2 - // assert(Math::abs(max_elevation2 -
// max_elevation) < 1.0f); // max_elevation) < 1.0f);
#endif #endif
Transform xform = BuildingsData::get_singleton() Transform xform = bd()->get_building(key).xform;
->get_building(key)
.xform;
xform.origin.y = max_elevation * 1.4998f - 0.5f; xform.origin.y = max_elevation * 1.4998f - 0.5f;
editor->editor_command( editor->editor_command(
"update_building_transform", "update_building_transform",
@@ -474,7 +477,7 @@ end:;
e = e->next(); e = e->next();
} }
imgmapper->save_dirty_tiles(); imgmapper->save_dirty_tiles();
BuildingsData::get_singleton()->save_buildings(); bd()->save_buildings();
editor->editor_command("nudge_generator", varray()); editor->editor_command("nudge_generator", varray());
} break; } break;
default: default:

View File

@@ -426,19 +426,21 @@ void MainTabs::_notification(int which)
/* 43 */ /* 43 */
"Delete Building", "buildings_delete_building", "delete_building", varray(), "Delete Building", "buildings_delete_building", "delete_building", varray(),
/* 47 */ /* 47 */
"Create Building", "buildings_create_building", "create_building", varray(), "Layout", "buildings_edit_layout", "edit_layout", varray(),
/* 51 */ /* 51 */
"Save Buildings", "buildings_save", "buildings_save", varray(), "Create Building", "buildings_create_building", "create_building", varray(),
/* 55 */ /* 55 */
"Save Buildings", "buildings_save", "buildings_save", varray(),
/* 59 */
0, Vector2(0, 80), "lines_list_building", 0, Vector2(0, 80), "lines_list_building",
/* 58 */ /* 62 */
"Assign To Line", "buildings_assign_to_line" "Assign To Line", "buildings_assign_to_line"
/* 60 */ /* 64 */
}; };
/* clang-format on */ /* clang-format on */
ui_field::ui_field_builder( ui_field::ui_field_builder(
this, tab, this, tab,
"l_p{v{lh{e#!+e#!+e#!+b#!}lh{e#!+e#!+e#!+}h{le#!b#!}_lo#!Mlo#!T_b#!Qb#!QB#!qi.#!b#!}}", "l_p{v{lh{e#!+e#!+e#!+b#!}lh{e#!+e#!+e#!+}h{le#!b#!}_lo#!Mlo#!T_b#!Qb#!Qb#!QB#!qi.#!b#!}}",
args_data.data(), args_data.data(),
args_data.size()); args_data.size());
} }