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
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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -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);

View File

@@ -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") {

View File

@@ -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)

View File

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