Worked on buildings in lines
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -233,7 +233,7 @@ text = "POI mode"
|
||||
unique_name_in_owner = true
|
||||
margin_top = 538.0
|
||||
margin_right = 248.0
|
||||
margin_bottom = 1188.0
|
||||
margin_bottom = 1497.0
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_road_lines"]
|
||||
margin_right = 248.0
|
||||
@@ -283,7 +283,7 @@ margin_left = 79.0
|
||||
margin_right = 124.0
|
||||
margin_bottom = 20.0
|
||||
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
|
||||
|
||||
[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
|
||||
focus_mode = 2
|
||||
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
|
||||
|
||||
[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_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"]
|
||||
unique_name_in_owner = true
|
||||
margin_top = 1192.0
|
||||
margin_top = 1501.0
|
||||
margin_right = 248.0
|
||||
margin_bottom = 1214.0
|
||||
margin_bottom = 1523.0
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_npc"]
|
||||
margin_right = 248.0
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <core/os/memory.h>
|
||||
#include <core/io/json.h>
|
||||
#include <core/os/time.h>
|
||||
#include <core/os/file_access.h>
|
||||
#include <core/io/config_file.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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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();
|
||||
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);
|
||||
e = e->next();
|
||||
}
|
||||
@@ -136,8 +177,7 @@ void BuildingsData::save_buildings_json(const String &buildings_path)
|
||||
fa->close();
|
||||
Dictionary json;
|
||||
for (i = 0; i < (int)buildings.size(); i++) {
|
||||
String key;
|
||||
VariantWriter::write_to_string(buildings[i].xform, key);
|
||||
String key = buildings[i].key;
|
||||
Dictionary dict = buildings[i].to_dict();
|
||||
dict["index"] = i;
|
||||
json[key] = dict;
|
||||
@@ -149,12 +189,13 @@ void BuildingsData::save_buildings_json(const String &buildings_path)
|
||||
print_line("entries count: " + itos(buildings.size()));
|
||||
}
|
||||
|
||||
void BuildingsData::building::from_dict(building *b, const Dictionary &dict,
|
||||
const String &key)
|
||||
void BuildingsData::building::from_dict(building *b, const Dictionary &dict)
|
||||
{
|
||||
int i;
|
||||
b->key = key;
|
||||
b->xform = from_string<Transform>(key);
|
||||
assert(dict.has("key"));
|
||||
assert(dict.has("xform"));
|
||||
b->xform = from_string<Transform>(
|
||||
dict.get("xform", to_string<Transform>(Transform())));
|
||||
b->id = dict.get("id", "empty");
|
||||
b->pattern_id = dict.get("pattern_id", 0);
|
||||
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[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)
|
||||
@@ -206,6 +255,8 @@ Dictionary BuildingsData::building::to_dict() const
|
||||
wt[0] = worktime[0];
|
||||
wt[1] = worktime[1];
|
||||
ret["worktime"] = wt;
|
||||
ret["key"] = key;
|
||||
ret["xform"] = to_string<Transform>(xform);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,14 @@ public:
|
||||
int pattern_id;
|
||||
Vector<int> residents, workers, guests;
|
||||
String key;
|
||||
uint64_t key_hash;
|
||||
Transform xform;
|
||||
int worktime[2];
|
||||
bool generated;
|
||||
static void from_dict(struct building *b,
|
||||
const Dictionary &dict,
|
||||
const String &key);
|
||||
const Dictionary &dict);
|
||||
Dictionary to_dict() const;
|
||||
String line_name;
|
||||
};
|
||||
/* Scene objects data */
|
||||
struct scene_data {
|
||||
@@ -54,7 +55,10 @@ public:
|
||||
void undo();
|
||||
void fill_door_locations();
|
||||
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 void cleanup();
|
||||
int get_building_by_key(const String &key);
|
||||
};
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <core/variant.h>
|
||||
#include <core/os/time.h>
|
||||
#include <scene/gui/option_button.h>
|
||||
#include <scene/main/viewport.h>
|
||||
#include <scene/3d/camera.h>
|
||||
@@ -9,6 +10,7 @@
|
||||
#include "from_string.h"
|
||||
#include "editor_event.h"
|
||||
#include "world_editor.h"
|
||||
#include "buildings_data.h"
|
||||
#include "buildings_editor.h"
|
||||
|
||||
class HandleChangeBuildingType : public Object {
|
||||
@@ -240,10 +242,15 @@ void BuildingsEditor::handle_create_building()
|
||||
->get_global_transform();
|
||||
Dictionary building_data;
|
||||
/* FIXME: calculate AABBs as in previous editor */
|
||||
String building_xform = to_string<Transform>(xform);
|
||||
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_key);
|
||||
editor->editor_command("create_building", args);
|
||||
}
|
||||
}
|
||||
@@ -425,6 +432,7 @@ void BuildingsEditor::mouse_press(const Vector2 &position)
|
||||
float h = gen->get_height_full(newpos);
|
||||
newpos.y = h;
|
||||
Transform xform(Basis(), newpos);
|
||||
get_as_node<Spatial>("%building_cursor")->show();
|
||||
get_as_node<Spatial>("%building_cursor")
|
||||
->set_global_transform(xform);
|
||||
} break;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <scene/3d/immediate_geometry.h>
|
||||
#include <scene/main/viewport.h>
|
||||
#include "from_string.h"
|
||||
#include "buildings_data.h"
|
||||
#include "road_lines_data.h"
|
||||
|
||||
ImmediateGeometry *RoadLinesData::debug_im = nullptr;
|
||||
@@ -62,7 +63,6 @@ RoadLinesData::RoadLinesData()
|
||||
e = e->next();
|
||||
}
|
||||
}
|
||||
|
||||
RoadLinesData *RoadLinesData::singleton = nullptr;
|
||||
RoadLinesData *RoadLinesData::get_singleton()
|
||||
{
|
||||
@@ -70,7 +70,6 @@ RoadLinesData *RoadLinesData::get_singleton()
|
||||
singleton = memnew(RoadLinesData);
|
||||
return singleton;
|
||||
}
|
||||
|
||||
RoadLinesData::~RoadLinesData()
|
||||
{
|
||||
#if 0
|
||||
@@ -80,18 +79,15 @@ RoadLinesData::~RoadLinesData()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void RoadLinesData::cleanup()
|
||||
{
|
||||
memdelete(singleton);
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
String RoadLinesData::get_road_lines_path()
|
||||
{
|
||||
return road_lines_path;
|
||||
}
|
||||
|
||||
void RoadLinesData::get_road_lines_key_list(List<String> *keys)
|
||||
{
|
||||
List<String> line_keys;
|
||||
@@ -234,8 +230,7 @@ void RoadLinesData::create_segments(const String &road,
|
||||
std::vector<int> &segments)
|
||||
{
|
||||
int i;
|
||||
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||
for (i = 0; i < (int)rld->lines[road].indices.size() - 1; i++) {
|
||||
for (i = 0; i < (int)lines[road].indices.size() - 1; i++) {
|
||||
segments.push_back(i);
|
||||
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(
|
||||
std::vector<Vector3> &road_lines_nodes)
|
||||
{
|
||||
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;
|
||||
{
|
||||
List<String>::Element *k = keys.front();
|
||||
@@ -335,25 +328,22 @@ void RoadLinesData::update_road_lines_nodes(
|
||||
std::tuple<String, String> data = kcmp[it->first];
|
||||
const String &k = std::get<0>(data);
|
||||
const String &r = std::get<1>(data);
|
||||
if (rld->lines[k].indices.size() < 2)
|
||||
if (lines[k].indices.size() < 2)
|
||||
continue;
|
||||
if (rld->lines[r].indices.size() < 2)
|
||||
if (lines[r].indices.size() < 2)
|
||||
continue;
|
||||
for (i = 0; i < (int)rld->lines[k].indices.size() - 1; i++) {
|
||||
for (j = 0; j < (int)rld->lines[k].indices.size() - 1;
|
||||
j++) {
|
||||
for (i = 0; i < (int)lines[k].indices.size() - 1; i++) {
|
||||
for (j = 0; j < (int)lines[k].indices.size() - 1; j++) {
|
||||
uint32_t key = k.hash() ^ i ^ r.hash() ^ j ^
|
||||
2147483137;
|
||||
uint32_t key2 = r.hash() ^ j ^ k.hash() ^ i ^
|
||||
2147463167;
|
||||
if (checks.find(key) == checks.end() &&
|
||||
checks.find(key2) == checks.end()) {
|
||||
int idx_a1 = rld->lines[k].indices[i];
|
||||
int idx_a2 =
|
||||
rld->lines[k].indices[i + 1];
|
||||
int idx_b1 = rld->lines[k].indices[j];
|
||||
int idx_b2 =
|
||||
rld->lines[k].indices[j + 1];
|
||||
int idx_a1 = lines[k].indices[i];
|
||||
int idx_a2 = lines[k].indices[i + 1];
|
||||
int idx_b1 = lines[k].indices[j];
|
||||
int idx_b2 = lines[k].indices[j + 1];
|
||||
std::vector<int> cmp1 = { idx_a1,
|
||||
idx_a2 };
|
||||
if (std::find(cmp1.begin(), cmp1.end(),
|
||||
@@ -419,16 +409,16 @@ void RoadLinesData::update_road_lines_nodes(
|
||||
int nidx = road_lines_nodes.size();
|
||||
road_lines_nodes.push_back(pxt);
|
||||
// int il = (int)road_lines[k].indices.size();
|
||||
assert(std::find(rld->lines[k].indices.begin(),
|
||||
rld->lines[k].indices.end(),
|
||||
nidx) == rld->lines[k].indices.end());
|
||||
assert(std::find(rld->lines[r].indices.begin(),
|
||||
rld->lines[r].indices.end(),
|
||||
nidx) == rld->lines[r].indices.end());
|
||||
rld->lines[k].indices.insert(
|
||||
rld->lines[k].indices.begin() + i + 1, nidx);
|
||||
rld->lines[r].indices.insert(
|
||||
rld->lines[k].indices.begin() + j + 1, nidx);
|
||||
assert(std::find(lines[k].indices.begin(),
|
||||
lines[k].indices.end(),
|
||||
nidx) == lines[k].indices.end());
|
||||
assert(std::find(lines[r].indices.begin(),
|
||||
lines[r].indices.end(),
|
||||
nidx) == lines[r].indices.end());
|
||||
lines[k].indices.insert(
|
||||
lines[k].indices.begin() + i + 1, nidx);
|
||||
lines[r].indices.insert(
|
||||
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;
|
||||
List<String> keys;
|
||||
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||
rld->get_road_lines_key_list(&keys);
|
||||
get_road_lines_key_list(&keys);
|
||||
List<String>::Element *e = keys.front();
|
||||
while (e) {
|
||||
String rkey = e->get();
|
||||
struct RoadLinesData::road_line &pt = rld->lines[rkey];
|
||||
struct RoadLinesData::road_line &pt = lines[rkey];
|
||||
String outline = rkey + ": ";
|
||||
for (i = 0; i < (int)pt.indices.size(); 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();
|
||||
}
|
||||
}
|
||||
|
||||
ImmediateGeometry *RoadLinesData::get_debug_node()
|
||||
{
|
||||
if (!debug_im) {
|
||||
@@ -474,7 +462,6 @@ ImmediateGeometry *RoadLinesData::get_debug_node()
|
||||
}
|
||||
return debug_im;
|
||||
}
|
||||
|
||||
void RoadLinesData::process_lines(
|
||||
std::unordered_map<uint32_t, std::vector<Vector3> >
|
||||
&road_lines_nodes_hash,
|
||||
@@ -485,13 +472,181 @@ void RoadLinesData::process_lines(
|
||||
update_road_lines_nodes(road_lines_nodes);
|
||||
dump_road_lines(road_lines_nodes);
|
||||
}
|
||||
|
||||
void RoadLinesData::set_debug_flags(int debug_flags)
|
||||
{
|
||||
this->debug_flags = debug_flags;
|
||||
}
|
||||
|
||||
int RoadLinesData::get_debug_flags() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -14,17 +14,34 @@ protected:
|
||||
_Signal<void> lines_updated;
|
||||
|
||||
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 {
|
||||
std::vector<Transform> points;
|
||||
std::vector<int> indices;
|
||||
std::vector<struct line_building_data> buildings;
|
||||
std::vector<struct line_segment> segments;
|
||||
int lanes;
|
||||
int pattern;
|
||||
int flags;
|
||||
Dictionary metadata;
|
||||
_Signal<void> line_updated;
|
||||
};
|
||||
static ImmediateGeometry *get_debug_node();
|
||||
HashMap<String, struct road_line> lines;
|
||||
HashMap<String, Ref<Curve3D> > curves;
|
||||
static RoadLinesData *get_singleton();
|
||||
virtual ~RoadLinesData();
|
||||
static void cleanup();
|
||||
@@ -36,6 +53,13 @@ public:
|
||||
std::vector<Vector3> &road_lines_nodes);
|
||||
void set_debug_flags(int debug_flags);
|
||||
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:
|
||||
void create_segments_from_lines();
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "from_string.h"
|
||||
#include "road_lines_data.h"
|
||||
#include "road_processing.h"
|
||||
#include "buildings_data.h"
|
||||
#include "road_lines_editor.h"
|
||||
|
||||
static ImmediateGeometry *line_im = nullptr;
|
||||
@@ -241,6 +242,8 @@ public:
|
||||
"%road_lines_metadata_update");
|
||||
TextEdit *metadata_edit = editor->get_as_node<TextEdit>(
|
||||
"%road_lines_metadata_edit");
|
||||
Button *line_buildings_close =
|
||||
editor->get_as_node<Button>("%line_buildings_close");
|
||||
cancel_button->connect("pressed", this, "cancel_handler");
|
||||
line_name->connect("text_entered", this, "entered_handler");
|
||||
line_name->connect("text_changed", this, "changed_handler");
|
||||
@@ -250,10 +253,14 @@ public:
|
||||
"update_metadata_handler");
|
||||
metadata_edit->connect("text_changed", this,
|
||||
"metadata_changed_handler");
|
||||
line_buildings_close->connect("pressed", this,
|
||||
"line_buildings_close_handler");
|
||||
}
|
||||
virtual ~HandleCreateNewLine()
|
||||
{
|
||||
int i;
|
||||
Button *line_buildings_close =
|
||||
editor->get_as_node<Button>("%line_buildings_close");
|
||||
TextEdit *metadata_edit = editor->get_as_node<TextEdit>(
|
||||
"%road_lines_metadata_edit");
|
||||
Button *update_metadata_button = editor->get_as_node<Button>(
|
||||
@@ -264,6 +271,8 @@ public:
|
||||
"%road_lines_create_new_cancel");
|
||||
LineEdit *line_name = editor->get_as_node<LineEdit>(
|
||||
"%road_lines_create_new_line_name");
|
||||
line_buildings_close->disconnect(
|
||||
"pressed", this, "line_buildings_close_handler");
|
||||
metadata_edit->disconnect("text_changed", this,
|
||||
"metadata_changed_handler");
|
||||
update_metadata_button->disconnect("pressed", this,
|
||||
@@ -296,6 +305,25 @@ protected:
|
||||
String text = editor->get_current_line_metadata();
|
||||
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)
|
||||
{
|
||||
switch (id) {
|
||||
@@ -340,12 +368,25 @@ protected:
|
||||
case 33:
|
||||
editor->remove_road_meshes();
|
||||
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:
|
||||
editor->set_point_to_cursor();
|
||||
break;
|
||||
case 52:
|
||||
editor->move_cursor_to_point();
|
||||
break;
|
||||
case 53:
|
||||
editor->move_cursor_to_closest_building();
|
||||
case 101:
|
||||
editor->save_data();
|
||||
break;
|
||||
@@ -403,6 +444,7 @@ protected:
|
||||
} break;
|
||||
default:
|
||||
print_line("menu option pressed: " + itos(id));
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
void cancel_handler()
|
||||
@@ -496,6 +538,19 @@ protected:
|
||||
} else
|
||||
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()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("main_handler", "id"),
|
||||
@@ -515,6 +570,15 @@ protected:
|
||||
ClassDB::bind_method(
|
||||
D_METHOD("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();
|
||||
}
|
||||
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()
|
||||
@@ -705,6 +788,20 @@ void RoadLinesEditor::move_cursor_to_point()
|
||||
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)
|
||||
{
|
||||
if (!active)
|
||||
@@ -794,6 +891,7 @@ void RoadLinesEditor::update_ui()
|
||||
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_edit_metadata_dlg")->hide();
|
||||
get_as_node<Control>("%road_lines_buildings")->hide();
|
||||
ItemList *lines_list = get_as_node<ItemList>("%lines_list");
|
||||
List<String> line_keys;
|
||||
rld->lines.get_key_list(&line_keys);
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
void set_point_to_cursor();
|
||||
int get_line_index();
|
||||
void move_cursor_to_point();
|
||||
void move_cursor_to_closest_building();
|
||||
void update(float delta);
|
||||
void exit();
|
||||
void editor_command(const String &command, const Array &args);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <core/set.h>
|
||||
#include <core/io/json.h>
|
||||
#include <scene/main/viewport.h>
|
||||
#include <scene/resources/packed_scene.h>
|
||||
#include <scene/resources/material.h>
|
||||
@@ -258,27 +259,13 @@ void StreamWorld::run_command(const String &command, const Array &args)
|
||||
return;
|
||||
}
|
||||
const Transform &xform = args[0];
|
||||
int i;
|
||||
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;
|
||||
}
|
||||
}
|
||||
int id = data()->get_closest_building(xform);
|
||||
Array ret_data;
|
||||
ret_data.resize(5);
|
||||
ret_data[0] = ret;
|
||||
ret_data[1] = dst;
|
||||
ret_data[2] = rkey;
|
||||
ret_data[0] = data()->buildings[id].xform;
|
||||
ret_data[1] = xform.origin.distance_squared_to(
|
||||
data()->buildings[id].xform.origin);
|
||||
ret_data[2] = data()->buildings[id].key;
|
||||
ret_data[3] = id;
|
||||
ret_data[4] = data()->buildings[id].id;
|
||||
emit_signal("command_result", command, ret_data);
|
||||
@@ -288,11 +275,12 @@ void StreamWorld::run_command(const String &command, const Array &args)
|
||||
return;
|
||||
}
|
||||
String key = args[1];
|
||||
uint64_t khash = key.hash64();
|
||||
Array ret_data;
|
||||
ret_data.resize(1);
|
||||
int id = -1, 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;
|
||||
break;
|
||||
}
|
||||
@@ -306,16 +294,12 @@ void StreamWorld::run_command(const String &command, const Array &args)
|
||||
int id = args[0];
|
||||
if (id < 0 || id >= (int)data()->buildings.size())
|
||||
return;
|
||||
String key = data()->buildings[id].key;
|
||||
data()->buildings[id].xform == args[1];
|
||||
data()->update_building_transform(id, args[1]);
|
||||
if (item_nodes.has(id)) {
|
||||
Spatial *bnode =
|
||||
Object::cast_to<Spatial>(item_nodes[id]);
|
||||
bnode->set_global_transform(args[1]);
|
||||
}
|
||||
VariantWriter::write_to_string(data()->buildings[id].xform,
|
||||
key);
|
||||
data()->buildings[id].key = key;
|
||||
} else if (command == "checkpoint")
|
||||
data()->checkpoint();
|
||||
else if (command == "undo")
|
||||
@@ -356,10 +340,10 @@ void StreamWorld::run_command(const String &command, const Array &args)
|
||||
return;
|
||||
}
|
||||
const Dictionary &building_dict = args[0];
|
||||
const String &key = args[1];
|
||||
struct BuildingsData::building b;
|
||||
// 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);
|
||||
load_building(data()->buildings.size() - 1);
|
||||
} else if (command == "remove_building") {
|
||||
|
||||
@@ -389,12 +389,8 @@ void WorldEditor::world_command_result(const String &what, const Array &data)
|
||||
}
|
||||
|
||||
static std::vector<String> tool_buttons = {
|
||||
"%select_buildings"
|
||||
"%select_navigation",
|
||||
"%select_poi",
|
||||
"%select_road_lines",
|
||||
"%select_npc",
|
||||
"%buildings_save",
|
||||
"%select_buildings", "%select_navigation", "%select_poi",
|
||||
"%select_road_lines", "%select_npc", "%buildings_save",
|
||||
};
|
||||
std::vector<HandleCommandButton *> tool_handlers;
|
||||
void WorldEditor::_notification(int which)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <scene/3d/spatial.h>
|
||||
#include "editor_mixin.h"
|
||||
#include "stream.h"
|
||||
class RoadLinesEditor;
|
||||
class BuildingsEditor;
|
||||
|
||||
Reference in New Issue
Block a user