Worked on buildings in lines

This commit is contained in:
2024-09-22 02:19:40 +03:00
parent 6fa644c57d
commit 2f3187257d
13 changed files with 5452 additions and 3527 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -233,7 +233,7 @@ text = "POI mode"
unique_name_in_owner = true unique_name_in_owner = true
margin_top = 538.0 margin_top = 538.0
margin_right = 248.0 margin_right = 248.0
margin_bottom = 1188.0 margin_bottom = 1497.0
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_road_lines"] [node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_road_lines"]
margin_right = 248.0 margin_right = 248.0
@@ -283,7 +283,7 @@ margin_left = 79.0
margin_right = 124.0 margin_right = 124.0
margin_bottom = 20.0 margin_bottom = 20.0
text = "Point" text = "Point"
items = [ "", null, 0, false, false, 0, 0, null, "", true, "Create", null, 0, false, false, 11, 0, null, "", false, "Remove", null, 0, false, false, 12, 0, null, "", false, "", null, 0, false, false, 3, 0, null, "", true, "Point To Cursor", null, 0, false, false, 51, 0, null, "", false, "Cursor To Point", null, 0, false, false, 52, 0, null, "", false, "Item 6", null, 0, false, true, 6, 0, null, "", false, "Item 7", null, 0, false, true, 7, 0, null, "", false ] items = [ "", null, 0, false, false, 0, 0, null, "", true, "Create", null, 0, false, false, 11, 0, null, "", false, "Remove", null, 0, false, false, 12, 0, null, "", false, "", null, 0, false, false, 3, 0, null, "", true, "Point To Cursor", null, 0, false, false, 51, 0, null, "", false, "Cursor To Point", null, 0, false, false, 52, 0, null, "", false, "Cursor to closest building", null, 0, false, false, 53, 0, null, "", false, "Item 7", null, 0, false, true, 7, 0, null, "", false ]
switch_on_hover = true switch_on_hover = true
[node name="road_lines_line_menu" type="MenuButton" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_menu_block"] [node name="road_lines_line_menu" type="MenuButton" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_menu_block"]
@@ -293,7 +293,7 @@ margin_right = 167.0
margin_bottom = 20.0 margin_bottom = 20.0
focus_mode = 2 focus_mode = 2
text = "Line" text = "Line"
items = [ "Create", null, 0, false, false, 21, 0, null, "", false, "Delete", null, 0, false, false, 22, 0, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Remove Generated", null, 0, false, false, 30, 0, null, "", false, "Place Generated Objects", null, 0, false, false, 31, 0, null, "", false, "Edit Line Metadata", null, 0, false, false, 23, 0, null, "", false, "Rebuild roads", null, 0, false, false, 32, 0, null, "", false, "Remove road meshes", null, 0, false, false, 33, 0, null, "", false ] items = [ "Create", null, 0, false, false, 21, 0, null, "", false, "Delete", null, 0, false, false, 22, 0, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Remove Generated", null, 0, false, false, 30, 0, null, "", false, "Place Generated Objects", null, 0, false, false, 31, 0, null, "", false, "Edit Line Metadata", null, 0, false, false, 23, 0, null, "", false, "Rebuild roads", null, 0, false, false, 32, 0, null, "", false, "Remove road meshes", null, 0, false, false, 33, 0, null, "", false, "Assign close (generated) buildings", null, 0, false, false, 34, 0, null, "", false, "Create new building at cursor", null, 0, false, false, 35, 0, null, "", false, "View Buildings", null, 0, false, false, 36, 0, null, "", false ]
switch_on_hover = true switch_on_hover = true
[node name="road_lines_options_menu" type="MenuButton" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_menu_block"] [node name="road_lines_options_menu" type="MenuButton" parent="VBoxContainer/v_road_lines/road_lines_base/VBoxContainer/road_lines_menu_block"]
@@ -517,11 +517,103 @@ margin_top = 212.0
margin_right = 222.0 margin_right = 222.0
margin_bottom = 418.0 margin_bottom = 418.0
[node name="road_lines_buildings" type="PanelContainer" parent="VBoxContainer/v_road_lines"]
unique_name_in_owner = true
margin_top = 654.0
margin_right = 248.0
margin_bottom = 959.0
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/v_road_lines/road_lines_buildings"]
margin_left = 7.0
margin_top = 7.0
margin_right = 241.0
margin_bottom = 298.0
[node name="Label" type="Label" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer"]
margin_right = 234.0
margin_bottom = 31.0
text = "Line buildings
"
[node name="line_buildings_list" type="ItemList" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer"]
unique_name_in_owner = true
margin_top = 35.0
margin_right = 234.0
margin_bottom = 135.0
rect_min_size = Vector2( 0, 100 )
size_flags_horizontal = 3
[node name="GridContainer" type="GridContainer" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer"]
margin_top = 139.0
margin_right = 234.0
margin_bottom = 219.0
columns = 2
[node name="Label" type="Label" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer/GridContainer"]
margin_top = 5.0
margin_right = 85.0
margin_bottom = 19.0
text = "line offset"
[node name="line_buildings_line_offset" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer/GridContainer"]
unique_name_in_owner = true
margin_left = 89.0
margin_right = 234.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="Label2" type="Label" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer/GridContainer"]
margin_top = 33.0
margin_right = 85.0
margin_bottom = 47.0
text = "normal offset"
[node name="line_buildings_normal_offset" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer/GridContainer"]
unique_name_in_owner = true
margin_left = 89.0
margin_top = 28.0
margin_right = 234.0
margin_bottom = 52.0
size_flags_horizontal = 3
[node name="Label3" type="Label" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer/GridContainer"]
margin_top = 61.0
margin_right = 85.0
margin_bottom = 75.0
text = "Y-rotation"
[node name="LineEdit" type="LineEdit" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer/GridContainer"]
margin_left = 89.0
margin_top = 56.0
margin_right = 234.0
margin_bottom = 80.0
[node name="line_buildings_remove_from_line" type="Button" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer"]
unique_name_in_owner = true
margin_top = 223.0
margin_right = 234.0
margin_bottom = 243.0
text = "Remove"
[node name="line_buildings_assign" type="Button" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer"]
unique_name_in_owner = true
margin_top = 247.0
margin_right = 234.0
margin_bottom = 267.0
text = "Assign"
[node name="line_buildings_close" type="Button" parent="VBoxContainer/v_road_lines/road_lines_buildings/VBoxContainer"]
unique_name_in_owner = true
margin_top = 271.0
margin_right = 234.0
margin_bottom = 291.0
text = "Close"
[node name="v_npc" type="VBoxContainer" parent="VBoxContainer"] [node name="v_npc" type="VBoxContainer" parent="VBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
margin_top = 1192.0 margin_top = 1501.0
margin_right = 248.0 margin_right = 248.0
margin_bottom = 1214.0 margin_bottom = 1523.0
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_npc"] [node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_npc"]
margin_right = 248.0 margin_right = 248.0

View File

@@ -1,5 +1,6 @@
#include <core/os/memory.h> #include <core/os/memory.h>
#include <core/io/json.h> #include <core/io/json.h>
#include <core/os/time.h>
#include <core/os/file_access.h> #include <core/os/file_access.h>
#include <core/io/config_file.h> #include <core/io/config_file.h>
#include <scene/resources/packed_scene.h> #include <scene/resources/packed_scene.h>
@@ -71,6 +72,29 @@ void BuildingsData::build_building_aabbs()
} }
} }
void BuildingsData::update_building_transform(int index, const Transform &xform)
{
buildings[index].xform = xform;
}
int BuildingsData::get_closest_building(const Transform &xform)
{
int i;
float dst = Math_INF;
String rkey;
int id = -1;
for (i = 0; i < (int)buildings.size(); i++) {
Vector3 o = xform.origin;
Vector3 m = buildings[i].xform.origin;
float mdst = o.distance_squared_to(m);
if (dst > mdst) {
dst = mdst;
id = i;
}
}
return id;
}
void BuildingsData::cleanup() void BuildingsData::cleanup()
{ {
if (singleton) { if (singleton) {
@@ -80,6 +104,19 @@ void BuildingsData::cleanup()
} }
} }
int BuildingsData::get_building_by_key(const String &key)
{
int i, index = -1;
uint64_t key_hash = key.hash64();
for (i = 0; i < (int)buildings.size(); i++) {
if (key_hash == buildings[i].key_hash) {
index = i;
break;
}
}
return index;
}
void BuildingsData::read_buildings_json(const String &buildings_path) void BuildingsData::read_buildings_json(const String &buildings_path)
{ {
String buildings_json = FileAccess::get_file_as_string(buildings_path); String buildings_json = FileAccess::get_file_as_string(buildings_path);
@@ -103,7 +140,11 @@ void BuildingsData::read_buildings_json(const String &buildings_path)
e = e->next(); e = e->next();
continue; continue;
} }
building::from_dict(&b, json[key], key); if (!entry.has("xform")) // legacy
entry["xform"] = key;
if (!entry.has("key")) // legacy
entry["key"] = key;
building::from_dict(&b, json[key]);
buildings.push_back(b); buildings.push_back(b);
e = e->next(); e = e->next();
} }
@@ -136,8 +177,7 @@ void BuildingsData::save_buildings_json(const String &buildings_path)
fa->close(); fa->close();
Dictionary json; Dictionary json;
for (i = 0; i < (int)buildings.size(); i++) { for (i = 0; i < (int)buildings.size(); i++) {
String key; String key = buildings[i].key;
VariantWriter::write_to_string(buildings[i].xform, key);
Dictionary dict = buildings[i].to_dict(); Dictionary dict = buildings[i].to_dict();
dict["index"] = i; dict["index"] = i;
json[key] = dict; json[key] = dict;
@@ -149,12 +189,13 @@ void BuildingsData::save_buildings_json(const String &buildings_path)
print_line("entries count: " + itos(buildings.size())); print_line("entries count: " + itos(buildings.size()));
} }
void BuildingsData::building::from_dict(building *b, const Dictionary &dict, void BuildingsData::building::from_dict(building *b, const Dictionary &dict)
const String &key)
{ {
int i; int i;
b->key = key; assert(dict.has("key"));
b->xform = from_string<Transform>(key); assert(dict.has("xform"));
b->xform = from_string<Transform>(
dict.get("xform", to_string<Transform>(Transform())));
b->id = dict.get("id", "empty"); b->id = dict.get("id", "empty");
b->pattern_id = dict.get("pattern_id", 0); b->pattern_id = dict.get("pattern_id", 0);
b->generated = dict.get("generated", false); b->generated = dict.get("generated", false);
@@ -178,6 +219,14 @@ void BuildingsData::building::from_dict(building *b, const Dictionary &dict,
} }
b->worktime[0] = worktime[0]; b->worktime[0] = worktime[0];
b->worktime[1] = worktime[1]; b->worktime[1] = worktime[1];
String new_key = String::num_uint64(
String(b->id +
dict.get("xform", to_string<Transform>(Transform())) +
itos(Time::get_singleton()->get_ticks_usec()))
.hash64(),
16);
b->key = dict.get("key", new_key);
b->key_hash = b->key.hash64();
} }
template <class T> static inline void v2a(Array &ret, const Vector<T> &data) template <class T> static inline void v2a(Array &ret, const Vector<T> &data)
@@ -206,6 +255,8 @@ Dictionary BuildingsData::building::to_dict() const
wt[0] = worktime[0]; wt[0] = worktime[0];
wt[1] = worktime[1]; wt[1] = worktime[1];
ret["worktime"] = wt; ret["worktime"] = wt;
ret["key"] = key;
ret["xform"] = to_string<Transform>(xform);
return ret; return ret;
} }

View File

@@ -12,13 +12,14 @@ public:
int pattern_id; int pattern_id;
Vector<int> residents, workers, guests; Vector<int> residents, workers, guests;
String key; String key;
uint64_t key_hash;
Transform xform; Transform xform;
int worktime[2]; int worktime[2];
bool generated; bool generated;
static void from_dict(struct building *b, static void from_dict(struct building *b,
const Dictionary &dict, const Dictionary &dict);
const String &key);
Dictionary to_dict() const; Dictionary to_dict() const;
String line_name;
}; };
/* Scene objects data */ /* Scene objects data */
struct scene_data { struct scene_data {
@@ -54,7 +55,10 @@ public:
void undo(); void undo();
void fill_door_locations(); void fill_door_locations();
void build_building_aabbs(); void build_building_aabbs();
void update_building_transform(int index, const Transform &xform);
int get_closest_building(const Transform &xform);
static BuildingsData *get_singleton(); static BuildingsData *get_singleton();
static void cleanup(); static void cleanup();
int get_building_by_key(const String &key);
}; };
#endif #endif

View File

@@ -1,6 +1,7 @@
#undef NDEBUG #undef NDEBUG
#include <cassert> #include <cassert>
#include <core/variant.h> #include <core/variant.h>
#include <core/os/time.h>
#include <scene/gui/option_button.h> #include <scene/gui/option_button.h>
#include <scene/main/viewport.h> #include <scene/main/viewport.h>
#include <scene/3d/camera.h> #include <scene/3d/camera.h>
@@ -9,6 +10,7 @@
#include "from_string.h" #include "from_string.h"
#include "editor_event.h" #include "editor_event.h"
#include "world_editor.h" #include "world_editor.h"
#include "buildings_data.h"
#include "buildings_editor.h" #include "buildings_editor.h"
class HandleChangeBuildingType : public Object { class HandleChangeBuildingType : public Object {
@@ -240,10 +242,15 @@ void BuildingsEditor::handle_create_building()
->get_global_transform(); ->get_global_transform();
Dictionary building_data; Dictionary building_data;
/* FIXME: calculate AABBs as in previous editor */ /* FIXME: calculate AABBs as in previous editor */
String building_xform = to_string<Transform>(xform);
building_data["id"] = item; building_data["id"] = item;
String building_key = to_string<Transform>(xform); building_data["key"] = String::num_uint64(
String(item + building_xform +
itos(Time::get_singleton()->get_ticks_usec()))
.hash64(),
16);
building_data["xform"] = building_xform;
args.push_back(building_data); args.push_back(building_data);
args.push_back(building_key);
editor->editor_command("create_building", args); editor->editor_command("create_building", args);
} }
} }
@@ -425,6 +432,7 @@ void BuildingsEditor::mouse_press(const Vector2 &position)
float h = gen->get_height_full(newpos); float h = gen->get_height_full(newpos);
newpos.y = h; newpos.y = h;
Transform xform(Basis(), newpos); Transform xform(Basis(), newpos);
get_as_node<Spatial>("%building_cursor")->show();
get_as_node<Spatial>("%building_cursor") get_as_node<Spatial>("%building_cursor")
->set_global_transform(xform); ->set_global_transform(xform);
} break; } break;

View File

@@ -11,6 +11,7 @@
#include <scene/3d/immediate_geometry.h> #include <scene/3d/immediate_geometry.h>
#include <scene/main/viewport.h> #include <scene/main/viewport.h>
#include "from_string.h" #include "from_string.h"
#include "buildings_data.h"
#include "road_lines_data.h" #include "road_lines_data.h"
ImmediateGeometry *RoadLinesData::debug_im = nullptr; ImmediateGeometry *RoadLinesData::debug_im = nullptr;
@@ -62,7 +63,6 @@ RoadLinesData::RoadLinesData()
e = e->next(); e = e->next();
} }
} }
RoadLinesData *RoadLinesData::singleton = nullptr; RoadLinesData *RoadLinesData::singleton = nullptr;
RoadLinesData *RoadLinesData::get_singleton() RoadLinesData *RoadLinesData::get_singleton()
{ {
@@ -70,7 +70,6 @@ RoadLinesData *RoadLinesData::get_singleton()
singleton = memnew(RoadLinesData); singleton = memnew(RoadLinesData);
return singleton; return singleton;
} }
RoadLinesData::~RoadLinesData() RoadLinesData::~RoadLinesData()
{ {
#if 0 #if 0
@@ -80,18 +79,15 @@ RoadLinesData::~RoadLinesData()
} }
#endif #endif
} }
void RoadLinesData::cleanup() void RoadLinesData::cleanup()
{ {
memdelete(singleton); memdelete(singleton);
singleton = nullptr; singleton = nullptr;
} }
String RoadLinesData::get_road_lines_path() String RoadLinesData::get_road_lines_path()
{ {
return road_lines_path; return road_lines_path;
} }
void RoadLinesData::get_road_lines_key_list(List<String> *keys) void RoadLinesData::get_road_lines_key_list(List<String> *keys)
{ {
List<String> line_keys; List<String> line_keys;
@@ -234,8 +230,7 @@ void RoadLinesData::create_segments(const String &road,
std::vector<int> &segments) std::vector<int> &segments)
{ {
int i; int i;
RoadLinesData *rld = RoadLinesData::get_singleton(); for (i = 0; i < (int)lines[road].indices.size() - 1; i++) {
for (i = 0; i < (int)rld->lines[road].indices.size() - 1; i++) {
segments.push_back(i); segments.push_back(i);
segments.push_back(i + 1); segments.push_back(i + 1);
} }
@@ -296,14 +291,12 @@ void RoadLinesData::insert_close_points(std::vector<Vector3> &road_lines_nodes,
} }
} }
} }
void RoadLinesData::update_road_lines_nodes( void RoadLinesData::update_road_lines_nodes(
std::vector<Vector3> &road_lines_nodes) std::vector<Vector3> &road_lines_nodes)
{ {
List<String> keys; List<String> keys;
RoadLinesData *rld = RoadLinesData::get_singleton();
rld->get_road_lines_key_list(&keys); get_road_lines_key_list(&keys);
std::unordered_map<uint32_t, std::tuple<String, String> > kcmp; std::unordered_map<uint32_t, std::tuple<String, String> > kcmp;
{ {
List<String>::Element *k = keys.front(); List<String>::Element *k = keys.front();
@@ -335,25 +328,22 @@ void RoadLinesData::update_road_lines_nodes(
std::tuple<String, String> data = kcmp[it->first]; std::tuple<String, String> data = kcmp[it->first];
const String &k = std::get<0>(data); const String &k = std::get<0>(data);
const String &r = std::get<1>(data); const String &r = std::get<1>(data);
if (rld->lines[k].indices.size() < 2) if (lines[k].indices.size() < 2)
continue; continue;
if (rld->lines[r].indices.size() < 2) if (lines[r].indices.size() < 2)
continue; continue;
for (i = 0; i < (int)rld->lines[k].indices.size() - 1; i++) { for (i = 0; i < (int)lines[k].indices.size() - 1; i++) {
for (j = 0; j < (int)rld->lines[k].indices.size() - 1; for (j = 0; j < (int)lines[k].indices.size() - 1; j++) {
j++) {
uint32_t key = k.hash() ^ i ^ r.hash() ^ j ^ uint32_t key = k.hash() ^ i ^ r.hash() ^ j ^
2147483137; 2147483137;
uint32_t key2 = r.hash() ^ j ^ k.hash() ^ i ^ uint32_t key2 = r.hash() ^ j ^ k.hash() ^ i ^
2147463167; 2147463167;
if (checks.find(key) == checks.end() && if (checks.find(key) == checks.end() &&
checks.find(key2) == checks.end()) { checks.find(key2) == checks.end()) {
int idx_a1 = rld->lines[k].indices[i]; int idx_a1 = lines[k].indices[i];
int idx_a2 = int idx_a2 = lines[k].indices[i + 1];
rld->lines[k].indices[i + 1]; int idx_b1 = lines[k].indices[j];
int idx_b1 = rld->lines[k].indices[j]; int idx_b2 = lines[k].indices[j + 1];
int idx_b2 =
rld->lines[k].indices[j + 1];
std::vector<int> cmp1 = { idx_a1, std::vector<int> cmp1 = { idx_a1,
idx_a2 }; idx_a2 };
if (std::find(cmp1.begin(), cmp1.end(), if (std::find(cmp1.begin(), cmp1.end(),
@@ -419,16 +409,16 @@ void RoadLinesData::update_road_lines_nodes(
int nidx = road_lines_nodes.size(); int nidx = road_lines_nodes.size();
road_lines_nodes.push_back(pxt); road_lines_nodes.push_back(pxt);
// int il = (int)road_lines[k].indices.size(); // int il = (int)road_lines[k].indices.size();
assert(std::find(rld->lines[k].indices.begin(), assert(std::find(lines[k].indices.begin(),
rld->lines[k].indices.end(), lines[k].indices.end(),
nidx) == rld->lines[k].indices.end()); nidx) == lines[k].indices.end());
assert(std::find(rld->lines[r].indices.begin(), assert(std::find(lines[r].indices.begin(),
rld->lines[r].indices.end(), lines[r].indices.end(),
nidx) == rld->lines[r].indices.end()); nidx) == lines[r].indices.end());
rld->lines[k].indices.insert( lines[k].indices.insert(
rld->lines[k].indices.begin() + i + 1, nidx); lines[k].indices.begin() + i + 1, nidx);
rld->lines[r].indices.insert( lines[r].indices.insert(
rld->lines[k].indices.begin() + j + 1, nidx); lines[k].indices.begin() + j + 1, nidx);
} }
} }
} }
@@ -436,12 +426,11 @@ void RoadLinesData::dump_road_lines(const std::vector<Vector3> &road_lines_nodes
{ {
int i; int i;
List<String> keys; List<String> keys;
RoadLinesData *rld = RoadLinesData::get_singleton(); get_road_lines_key_list(&keys);
rld->get_road_lines_key_list(&keys);
List<String>::Element *e = keys.front(); List<String>::Element *e = keys.front();
while (e) { while (e) {
String rkey = e->get(); String rkey = e->get();
struct RoadLinesData::road_line &pt = rld->lines[rkey]; struct RoadLinesData::road_line &pt = lines[rkey];
String outline = rkey + ": "; String outline = rkey + ": ";
for (i = 0; i < (int)pt.indices.size(); i++) { for (i = 0; i < (int)pt.indices.size(); i++) {
outline += " " + itos(pt.indices[i]); outline += " " + itos(pt.indices[i]);
@@ -453,7 +442,6 @@ void RoadLinesData::dump_road_lines(const std::vector<Vector3> &road_lines_nodes
e = e->next(); e = e->next();
} }
} }
ImmediateGeometry *RoadLinesData::get_debug_node() ImmediateGeometry *RoadLinesData::get_debug_node()
{ {
if (!debug_im) { if (!debug_im) {
@@ -474,7 +462,6 @@ ImmediateGeometry *RoadLinesData::get_debug_node()
} }
return debug_im; return debug_im;
} }
void RoadLinesData::process_lines( void RoadLinesData::process_lines(
std::unordered_map<uint32_t, std::vector<Vector3> > std::unordered_map<uint32_t, std::vector<Vector3> >
&road_lines_nodes_hash, &road_lines_nodes_hash,
@@ -485,13 +472,181 @@ void RoadLinesData::process_lines(
update_road_lines_nodes(road_lines_nodes); update_road_lines_nodes(road_lines_nodes);
dump_road_lines(road_lines_nodes); dump_road_lines(road_lines_nodes);
} }
void RoadLinesData::set_debug_flags(int debug_flags) void RoadLinesData::set_debug_flags(int debug_flags)
{ {
this->debug_flags = debug_flags; this->debug_flags = debug_flags;
} }
int RoadLinesData::get_debug_flags() const int RoadLinesData::get_debug_flags() const
{ {
return debug_flags; return debug_flags;
} }
void RoadLinesData::update_line_segments(const String &line)
{
int i;
lines[line].segments.clear();
lines[line].segments.resize(lines[line].points.size() - 1);
float offset = 0.0f;
for (i = 0; i < (int)lines[line].points.size() - 1; i++) {
struct line_segment segment;
segment.p1 = lines[line].points[i].origin;
segment.p2 = lines[line].points[i + 1].origin;
segment.length = segment.p1.distance_to(segment.p2);
segment.dir = (segment.p2 - segment.p1).normalized();
Vector3 side = segment.dir.cross(Vector3(0, 1, 0));
side.y = 0;
segment.tangent = side.normalized();
segment.offset = offset;
lines[line].segments[i] = segment;
offset += segment.length;
}
}
void RoadLinesData::line_add_building(const String &line, const String &key,
float curve_offset, float normal_offset)
{
int index = BuildingsData::get_singleton()->get_building_by_key(key);
if (index < 0)
return;
struct line_building_data lb;
lb.building_key = key;
lb.building_key_hash = key.hash64();
lb.line_offset = curve_offset;
lb.normal_offset = normal_offset;
lines[line].buildings.push_back(lb);
// TODO: save/load
BuildingsData::get_singleton()->buildings[index].line_name = line;
}
void RoadLinesData::assign_close_buildings(const String &line)
{
int i, j;
print_line("assign_close_buildings: " + line);
if (!lines.has(line))
return;
if (!line.ends_with("_buildings"))
return;
if (lines[line].points.size() < 2)
return;
update_line_segments(line);
if (lines[line].segments.size() == 0)
return;
print_line("assign_close_buildings: processing: " +
itos(BuildingsData::get_singleton()->buildings.size()) +
" buildings");
for (i = 0; i < (int)BuildingsData::get_singleton()->buildings.size();
i++) {
float dst = Math_INF;
float result_offset = 0.0f;
float side = 0.0f;
String building_key;
struct BuildingsData::building &data =
BuildingsData::get_singleton()->buildings[i];
// manually placed
if (!data.generated)
continue;
// already assigned to another line
const String &building_line =
BuildingsData::get_singleton()->buildings[i].line_name;
if (building_line != line && building_line != "")
continue;
if (line_has_building(line, data.key))
continue;
Vector3 p = data.xform.origin;
Vector3 segment_point;
int segment_index = -1;
for (j = 0; j < (int)lines[line].segments.size(); j++) {
Vector3 seg[] = { lines[line].segments[j].p1,
lines[line].segments[j].p2 };
Vector3 closest =
Geometry::get_closest_point_to_segment(p, seg);
Vector3 xp = p;
xp.y = p.y;
float tmpdst = xp.distance_squared_to(closest);
if (closest.is_equal_approx(
lines[line].segments[j].p1) ||
closest.is_equal_approx(
lines[line].segments[j].p2)) {
float w = closest.dot(
lines[line].segments[j].dir);
float wt = xp.dot(lines[line].segments[j].dir);
if (wt - w > 0.1f || wt - w < -0.1f)
continue;
}
if (dst > tmpdst) {
dst = tmpdst;
building_key = data.key;
segment_index = j;
segment_point = closest;
}
}
if (segment_index < 0)
continue;
const Vector3 &p1 = lines[line].segments[segment_index].p1;
const Vector3 &p2 = lines[line].segments[segment_index].p2;
const Vector3 &dir = lines[line].segments[segment_index].dir;
assert(segment_index >= 0);
// assert(!segment_point.is_equal_approx(p1));
// assert(!segment_point.is_equal_approx(p2));
assert((segment_point - p1).dot(dir) >= 0);
float wdst = (p - p1).dot(dir);
print_line("wdst=" + String::num(wdst));
assert(wdst >= 0);
result_offset =
lines[line].segments[segment_index].offset + wdst;
side = (p - p1).dot(lines[line].segments[j].tangent);
assert(result_offset >= 0);
print_line("key: " + building_key +
" dst: " + String::num(dst));
if (dst < 16 * 16) {
print_line("adding: key: " + building_key +
" dst: " + String::num(dst));
assert(result_offset >= 0);
line_add_building(line, building_key, result_offset,
side);
}
}
}
bool RoadLinesData::line_has_building(const String &line,
const String &building_key)
{
uint64_t key_hash = building_key.hash64();
bool ret = false;
int i;
for (i = 0; i < (int)lines[line].buildings.size(); i++)
if (lines[line].buildings[i].building_key_hash == key_hash) {
ret = true;
break;
}
return ret;
}
Vector3 RoadLinesData::get_point_by_offsets(const String &line,
float dir_offset,
float normal_offset)
{
Vector3 ret;
int i;
print_verbose("line: " + line +
" line_offset: " + String::num(dir_offset) +
" normal_offset: " + String::num(normal_offset));
float n_offset = dir_offset;
int selected_segment = 0;
for (i = 0; i < (int)lines[line].segments.size(); i++) {
struct line_segment *segment = &lines[line].segments[i];
if (n_offset < segment->length) {
selected_segment = i;
break;
}
n_offset -= segment->length;
}
ret = lines[line].segments[selected_segment].p1 +
lines[line].segments[selected_segment].dir * n_offset +
lines[line].segments[selected_segment].tangent * normal_offset;
return ret;
}

View File

@@ -14,17 +14,34 @@ protected:
_Signal<void> lines_updated; _Signal<void> lines_updated;
public: public:
static ImmediateGeometry *get_debug_node(); struct line_building_data {
String building_key;
uint64_t building_key_hash;
float line_offset;
float normal_offset;
};
struct line_segment {
Vector3 p1;
Vector3 p2;
float length;
Vector3 dir;
Vector3 tangent;
float offset;
};
struct road_line { struct road_line {
std::vector<Transform> points; std::vector<Transform> points;
std::vector<int> indices; std::vector<int> indices;
std::vector<struct line_building_data> buildings;
std::vector<struct line_segment> segments;
int lanes; int lanes;
int pattern; int pattern;
int flags; int flags;
Dictionary metadata; Dictionary metadata;
_Signal<void> line_updated; _Signal<void> line_updated;
}; };
static ImmediateGeometry *get_debug_node();
HashMap<String, struct road_line> lines; HashMap<String, struct road_line> lines;
HashMap<String, Ref<Curve3D> > curves;
static RoadLinesData *get_singleton(); static RoadLinesData *get_singleton();
virtual ~RoadLinesData(); virtual ~RoadLinesData();
static void cleanup(); static void cleanup();
@@ -36,6 +53,13 @@ public:
std::vector<Vector3> &road_lines_nodes); std::vector<Vector3> &road_lines_nodes);
void set_debug_flags(int debug_flags); void set_debug_flags(int debug_flags);
int get_debug_flags() const; int get_debug_flags() const;
void update_line_segments(const String &line);
void line_add_building(const String &line, const String &key,
float curve_offset, float normal_offset);
void assign_close_buildings(const String &line);
bool line_has_building(const String &line, const String &building_key);
Vector3 get_point_by_offsets(const String &line, float dir_offset,
float normal_offset);
private: private:
void create_segments_from_lines(); void create_segments_from_lines();

View File

@@ -21,6 +21,7 @@
#include "from_string.h" #include "from_string.h"
#include "road_lines_data.h" #include "road_lines_data.h"
#include "road_processing.h" #include "road_processing.h"
#include "buildings_data.h"
#include "road_lines_editor.h" #include "road_lines_editor.h"
static ImmediateGeometry *line_im = nullptr; static ImmediateGeometry *line_im = nullptr;
@@ -241,6 +242,8 @@ public:
"%road_lines_metadata_update"); "%road_lines_metadata_update");
TextEdit *metadata_edit = editor->get_as_node<TextEdit>( TextEdit *metadata_edit = editor->get_as_node<TextEdit>(
"%road_lines_metadata_edit"); "%road_lines_metadata_edit");
Button *line_buildings_close =
editor->get_as_node<Button>("%line_buildings_close");
cancel_button->connect("pressed", this, "cancel_handler"); cancel_button->connect("pressed", this, "cancel_handler");
line_name->connect("text_entered", this, "entered_handler"); line_name->connect("text_entered", this, "entered_handler");
line_name->connect("text_changed", this, "changed_handler"); line_name->connect("text_changed", this, "changed_handler");
@@ -250,10 +253,14 @@ public:
"update_metadata_handler"); "update_metadata_handler");
metadata_edit->connect("text_changed", this, metadata_edit->connect("text_changed", this,
"metadata_changed_handler"); "metadata_changed_handler");
line_buildings_close->connect("pressed", this,
"line_buildings_close_handler");
} }
virtual ~HandleCreateNewLine() virtual ~HandleCreateNewLine()
{ {
int i; int i;
Button *line_buildings_close =
editor->get_as_node<Button>("%line_buildings_close");
TextEdit *metadata_edit = editor->get_as_node<TextEdit>( TextEdit *metadata_edit = editor->get_as_node<TextEdit>(
"%road_lines_metadata_edit"); "%road_lines_metadata_edit");
Button *update_metadata_button = editor->get_as_node<Button>( Button *update_metadata_button = editor->get_as_node<Button>(
@@ -264,6 +271,8 @@ public:
"%road_lines_create_new_cancel"); "%road_lines_create_new_cancel");
LineEdit *line_name = editor->get_as_node<LineEdit>( LineEdit *line_name = editor->get_as_node<LineEdit>(
"%road_lines_create_new_line_name"); "%road_lines_create_new_line_name");
line_buildings_close->disconnect(
"pressed", this, "line_buildings_close_handler");
metadata_edit->disconnect("text_changed", this, metadata_edit->disconnect("text_changed", this,
"metadata_changed_handler"); "metadata_changed_handler");
update_metadata_button->disconnect("pressed", this, update_metadata_button->disconnect("pressed", this,
@@ -296,6 +305,25 @@ protected:
String text = editor->get_current_line_metadata(); String text = editor->get_current_line_metadata();
metadata_edit->set_text(text); metadata_edit->set_text(text);
} }
void update_line_buildings_editor()
{
int i;
if (current_line == "")
return;
ItemList *items =
editor->get_as_node<ItemList>("%line_buildings_list");
items->clear();
for (i = 0; i < (int)RoadLinesData::get_singleton()
->lines[current_line]
.buildings.size();
i++) {
const String &key = RoadLinesData::get_singleton()
->lines[current_line]
.buildings[i]
.building_key;
items->add_item(key);
}
}
void main_handler(int id) void main_handler(int id)
{ {
switch (id) { switch (id) {
@@ -340,12 +368,25 @@ protected:
case 33: case 33:
editor->remove_road_meshes(); editor->remove_road_meshes();
break; break;
case 34: {
RoadLinesData::get_singleton()->assign_close_buildings(
current_line);
editor->update_line_geometry();
} break;
case 36:
editor->get_as_node<Control>("%road_lines_base")->hide();
editor->get_as_node<Control>("%road_lines_buildings")
->show();
update_line_buildings_editor();
break;
case 51: case 51:
editor->set_point_to_cursor(); editor->set_point_to_cursor();
break; break;
case 52: case 52:
editor->move_cursor_to_point(); editor->move_cursor_to_point();
break; break;
case 53:
editor->move_cursor_to_closest_building();
case 101: case 101:
editor->save_data(); editor->save_data();
break; break;
@@ -403,6 +444,7 @@ protected:
} break; } break;
default: default:
print_line("menu option pressed: " + itos(id)); print_line("menu option pressed: " + itos(id));
assert(false);
} }
} }
void cancel_handler() void cancel_handler()
@@ -496,6 +538,19 @@ protected:
} else } else
metadata_text->remove_color_override("font_color"); metadata_text->remove_color_override("font_color");
} }
void line_buildings_close_handler()
{
editor->get_as_node<Control>("%road_lines_base")->show();
editor->get_as_node<Control>("%road_lines_buildings")->hide();
}
void line_buildings_assign_handler()
{
update_line_buildings_editor();
}
void line_buildings_remove_handler()
{
update_line_buildings_editor();
}
static void _bind_methods() static void _bind_methods()
{ {
ClassDB::bind_method(D_METHOD("main_handler", "id"), ClassDB::bind_method(D_METHOD("main_handler", "id"),
@@ -515,6 +570,15 @@ protected:
ClassDB::bind_method( ClassDB::bind_method(
D_METHOD("metadata_changed_handler"), D_METHOD("metadata_changed_handler"),
&HandleCreateNewLine::metadata_changed_handler); &HandleCreateNewLine::metadata_changed_handler);
ClassDB::bind_method(
D_METHOD("line_buildings_close_handler"),
&HandleCreateNewLine::line_buildings_close_handler);
ClassDB::bind_method(
D_METHOD("line_buildings_assign_handler"),
&HandleCreateNewLine::line_buildings_assign_handler);
ClassDB::bind_method(
D_METHOD("line_buildings_remove_handler"),
&HandleCreateNewLine::line_buildings_remove_handler);
} }
}; };
@@ -593,6 +657,25 @@ void RoadLinesEditor::update_line_geometry()
} }
line_im->end(); line_im->end();
} }
if (rld->lines[current_line].buildings.size() > 1) {
line_im->begin(Mesh::PRIMITIVE_LINES);
for (i = 0;
i < (int)rld->lines[current_line].buildings.size();
i++) {
const RoadLinesData::line_building_data &b =
rld->lines[current_line].buildings[i];
Vector3 pt = rld->get_point_by_offsets(
current_line, b.line_offset,
b.normal_offset);
line_im->set_color(
Color(0.1f, 0.8f, 0.8f, 1.0f));
line_im->add_vertex(pt +
Vector3(0.0f, 5.0f, 0.0f));
line_im->add_vertex(pt +
Vector3(0.0f, 15.0f, 0.0f));
}
line_im->end();
}
} }
} }
void RoadLinesEditor::update_line_index_ui() void RoadLinesEditor::update_line_index_ui()
@@ -705,6 +788,20 @@ void RoadLinesEditor::move_cursor_to_point()
set_ui_cursor_position(xform.origin); set_ui_cursor_position(xform.origin);
} }
void RoadLinesEditor::move_cursor_to_closest_building()
{
print_line("move_cursor_to_closest_building");
Vector3 pt = get_cursor_position();
int index = BuildingsData::get_singleton()->get_closest_building(
Transform(Basis(), pt));
const Transform &xform =
BuildingsData::get_singleton()->buildings[index].xform;
set_cursor_position(xform.origin);
Spatial *cursor = get_as_node<Spatial>(cursor_name);
if (!cursor->is_visible())
cursor->show();
}
void RoadLinesEditor::update(float delta) void RoadLinesEditor::update(float delta)
{ {
if (!active) if (!active)
@@ -794,6 +891,7 @@ void RoadLinesEditor::update_ui()
get_as_node<Control>("%road_lines_base")->show(); get_as_node<Control>("%road_lines_base")->show();
get_as_node<Control>("%road_lines_create_new_line_dlg")->hide(); get_as_node<Control>("%road_lines_create_new_line_dlg")->hide();
get_as_node<Control>("%road_lines_edit_metadata_dlg")->hide(); get_as_node<Control>("%road_lines_edit_metadata_dlg")->hide();
get_as_node<Control>("%road_lines_buildings")->hide();
ItemList *lines_list = get_as_node<ItemList>("%lines_list"); ItemList *lines_list = get_as_node<ItemList>("%lines_list");
List<String> line_keys; List<String> line_keys;
rld->lines.get_key_list(&line_keys); rld->lines.get_key_list(&line_keys);

View File

@@ -30,6 +30,7 @@ public:
void set_point_to_cursor(); void set_point_to_cursor();
int get_line_index(); int get_line_index();
void move_cursor_to_point(); void move_cursor_to_point();
void move_cursor_to_closest_building();
void update(float delta); void update(float delta);
void exit(); void exit();
void editor_command(const String &command, const Array &args); void editor_command(const String &command, const Array &args);

View File

@@ -1,4 +1,5 @@
#include <core/set.h> #include <core/set.h>
#include <core/io/json.h>
#include <scene/main/viewport.h> #include <scene/main/viewport.h>
#include <scene/resources/packed_scene.h> #include <scene/resources/packed_scene.h>
#include <scene/resources/material.h> #include <scene/resources/material.h>
@@ -258,27 +259,13 @@ void StreamWorld::run_command(const String &command, const Array &args)
return; return;
} }
const Transform &xform = args[0]; const Transform &xform = args[0];
int i; int id = data()->get_closest_building(xform);
float dst = Math_INF;
Transform ret;
String rkey;
int id = -1;
for (i = 0; i < (int)data()->buildings.size(); i++) {
Vector3 o = xform.origin;
Vector3 m = data()->buildings[i].xform.origin;
float mdst = o.distance_squared_to(m);
if (dst > mdst) {
ret = data()->buildings[i].xform;
dst = mdst;
rkey = data()->buildings[i].key;
id = i;
}
}
Array ret_data; Array ret_data;
ret_data.resize(5); ret_data.resize(5);
ret_data[0] = ret; ret_data[0] = data()->buildings[id].xform;
ret_data[1] = dst; ret_data[1] = xform.origin.distance_squared_to(
ret_data[2] = rkey; data()->buildings[id].xform.origin);
ret_data[2] = data()->buildings[id].key;
ret_data[3] = id; ret_data[3] = id;
ret_data[4] = data()->buildings[id].id; ret_data[4] = data()->buildings[id].id;
emit_signal("command_result", command, ret_data); emit_signal("command_result", command, ret_data);
@@ -288,11 +275,12 @@ void StreamWorld::run_command(const String &command, const Array &args)
return; return;
} }
String key = args[1]; String key = args[1];
uint64_t khash = key.hash64();
Array ret_data; Array ret_data;
ret_data.resize(1); ret_data.resize(1);
int id = -1, i; int id = -1, i;
for (i = 0; i < (int)data()->buildings.size(); i++) for (i = 0; i < (int)data()->buildings.size(); i++)
if (data()->buildings[i].key == key) { if (data()->buildings[i].key.hash64() == khash) {
id = i; id = i;
break; break;
} }
@@ -306,16 +294,12 @@ void StreamWorld::run_command(const String &command, const Array &args)
int id = args[0]; int id = args[0];
if (id < 0 || id >= (int)data()->buildings.size()) if (id < 0 || id >= (int)data()->buildings.size())
return; return;
String key = data()->buildings[id].key; data()->update_building_transform(id, args[1]);
data()->buildings[id].xform == args[1];
if (item_nodes.has(id)) { if (item_nodes.has(id)) {
Spatial *bnode = Spatial *bnode =
Object::cast_to<Spatial>(item_nodes[id]); Object::cast_to<Spatial>(item_nodes[id]);
bnode->set_global_transform(args[1]); bnode->set_global_transform(args[1]);
} }
VariantWriter::write_to_string(data()->buildings[id].xform,
key);
data()->buildings[id].key = key;
} else if (command == "checkpoint") } else if (command == "checkpoint")
data()->checkpoint(); data()->checkpoint();
else if (command == "undo") else if (command == "undo")
@@ -356,10 +340,10 @@ void StreamWorld::run_command(const String &command, const Array &args)
return; return;
} }
const Dictionary &building_dict = args[0]; const Dictionary &building_dict = args[0];
const String &key = args[1];
struct BuildingsData::building b; struct BuildingsData::building b;
// TODO: check that key is valid // TODO: check that key is valid
BuildingsData::building::from_dict(&b, building_dict, key); print_verbose("DICT: " + (JSON::print(building_dict, "\t")));
BuildingsData::building::from_dict(&b, building_dict);
data()->buildings.push_back(b); data()->buildings.push_back(b);
load_building(data()->buildings.size() - 1); load_building(data()->buildings.size() - 1);
} else if (command == "remove_building") { } else if (command == "remove_building") {

View File

@@ -389,12 +389,8 @@ void WorldEditor::world_command_result(const String &what, const Array &data)
} }
static std::vector<String> tool_buttons = { static std::vector<String> tool_buttons = {
"%select_buildings" "%select_buildings", "%select_navigation", "%select_poi",
"%select_navigation", "%select_road_lines", "%select_npc", "%buildings_save",
"%select_poi",
"%select_road_lines",
"%select_npc",
"%buildings_save",
}; };
std::vector<HandleCommandButton *> tool_handlers; std::vector<HandleCommandButton *> tool_handlers;
void WorldEditor::_notification(int which) void WorldEditor::_notification(int which)

View File

@@ -4,7 +4,6 @@
#include <cassert> #include <cassert>
#include <list> #include <list>
#include <scene/3d/spatial.h> #include <scene/3d/spatial.h>
#include "editor_mixin.h"
#include "stream.h" #include "stream.h"
class RoadLinesEditor; class RoadLinesEditor;
class BuildingsEditor; class BuildingsEditor;