Refactoring of lines handling
This commit is contained in:
435
src/modules/stream/road_lines_data.cpp
Normal file
435
src/modules/stream/road_lines_data.cpp
Normal file
@@ -0,0 +1,435 @@
|
|||||||
|
#undef NDEBUG
|
||||||
|
#include <cassert>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <core/io/config_file.h>
|
||||||
|
#include <core/io/json.h>
|
||||||
|
#include <core/os/dir_access.h>
|
||||||
|
#include <core/os/time.h>
|
||||||
|
#include <core/math/geometry.h>
|
||||||
|
#include "from_string.h"
|
||||||
|
#include "road_lines_data.h"
|
||||||
|
RoadLinesData::RoadLinesData()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
ConfigFile config;
|
||||||
|
Error result = config.load("res://config/stream.conf");
|
||||||
|
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
||||||
|
road_lines_path = config.get_value("lines", "road_lines_path");
|
||||||
|
String road_lines_path = config.get_value("lines", "road_lines_path");
|
||||||
|
String road_lines_json =
|
||||||
|
FileAccess::get_file_as_string(road_lines_path);
|
||||||
|
Variant json_v;
|
||||||
|
String es;
|
||||||
|
int eline;
|
||||||
|
Error status = JSON::parse(road_lines_json, json_v, es, eline);
|
||||||
|
ERR_FAIL_COND_MSG(status != OK, "Can't parse json: " + es +
|
||||||
|
" at line: " + itos(eline));
|
||||||
|
|
||||||
|
Dictionary json = json_v;
|
||||||
|
List<Variant> keys;
|
||||||
|
json.get_key_list(&keys);
|
||||||
|
List<Variant>::Element *e = keys.front();
|
||||||
|
while (e) {
|
||||||
|
String key = e->get();
|
||||||
|
struct road_line rline;
|
||||||
|
Dictionary entry = json.get(key, Dictionary());
|
||||||
|
Array points = entry.get("points", Array());
|
||||||
|
Array indices = entry.get("indices", Array());
|
||||||
|
rline.metadata = entry.get("metadata", Dictionary());
|
||||||
|
int lanes = entry.get("lanes", -1);
|
||||||
|
int pattern = entry.get("pattern", -1);
|
||||||
|
rline.pattern = pattern;
|
||||||
|
rline.points.resize(points.size());
|
||||||
|
rline.indices.resize(indices.size());
|
||||||
|
for (i = 0; i < (int)points.size(); i++) {
|
||||||
|
String point_s = points[i];
|
||||||
|
rline.points[i] = from_string<Transform>(point_s);
|
||||||
|
}
|
||||||
|
for (i = 0; i < (int)indices.size(); i++) {
|
||||||
|
int index = indices[i];
|
||||||
|
rline.indices[i] = index;
|
||||||
|
}
|
||||||
|
// TODO: wtf is flags?
|
||||||
|
rline.lanes = lanes;
|
||||||
|
lines[key] = rline;
|
||||||
|
e = e->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RoadLinesData *RoadLinesData::singleton = nullptr;
|
||||||
|
RoadLinesData *RoadLinesData::get_singleton()
|
||||||
|
{
|
||||||
|
if (!singleton)
|
||||||
|
singleton = memnew(RoadLinesData);
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
lines.get_key_list(&line_keys);
|
||||||
|
List<String>::Element *e = line_keys.front();
|
||||||
|
keys->clear();
|
||||||
|
while (e) {
|
||||||
|
const String &key = e->get();
|
||||||
|
if (key.ends_with("_road"))
|
||||||
|
keys->push_back(key);
|
||||||
|
e = e->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void RoadLinesData::save_data()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
ConfigFile config;
|
||||||
|
Error result = config.load("res://config/stream.conf");
|
||||||
|
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
||||||
|
String road_lines_path = config.get_value("road", "road_lines_path");
|
||||||
|
String road_lines_json =
|
||||||
|
FileAccess::get_file_as_string(road_lines_path);
|
||||||
|
Dictionary output;
|
||||||
|
List<String> keys;
|
||||||
|
lines.get_key_list(&keys);
|
||||||
|
List<String>::Element *e = keys.front();
|
||||||
|
while (e) {
|
||||||
|
Dictionary pvalues;
|
||||||
|
Array points, indices;
|
||||||
|
points.resize(lines[e->get()].points.size());
|
||||||
|
for (i = 0; i < (int)lines[e->get()].points.size(); i++)
|
||||||
|
points[i] = to_string(lines[e->get()].points[i]);
|
||||||
|
indices.resize(lines[e->get()].indices.size());
|
||||||
|
for (i = 0; i < (int)lines[e->get()].indices.size(); i++)
|
||||||
|
indices[i] = lines[e->get()].indices[i];
|
||||||
|
pvalues["points"] = points;
|
||||||
|
// pvalues["indices"] = indices;
|
||||||
|
pvalues["metadata"] = lines[e->get()].metadata;
|
||||||
|
pvalues["lanes"] = lines[e->get()].lanes;
|
||||||
|
pvalues["pattern"] = lines[e->get()].pattern;
|
||||||
|
output[e->get()] = pvalues;
|
||||||
|
e = e->next();
|
||||||
|
}
|
||||||
|
print_verbose(JSON::print(output, "\t", false));
|
||||||
|
Error err = OK;
|
||||||
|
if (FileAccess::exists(road_lines_path)) {
|
||||||
|
DirAccess *dir = DirAccess::open("res:///", &err);
|
||||||
|
assert(dir && err == OK);
|
||||||
|
err = dir->copy(
|
||||||
|
road_lines_path,
|
||||||
|
road_lines_path + "." +
|
||||||
|
String::num(
|
||||||
|
Time::get_singleton()
|
||||||
|
->get_unix_time_from_system()));
|
||||||
|
}
|
||||||
|
FileAccess *fd =
|
||||||
|
FileAccess::open(road_lines_path, FileAccess::WRITE, &err);
|
||||||
|
if (err == OK) {
|
||||||
|
fd->store_string(JSON::print(output, "\t", false));
|
||||||
|
fd->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t RoadLinesData::road_lines_hash(const Vector3 &v)
|
||||||
|
{
|
||||||
|
int x = (int)(v.x / 100);
|
||||||
|
int y = (int)(v.y / 100);
|
||||||
|
int z = (int)(v.z / 100);
|
||||||
|
return x ^ (y * 100) ^ (z * 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoadLinesData::road_lines_curve_index(
|
||||||
|
struct RoadLinesData::road_line &rline,
|
||||||
|
std::unordered_map<uint32_t, std::vector<Vector3> >
|
||||||
|
&road_lines_nodes_hash,
|
||||||
|
std::vector<Vector3> &road_lines_nodes)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
rline.indices.clear();
|
||||||
|
for (i = 0; i < (int)rline.points.size(); i++) {
|
||||||
|
Vector3 pt = rline.points[i].origin;
|
||||||
|
int pt_hash = road_lines_hash(pt);
|
||||||
|
if (road_lines_nodes_hash.find(pt_hash) !=
|
||||||
|
road_lines_nodes_hash.end()) {
|
||||||
|
bool ok = true;
|
||||||
|
for (j = 0;
|
||||||
|
j < (int)road_lines_nodes_hash[pt_hash].size();
|
||||||
|
j++) {
|
||||||
|
const Vector3 &xpt =
|
||||||
|
road_lines_nodes_hash[pt_hash][j];
|
||||||
|
if (xpt.distance_squared_to(pt) < 160) {
|
||||||
|
ok = false;
|
||||||
|
pt = xpt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
road_lines_nodes_hash[pt_hash].push_back(pt);
|
||||||
|
road_lines_nodes.push_back(pt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
road_lines_nodes.push_back(pt);
|
||||||
|
road_lines_nodes_hash[pt_hash] = { pt };
|
||||||
|
}
|
||||||
|
std::vector<Vector3>::iterator it = std::find(
|
||||||
|
road_lines_nodes.begin(), road_lines_nodes.end(), pt);
|
||||||
|
assert(it != road_lines_nodes.end());
|
||||||
|
int index = it - road_lines_nodes.begin();
|
||||||
|
rline.indices.push_back(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void RoadLinesData::index_lines(
|
||||||
|
std::unordered_map<uint32_t, std::vector<Vector3> >
|
||||||
|
&road_lines_nodes_hash,
|
||||||
|
std::vector<Vector3> &road_lines_nodes)
|
||||||
|
{
|
||||||
|
List<String> keys;
|
||||||
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
|
rld->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];
|
||||||
|
pt.indices.clear();
|
||||||
|
e = e->next();
|
||||||
|
}
|
||||||
|
e = keys.front();
|
||||||
|
while (e) {
|
||||||
|
String rkey = e->get();
|
||||||
|
struct RoadLinesData::road_line &pt = rld->lines[rkey];
|
||||||
|
road_lines_curve_index(pt, road_lines_nodes_hash,
|
||||||
|
road_lines_nodes);
|
||||||
|
e = e->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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++) {
|
||||||
|
int idx1 = rld->lines[road].indices[i];
|
||||||
|
int idx2 = rld->lines[road].indices[i + 1];
|
||||||
|
segments.push_back(idx1);
|
||||||
|
segments.push_back(idx2);
|
||||||
|
segments.push_back(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* add close points on each line to the line */
|
||||||
|
void RoadLinesData::insert_close_points(std::vector<Vector3> &road_lines_nodes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
List<String> keys;
|
||||||
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
|
rld->get_road_lines_key_list(&keys);
|
||||||
|
List<String>::Element *e = keys.front();
|
||||||
|
for (i = 0; i < (int)road_lines_nodes.size(); i++) {
|
||||||
|
int idx3 = i;
|
||||||
|
while (e) {
|
||||||
|
int j;
|
||||||
|
std::vector<int> segments;
|
||||||
|
String rkey = e->get();
|
||||||
|
create_segments(rkey, segments);
|
||||||
|
for (j = 0; j < (int)segments.size(); j += 3) {
|
||||||
|
int idx1 = segments[j];
|
||||||
|
int idx2 = segments[j + 1];
|
||||||
|
int idx = segments[j + 2];
|
||||||
|
/* Skip segment point */
|
||||||
|
if (idx3 == idx1 || idx3 == idx2)
|
||||||
|
continue;
|
||||||
|
Vector3 p1 = road_lines_nodes[idx1];
|
||||||
|
Vector3 p2 = road_lines_nodes[idx2];
|
||||||
|
Vector3 p3 = road_lines_nodes[idx3];
|
||||||
|
std::vector<Vector3> seg = { p1, p2 };
|
||||||
|
Vector3 closest =
|
||||||
|
Geometry::get_closest_point_to_segment(
|
||||||
|
p3, seg.data());
|
||||||
|
if (p3.distance_squared_to(closest) < 160) {
|
||||||
|
road_lines_nodes[idx3] = closest;
|
||||||
|
rld->lines[rkey].indices.insert(
|
||||||
|
rld->lines[rkey].indices.begin() +
|
||||||
|
idx,
|
||||||
|
idx3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e = e->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
std::unordered_map<uint32_t, std::tuple<String, String> > kcmp;
|
||||||
|
{
|
||||||
|
List<String>::Element *k = keys.front();
|
||||||
|
List<String>::Element *r = keys.front();
|
||||||
|
while (k) {
|
||||||
|
String kkey = k->get();
|
||||||
|
uint32_t kkey_hash = kkey.hash();
|
||||||
|
while (r) {
|
||||||
|
String rkey = r->get();
|
||||||
|
uint32_t rkey_hash = rkey.hash();
|
||||||
|
uint32_t key = kkey_hash ^ rkey_hash;
|
||||||
|
uint32_t key2 = rkey_hash ^ kkey_hash;
|
||||||
|
if (kcmp.find(key) == kcmp.end() &&
|
||||||
|
kcmp.find(key2) == kcmp.end())
|
||||||
|
kcmp[key] = std::make_tuple(k->get(),
|
||||||
|
r->get());
|
||||||
|
r = r->next();
|
||||||
|
}
|
||||||
|
k = k->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using checks_tuple =
|
||||||
|
std::tuple<String, int, int, int, String, int, int, int>;
|
||||||
|
std::unordered_map<uint32_t, checks_tuple> checks;
|
||||||
|
std::unordered_map<uint32_t, checks_tuple>::iterator checks_it;
|
||||||
|
std::unordered_map<uint32_t, std::tuple<String, String> >::iterator it;
|
||||||
|
for (it = kcmp.begin(); it != kcmp.end(); it++) {
|
||||||
|
int i, j;
|
||||||
|
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)
|
||||||
|
continue;
|
||||||
|
if (rld->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++) {
|
||||||
|
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];
|
||||||
|
std::vector<int> cmp1 = { idx_a1,
|
||||||
|
idx_a2 };
|
||||||
|
if (std::find(cmp1.begin(), cmp1.end(),
|
||||||
|
idx_b1) != cmp1.end())
|
||||||
|
continue;
|
||||||
|
if (std::find(cmp1.begin(), cmp1.end(),
|
||||||
|
idx_b2) != cmp1.end())
|
||||||
|
continue;
|
||||||
|
checks[key] = std::make_tuple(
|
||||||
|
k, i, idx_a1, idx_a2, r, j,
|
||||||
|
idx_b1, idx_b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
for ch in checks.values():
|
||||||
|
var k = ch[0]
|
||||||
|
var i1 = ch[1]
|
||||||
|
var idx_a1 = ch[2]
|
||||||
|
var idx_a2 = ch[3]
|
||||||
|
var r = ch[4]
|
||||||
|
var j1 = ch[5]
|
||||||
|
var idx_b1 = ch[6]
|
||||||
|
var idx_b2 = ch[7]
|
||||||
|
var p_a1 = road_lines_nodes[idx_a1]
|
||||||
|
var p_a2 = road_lines_nodes[idx_a2]
|
||||||
|
var p_b1 = road_lines_nodes[idx_b1]
|
||||||
|
var p_b2 = road_lines_nodes[idx_b2]
|
||||||
|
var px = Geometry.get_closest_points_between_segments(p_a1, p_a2, p_b1, p_b2)
|
||||||
|
var d = px[0].distance_squared_to(px[1])
|
||||||
|
if d < 160:
|
||||||
|
var pxt = px[0].linear_interpolate(px[1], 0.5)
|
||||||
|
var nidx = road_lines_nodes.size()
|
||||||
|
road_lines_nodes.push_back(pxt)
|
||||||
|
var il = road_lines[k].indices.size()
|
||||||
|
assert(!nidx in road_lines[k].indices)
|
||||||
|
assert(!nidx in road_lines[r].indices)
|
||||||
|
road_lines[k].indices.insert(i1 + 1, nidx)
|
||||||
|
road_lines[r].indices.insert(j1 + 1, nidx)
|
||||||
|
##end
|
||||||
|
*/
|
||||||
|
for (checks_it = checks.begin(); checks_it != checks.end();
|
||||||
|
checks_it++) {
|
||||||
|
String k = std::get<0>(checks_it->second);
|
||||||
|
int i = std::get<1>(checks_it->second);
|
||||||
|
int idx_a1 = std::get<2>(checks_it->second);
|
||||||
|
int idx_a2 = std::get<3>(checks_it->second);
|
||||||
|
String r = std::get<4>(checks_it->second);
|
||||||
|
int j = std::get<5>(checks_it->second);
|
||||||
|
int idx_b1 = std::get<6>(checks_it->second);
|
||||||
|
int idx_b2 = std::get<7>(checks_it->second);
|
||||||
|
Vector3 p_a1 = road_lines_nodes[idx_a1];
|
||||||
|
Vector3 p_a2 = road_lines_nodes[idx_a2];
|
||||||
|
Vector3 p_b1 = road_lines_nodes[idx_b1];
|
||||||
|
Vector3 p_b2 = road_lines_nodes[idx_b2];
|
||||||
|
Vector3 px, px2;
|
||||||
|
Geometry::get_closest_points_between_segments(p_a1, p_a2, p_b1,
|
||||||
|
p_b2, px, px2);
|
||||||
|
float d = px.distance_squared_to(px2);
|
||||||
|
if (d < 160) {
|
||||||
|
Vector3 pxt = px.linear_interpolate(px2, 0.5f);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
List<String>::Element *e = keys.front();
|
||||||
|
while (e) {
|
||||||
|
String rkey = e->get();
|
||||||
|
struct RoadLinesData::road_line &pt = rld->lines[rkey];
|
||||||
|
String outline = rkey + ": ";
|
||||||
|
for (i = 0; i < (int)pt.indices.size(); i++) {
|
||||||
|
outline += " " + itos(pt.indices[i]);
|
||||||
|
}
|
||||||
|
for (i = 0; i < (int)pt.indices.size(); i++) {
|
||||||
|
outline += " " + (road_lines_nodes[pt.indices[i]]
|
||||||
|
.operator String());
|
||||||
|
}
|
||||||
|
e = e->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoadLinesData::process_lines(
|
||||||
|
std::unordered_map<uint32_t, std::vector<Vector3> >
|
||||||
|
&road_lines_nodes_hash,
|
||||||
|
std::vector<Vector3> &road_lines_nodes)
|
||||||
|
{
|
||||||
|
index_lines(road_lines_nodes_hash, road_lines_nodes);
|
||||||
|
insert_close_points(road_lines_nodes);
|
||||||
|
update_road_lines_nodes(road_lines_nodes);
|
||||||
|
dump_road_lines(road_lines_nodes);
|
||||||
|
}
|
||||||
48
src/modules/stream/road_lines_data.h
Normal file
48
src/modules/stream/road_lines_data.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef ROAD_LINES_DATA_H
|
||||||
|
#define ROAD_LINES_DATA_H
|
||||||
|
class RoadLinesData {
|
||||||
|
String road_lines_path;
|
||||||
|
uint32_t road_lines_hash(const Vector3 &v);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RoadLinesData();
|
||||||
|
static RoadLinesData *singleton;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct road_line {
|
||||||
|
std::vector<Transform> points;
|
||||||
|
std::vector<int> indices;
|
||||||
|
int lanes;
|
||||||
|
int pattern;
|
||||||
|
int flags;
|
||||||
|
Dictionary metadata;
|
||||||
|
};
|
||||||
|
HashMap<String, struct road_line> lines;
|
||||||
|
static RoadLinesData *get_singleton();
|
||||||
|
static void cleanup();
|
||||||
|
String get_road_lines_path();
|
||||||
|
void get_road_lines_key_list(List<String> *keys);
|
||||||
|
void save_data();
|
||||||
|
void process_lines(std::unordered_map<uint32_t, std::vector<Vector3> >
|
||||||
|
&road_lines_nodes_hash,
|
||||||
|
std::vector<Vector3> &road_lines_nodes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void index_lines(std::unordered_map<uint32_t, std::vector<Vector3> >
|
||||||
|
&road_lines_nodes_hash,
|
||||||
|
std::vector<Vector3> &road_lines_nodes);
|
||||||
|
|
||||||
|
void create_segments(const String &road, std::vector<int> &segments);
|
||||||
|
|
||||||
|
void insert_close_points(std::vector<Vector3> &road_lines_nodes);
|
||||||
|
|
||||||
|
void update_road_lines_nodes(std::vector<Vector3> &road_lines_nodes);
|
||||||
|
|
||||||
|
void dump_road_lines(const std::vector<Vector3> &road_lines_nodes);
|
||||||
|
void road_lines_curve_index(
|
||||||
|
struct RoadLinesData::road_line &rline,
|
||||||
|
std::unordered_map<uint32_t, std::vector<Vector3> >
|
||||||
|
&road_lines_nodes_hash,
|
||||||
|
std::vector<Vector3> &road_lines_nodes);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -17,17 +17,10 @@
|
|||||||
#include <modules/regex/regex.h>
|
#include <modules/regex/regex.h>
|
||||||
#include "world_editor.h"
|
#include "world_editor.h"
|
||||||
#include "from_string.h"
|
#include "from_string.h"
|
||||||
|
#include "road_lines_data.h"
|
||||||
|
#include "road_processing.h"
|
||||||
#include "road_lines_editor.h"
|
#include "road_lines_editor.h"
|
||||||
|
|
||||||
struct road_line {
|
|
||||||
std::vector<Transform> points;
|
|
||||||
std::vector<int> indices;
|
|
||||||
int lanes;
|
|
||||||
int pattern;
|
|
||||||
int flags;
|
|
||||||
Dictionary metadata;
|
|
||||||
};
|
|
||||||
static HashMap<String, struct road_line> lines;
|
|
||||||
static ImmediateGeometry *line_im = nullptr;
|
static ImmediateGeometry *line_im = nullptr;
|
||||||
static Ref<Material> debug_material;
|
static Ref<Material> debug_material;
|
||||||
|
|
||||||
@@ -484,7 +477,8 @@ Node *RoadLinesEditor::scene()
|
|||||||
static String current_line = "";
|
static String current_line = "";
|
||||||
void RoadLinesEditor::update_line_geometry()
|
void RoadLinesEditor::update_line_geometry()
|
||||||
{
|
{
|
||||||
if (!lines.has(current_line)) {
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
|
if (!rld->lines.has(current_line)) {
|
||||||
if (line_im)
|
if (line_im)
|
||||||
line_im->clear();
|
line_im->clear();
|
||||||
return;
|
return;
|
||||||
@@ -498,15 +492,18 @@ void RoadLinesEditor::update_line_geometry()
|
|||||||
line_im->set_color(Color(1.0f, 0.0f, 0.0f, 1.0f));
|
line_im->set_color(Color(1.0f, 0.0f, 0.0f, 1.0f));
|
||||||
line_im->add_vertex(Vector3(0.0f, 100.0f, 0.0f));
|
line_im->add_vertex(Vector3(0.0f, 100.0f, 0.0f));
|
||||||
line_im->end();
|
line_im->end();
|
||||||
if (lines[current_line].points.size() > 1) {
|
if (rld->lines[current_line].points.size() > 1) {
|
||||||
line_im->begin(Mesh::PRIMITIVE_LINES);
|
line_im->begin(Mesh::PRIMITIVE_LINES);
|
||||||
for (i = 0;
|
for (i = 0;
|
||||||
i < (int)lines[current_line].points.size() - 1;
|
i <
|
||||||
|
(int)rld->lines[current_line].points.size() - 1;
|
||||||
i++) {
|
i++) {
|
||||||
Vector3 pt1 =
|
Vector3 pt1 = rld->lines[current_line]
|
||||||
lines[current_line].points[i].origin;
|
.points[i]
|
||||||
Vector3 pt2 =
|
.origin;
|
||||||
lines[current_line].points[i + 1].origin;
|
Vector3 pt2 = rld->lines[current_line]
|
||||||
|
.points[i + 1]
|
||||||
|
.origin;
|
||||||
line_im->set_color(
|
line_im->set_color(
|
||||||
Color(0.0f, 0.0f, 0.5f, 1.0f));
|
Color(0.0f, 0.0f, 0.5f, 1.0f));
|
||||||
line_im->add_vertex(pt1);
|
line_im->add_vertex(pt1);
|
||||||
@@ -527,14 +524,16 @@ void RoadLinesEditor::update_line_geometry()
|
|||||||
}
|
}
|
||||||
void RoadLinesEditor::update_line_index_ui()
|
void RoadLinesEditor::update_line_index_ui()
|
||||||
{
|
{
|
||||||
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
||||||
sp_line_index->set_max(lines[current_line].points.size() - 1);
|
sp_line_index->set_max(rld->lines[current_line].points.size() - 1);
|
||||||
sp_line_index->set_min(0);
|
sp_line_index->set_min(0);
|
||||||
}
|
}
|
||||||
void RoadLinesEditor::select_line(const String &line_name)
|
void RoadLinesEditor::select_line(const String &line_name)
|
||||||
{
|
{
|
||||||
print_line("selected line: " + line_name);
|
print_line("selected line: " + line_name);
|
||||||
assert(lines.has(line_name));
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
|
assert(rld->lines.has(line_name));
|
||||||
if (current_line != line_name) {
|
if (current_line != line_name) {
|
||||||
current_line = line_name;
|
current_line = line_name;
|
||||||
update_line_index_ui();
|
update_line_index_ui();
|
||||||
@@ -550,18 +549,20 @@ void RoadLinesEditor::select_line(const String &line_name)
|
|||||||
|
|
||||||
bool RoadLinesEditor::line_exists(const String &line_name)
|
bool RoadLinesEditor::line_exists(const String &line_name)
|
||||||
{
|
{
|
||||||
return lines.has(line_name);
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
|
return rld->lines.has(line_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoadLinesEditor::line_create_point()
|
void RoadLinesEditor::line_create_point()
|
||||||
{
|
{
|
||||||
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
/* Create point in line */
|
/* Create point in line */
|
||||||
print_line("line_create_point");
|
print_line("line_create_point");
|
||||||
Vector3 position = get_cursor_position();
|
Vector3 position = get_cursor_position();
|
||||||
Transform xform(Basis(), position);
|
Transform xform(Basis(), position);
|
||||||
int index = get_line_index();
|
int index = get_line_index();
|
||||||
lines[current_line].points.insert(
|
rld->lines[current_line].points.insert(
|
||||||
lines[current_line].points.begin() + index + 1, xform);
|
rld->lines[current_line].points.begin() + index + 1, xform);
|
||||||
update_line_geometry();
|
update_line_geometry();
|
||||||
update_line_index_ui();
|
update_line_index_ui();
|
||||||
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
||||||
@@ -574,10 +575,11 @@ void RoadLinesEditor::line_delete_point()
|
|||||||
/* Delete point from line */
|
/* Delete point from line */
|
||||||
print_line("line_delete_point");
|
print_line("line_delete_point");
|
||||||
int index = get_line_index();
|
int index = get_line_index();
|
||||||
if (lines[current_line].points.size() < 2)
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
|
if (rld->lines[current_line].points.size() < 2)
|
||||||
return;
|
return;
|
||||||
lines[current_line].points.erase(lines[current_line].points.begin() +
|
rld->lines[current_line].points.erase(
|
||||||
index);
|
rld->lines[current_line].points.begin() + index);
|
||||||
update_line_geometry();
|
update_line_geometry();
|
||||||
update_line_index_ui();
|
update_line_index_ui();
|
||||||
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
SpinBox *sp_line_index = get_as_node<SpinBox>("%line_index");
|
||||||
@@ -590,13 +592,14 @@ static const String cursor_name = "%line_cursor";
|
|||||||
|
|
||||||
void RoadLinesEditor::set_point_to_cursor()
|
void RoadLinesEditor::set_point_to_cursor()
|
||||||
{
|
{
|
||||||
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
print_line("set_point_to_cursor");
|
print_line("set_point_to_cursor");
|
||||||
Spatial *cursor = get_as_node<Spatial>(cursor_name);
|
Spatial *cursor = get_as_node<Spatial>(cursor_name);
|
||||||
Transform xform = cursor->get_global_transform();
|
Transform xform = cursor->get_global_transform();
|
||||||
int index = get_line_index();
|
int index = get_line_index();
|
||||||
lines[current_line].points[index].origin = xform.origin;
|
rld->lines[current_line].points[index].origin = xform.origin;
|
||||||
update_line_geometry();
|
update_line_geometry();
|
||||||
set_ui_point_position(lines[current_line].points[index].origin);
|
set_ui_point_position(rld->lines[current_line].points[index].origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
int RoadLinesEditor::get_line_index()
|
int RoadLinesEditor::get_line_index()
|
||||||
@@ -610,8 +613,9 @@ int RoadLinesEditor::get_line_index()
|
|||||||
void RoadLinesEditor::move_cursor_to_point()
|
void RoadLinesEditor::move_cursor_to_point()
|
||||||
{
|
{
|
||||||
print_line("move_cursor_to_point");
|
print_line("move_cursor_to_point");
|
||||||
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
int index = get_line_index();
|
int index = get_line_index();
|
||||||
Transform xform(Basis(), lines[current_line].points[index].origin);
|
Transform xform(Basis(), rld->lines[current_line].points[index].origin);
|
||||||
set_cursor_position(xform.origin);
|
set_cursor_position(xform.origin);
|
||||||
set_ui_cursor_position(xform.origin);
|
set_ui_cursor_position(xform.origin);
|
||||||
}
|
}
|
||||||
@@ -685,12 +689,13 @@ int RoadLinesEditor::get_camera_mode() const
|
|||||||
|
|
||||||
void RoadLinesEditor::update_ui()
|
void RoadLinesEditor::update_ui()
|
||||||
{
|
{
|
||||||
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
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();
|
||||||
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;
|
||||||
lines.get_key_list(&line_keys);
|
rld->lines.get_key_list(&line_keys);
|
||||||
List<String>::Element *e = line_keys.front();
|
List<String>::Element *e = line_keys.front();
|
||||||
lines_list->clear();
|
lines_list->clear();
|
||||||
if (!re.is_valid())
|
if (!re.is_valid())
|
||||||
@@ -722,7 +727,8 @@ void RoadLinesEditor::update_ui()
|
|||||||
void RoadLinesEditor::create_new_line_at_cursor(const String &line_name)
|
void RoadLinesEditor::create_new_line_at_cursor(const String &line_name)
|
||||||
{
|
{
|
||||||
print_line("creating new line called: " + line_name);
|
print_line("creating new line called: " + line_name);
|
||||||
struct road_line rline;
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
|
struct RoadLinesData::road_line rline;
|
||||||
rline.flags = 0;
|
rline.flags = 0;
|
||||||
rline.indices.resize(0);
|
rline.indices.resize(0);
|
||||||
rline.lanes = -1;
|
rline.lanes = -1;
|
||||||
@@ -732,17 +738,18 @@ void RoadLinesEditor::create_new_line_at_cursor(const String &line_name)
|
|||||||
rline.pattern = 0;
|
rline.pattern = 0;
|
||||||
Transform cursor_position(Basis(), get_cursor_position());
|
Transform cursor_position(Basis(), get_cursor_position());
|
||||||
rline.points.push_back(cursor_position);
|
rline.points.push_back(cursor_position);
|
||||||
lines[line_name] = rline;
|
rld->lines[line_name] = rline;
|
||||||
update_line_index_ui();
|
update_line_index_ui();
|
||||||
update_ui();
|
update_ui();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoadLinesEditor::delete_current_line()
|
void RoadLinesEditor::delete_current_line()
|
||||||
{
|
{
|
||||||
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
String delete_line = current_line;
|
String delete_line = current_line;
|
||||||
const String *k = lines.next(&delete_line);
|
const String *k = rld->lines.next(&delete_line);
|
||||||
current_line = *k;
|
current_line = *k;
|
||||||
lines.erase(delete_line);
|
rld->lines.erase(delete_line);
|
||||||
update_line_index_ui();
|
update_line_index_ui();
|
||||||
update_ui();
|
update_ui();
|
||||||
}
|
}
|
||||||
@@ -763,8 +770,9 @@ void RoadLinesEditor::set_cursor_position(const Vector3 &cursor_position)
|
|||||||
}
|
}
|
||||||
void RoadLinesEditor::set_point_position(const Vector3 &position)
|
void RoadLinesEditor::set_point_position(const Vector3 &position)
|
||||||
{
|
{
|
||||||
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
int index = get_line_index();
|
int index = get_line_index();
|
||||||
lines[current_line].points[index].origin = position;
|
rld->lines[current_line].points[index].origin = position;
|
||||||
update_line_geometry();
|
update_line_geometry();
|
||||||
}
|
}
|
||||||
void RoadLinesEditor::set_ui_cursor_position(const Vector3 &cursor_position)
|
void RoadLinesEditor::set_ui_cursor_position(const Vector3 &cursor_position)
|
||||||
@@ -788,9 +796,10 @@ void RoadLinesEditor::set_ui_point_position(const Vector3 &point_position)
|
|||||||
|
|
||||||
void RoadLinesEditor::set_line_index(int index)
|
void RoadLinesEditor::set_line_index(int index)
|
||||||
{
|
{
|
||||||
assert(lines.has(current_line));
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
assert(index < (int)lines[current_line].points.size());
|
assert(rld->lines.has(current_line));
|
||||||
Vector3 point_position = lines[current_line].points[index].origin;
|
assert(index < (int)rld->lines[current_line].points.size());
|
||||||
|
Vector3 point_position = rld->lines[current_line].points[index].origin;
|
||||||
Vector3 cursor_position = point_position;
|
Vector3 cursor_position = point_position;
|
||||||
set_cursor_position(cursor_position);
|
set_cursor_position(cursor_position);
|
||||||
set_ui_cursor_position(cursor_position);
|
set_ui_cursor_position(cursor_position);
|
||||||
@@ -807,7 +816,6 @@ void RoadLinesEditor::line_list_filter_changed(const String &text)
|
|||||||
void RoadLinesEditor::activate()
|
void RoadLinesEditor::activate()
|
||||||
{
|
{
|
||||||
assert(!active);
|
assert(!active);
|
||||||
load_data();
|
|
||||||
print_line("activate::update UI");
|
print_line("activate::update UI");
|
||||||
update_ui();
|
update_ui();
|
||||||
if (!line_im) {
|
if (!line_im) {
|
||||||
@@ -847,7 +855,6 @@ void RoadLinesEditor::deactivate()
|
|||||||
NodePath("%lines_list"));
|
NodePath("%lines_list"));
|
||||||
ItemList *lines_list = Object::cast_to<ItemList>(lines_list_node);
|
ItemList *lines_list = Object::cast_to<ItemList>(lines_list_node);
|
||||||
lines_list->clear();
|
lines_list->clear();
|
||||||
lines.clear();
|
|
||||||
if (line_im) {
|
if (line_im) {
|
||||||
line_im->queue_delete();
|
line_im->queue_delete();
|
||||||
line_im = nullptr;
|
line_im = nullptr;
|
||||||
@@ -874,52 +881,6 @@ void RoadLinesEditor::deactivate()
|
|||||||
active = false;
|
active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoadLinesEditor::load_data()
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
ConfigFile config;
|
|
||||||
Error result = config.load("res://config/stream.conf");
|
|
||||||
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
|
||||||
String road_lines_path = config.get_value("lines", "road_lines_path");
|
|
||||||
String road_lines_json =
|
|
||||||
FileAccess::get_file_as_string(road_lines_path);
|
|
||||||
Variant json_v;
|
|
||||||
String es;
|
|
||||||
int eline;
|
|
||||||
Error status = JSON::parse(road_lines_json, json_v, es, eline);
|
|
||||||
ERR_FAIL_COND_MSG(status != OK, "Can't parse json: " + es +
|
|
||||||
" at line: " + itos(eline));
|
|
||||||
|
|
||||||
Dictionary json = json_v;
|
|
||||||
List<Variant> keys;
|
|
||||||
json.get_key_list(&keys);
|
|
||||||
List<Variant>::Element *e = keys.front();
|
|
||||||
while (e) {
|
|
||||||
String key = e->get();
|
|
||||||
struct road_line rline;
|
|
||||||
Dictionary entry = json.get(key, Dictionary());
|
|
||||||
Array points = entry.get("points", Array());
|
|
||||||
Array indices = entry.get("indices", Array());
|
|
||||||
rline.metadata = entry.get("metadata", Dictionary());
|
|
||||||
int lanes = entry.get("lanes", -1);
|
|
||||||
int pattern = entry.get("pattern", -1);
|
|
||||||
rline.pattern = pattern;
|
|
||||||
rline.points.resize(points.size());
|
|
||||||
rline.indices.resize(indices.size());
|
|
||||||
for (i = 0; i < (int)points.size(); i++) {
|
|
||||||
String point_s = points[i];
|
|
||||||
rline.points[i] = from_string<Transform>(point_s);
|
|
||||||
}
|
|
||||||
for (i = 0; i < (int)indices.size(); i++) {
|
|
||||||
int index = indices[i];
|
|
||||||
rline.indices[i] = index;
|
|
||||||
}
|
|
||||||
// TODO: wtf is flags?
|
|
||||||
rline.lanes = lanes;
|
|
||||||
lines[key] = rline;
|
|
||||||
e = e->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void RoadLinesEditor::place_generated_objects()
|
void RoadLinesEditor::place_generated_objects()
|
||||||
{
|
{
|
||||||
place_zebras();
|
place_zebras();
|
||||||
@@ -1008,56 +969,12 @@ func place_zebras():
|
|||||||
}
|
}
|
||||||
void RoadLinesEditor::save_data()
|
void RoadLinesEditor::save_data()
|
||||||
{
|
{
|
||||||
int i;
|
RoadLinesData::get_singleton()->save_data();
|
||||||
ConfigFile config;
|
|
||||||
Error result = config.load("res://config/stream.conf");
|
|
||||||
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
|
||||||
String road_lines_path = config.get_value("road", "road_lines_path");
|
|
||||||
String road_lines_json =
|
|
||||||
FileAccess::get_file_as_string(road_lines_path);
|
|
||||||
Dictionary output;
|
|
||||||
List<String> keys;
|
|
||||||
lines.get_key_list(&keys);
|
|
||||||
List<String>::Element *e = keys.front();
|
|
||||||
while (e) {
|
|
||||||
Dictionary pvalues;
|
|
||||||
Array points, indices;
|
|
||||||
points.resize(lines[e->get()].points.size());
|
|
||||||
for (i = 0; i < (int)lines[e->get()].points.size(); i++)
|
|
||||||
points[i] = to_string(lines[e->get()].points[i]);
|
|
||||||
indices.resize(lines[e->get()].indices.size());
|
|
||||||
for (i = 0; i < (int)lines[e->get()].indices.size(); i++)
|
|
||||||
indices[i] = lines[e->get()].indices[i];
|
|
||||||
pvalues["points"] = points;
|
|
||||||
// pvalues["indices"] = indices;
|
|
||||||
pvalues["metadata"] = lines[e->get()].metadata;
|
|
||||||
pvalues["lanes"] = lines[e->get()].lanes;
|
|
||||||
pvalues["pattern"] = lines[e->get()].pattern;
|
|
||||||
output[e->get()] = pvalues;
|
|
||||||
e = e->next();
|
|
||||||
}
|
|
||||||
print_verbose(JSON::print(output, "\t", false));
|
|
||||||
Error err = OK;
|
|
||||||
if (FileAccess::exists(road_lines_path)) {
|
|
||||||
DirAccess *dir = DirAccess::open("res:///", &err);
|
|
||||||
assert(dir && err == OK);
|
|
||||||
err = dir->copy(
|
|
||||||
road_lines_path,
|
|
||||||
road_lines_path + "." +
|
|
||||||
String::num(
|
|
||||||
Time::get_singleton()
|
|
||||||
->get_unix_time_from_system()));
|
|
||||||
}
|
|
||||||
FileAccess *fd =
|
|
||||||
FileAccess::open(road_lines_path, FileAccess::WRITE, &err);
|
|
||||||
if (err == OK) {
|
|
||||||
fd->store_string(JSON::print(output, "\t", false));
|
|
||||||
fd->close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void RoadLinesEditor::update_current_line_metadata(const String &text)
|
void RoadLinesEditor::update_current_line_metadata(const String &text)
|
||||||
{
|
{
|
||||||
assert(lines.has(current_line));
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
|
assert(rld->lines.has(current_line));
|
||||||
if (!text.begins_with("{"))
|
if (!text.begins_with("{"))
|
||||||
return;
|
return;
|
||||||
String err_s;
|
String err_s;
|
||||||
@@ -1073,12 +990,13 @@ void RoadLinesEditor::update_current_line_metadata(const String &text)
|
|||||||
print_line("Invalid metadata type, should be Dictionary");
|
print_line("Invalid metadata type, should be Dictionary");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lines[current_line].metadata = v;
|
rld->lines[current_line].metadata = v;
|
||||||
}
|
}
|
||||||
String RoadLinesEditor::get_current_line_metadata() const
|
String RoadLinesEditor::get_current_line_metadata() const
|
||||||
{
|
{
|
||||||
assert(lines.has(current_line));
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
return JSON::print(lines[current_line].metadata, "\t", true);
|
assert(rld->lines.has(current_line));
|
||||||
|
return JSON::print(rld->lines[current_line].metadata, "\t", true);
|
||||||
}
|
}
|
||||||
void RoadLinesEditor::remove_generated_stuff()
|
void RoadLinesEditor::remove_generated_stuff()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void activate();
|
void activate();
|
||||||
void deactivate();
|
void deactivate();
|
||||||
void load_data();
|
|
||||||
void place_zebras();
|
void place_zebras();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <algorithm>
|
|
||||||
#include <core/reference.h>
|
#include <core/reference.h>
|
||||||
#include <core/io/config_file.h>
|
#include <core/io/config_file.h>
|
||||||
#include <core/os/file_access.h>
|
#include <core/os/file_access.h>
|
||||||
#include <core/io/json.h>
|
|
||||||
#include <scene/resources/mesh.h>
|
#include <scene/resources/mesh.h>
|
||||||
#include <scene/3d/mesh_instance.h>
|
#include <scene/3d/mesh_instance.h>
|
||||||
#include <core/math/transform.h>
|
#include <core/math/transform.h>
|
||||||
@@ -16,6 +15,7 @@
|
|||||||
#include <core/hash_map.h>
|
#include <core/hash_map.h>
|
||||||
#include "from_string.h"
|
#include "from_string.h"
|
||||||
#include "road_debug.h"
|
#include "road_debug.h"
|
||||||
|
#include "road_lines_data.h"
|
||||||
#include "road_processing.h"
|
#include "road_processing.h"
|
||||||
|
|
||||||
struct wedge {
|
struct wedge {
|
||||||
@@ -25,13 +25,6 @@ struct wedge {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct RoadLinesProcessing {
|
struct RoadLinesProcessing {
|
||||||
struct road_line {
|
|
||||||
std::vector<Transform> points;
|
|
||||||
std::vector<int> indices;
|
|
||||||
int lanes;
|
|
||||||
int flags;
|
|
||||||
};
|
|
||||||
HashMap<String, struct road_line> road_lines;
|
|
||||||
std::vector<Vector3> nodes;
|
std::vector<Vector3> nodes;
|
||||||
struct edgedata {
|
struct edgedata {
|
||||||
std::vector<int> neighbors;
|
std::vector<int> neighbors;
|
||||||
@@ -52,284 +45,6 @@ struct RoadLinesProcessing {
|
|||||||
singleton = this;
|
singleton = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t road_lines_hash(const Vector3 &v)
|
|
||||||
{
|
|
||||||
int x = (int)(v.x / 100);
|
|
||||||
int y = (int)(v.y / 100);
|
|
||||||
int z = (int)(v.z / 100);
|
|
||||||
return x ^ (y * 100) ^ (z * 10000);
|
|
||||||
}
|
|
||||||
void create_segments(const String &road, std::vector<int> &segments)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < (int)road_lines[road].indices.size() - 1; i++) {
|
|
||||||
int idx1 = road_lines[road].indices[i];
|
|
||||||
int idx2 = road_lines[road].indices[i + 1];
|
|
||||||
segments.push_back(idx1);
|
|
||||||
segments.push_back(idx2);
|
|
||||||
segments.push_back(i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void road_lines_curve_index(
|
|
||||||
struct road_line &rline,
|
|
||||||
std::unordered_map<uint32_t, std::vector<Vector3> >
|
|
||||||
&road_lines_nodes_hash,
|
|
||||||
std::vector<Vector3> &road_lines_nodes)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
rline.indices.clear();
|
|
||||||
for (i = 0; i < (int)rline.points.size(); i++) {
|
|
||||||
Vector3 pt = rline.points[i].origin;
|
|
||||||
int pt_hash = road_lines_hash(pt);
|
|
||||||
if (road_lines_nodes_hash.find(pt_hash) !=
|
|
||||||
road_lines_nodes_hash.end()) {
|
|
||||||
bool ok = true;
|
|
||||||
for (j = 0;
|
|
||||||
j <
|
|
||||||
(int)road_lines_nodes_hash[pt_hash].size();
|
|
||||||
j++) {
|
|
||||||
const Vector3 &xpt =
|
|
||||||
road_lines_nodes_hash[pt_hash]
|
|
||||||
[j];
|
|
||||||
if (xpt.distance_squared_to(pt) < 160) {
|
|
||||||
ok = false;
|
|
||||||
pt = xpt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ok) {
|
|
||||||
road_lines_nodes_hash[pt_hash].push_back(
|
|
||||||
pt);
|
|
||||||
road_lines_nodes.push_back(pt);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
road_lines_nodes.push_back(pt);
|
|
||||||
road_lines_nodes_hash[pt_hash] = { pt };
|
|
||||||
}
|
|
||||||
std::vector<Vector3>::iterator it =
|
|
||||||
std::find(road_lines_nodes.begin(),
|
|
||||||
road_lines_nodes.end(), pt);
|
|
||||||
assert(it != road_lines_nodes.end());
|
|
||||||
int index = it - road_lines_nodes.begin();
|
|
||||||
rline.indices.push_back(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void index_lines(std::unordered_map<uint32_t, std::vector<Vector3> >
|
|
||||||
&road_lines_nodes_hash,
|
|
||||||
std::vector<Vector3> &road_lines_nodes)
|
|
||||||
{
|
|
||||||
List<String> keys;
|
|
||||||
road_lines.get_key_list(&keys);
|
|
||||||
List<String>::Element *e = keys.front();
|
|
||||||
while (e) {
|
|
||||||
String rkey = e->get();
|
|
||||||
struct road_line &pt = road_lines[rkey];
|
|
||||||
pt.indices.clear();
|
|
||||||
e = e->next();
|
|
||||||
}
|
|
||||||
e = keys.front();
|
|
||||||
while (e) {
|
|
||||||
String rkey = e->get();
|
|
||||||
struct road_line &pt = road_lines[rkey];
|
|
||||||
road_lines_curve_index(pt, road_lines_nodes_hash,
|
|
||||||
road_lines_nodes);
|
|
||||||
e = e->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* add close points on each line to the line */
|
|
||||||
void insert_close_points(std::vector<Vector3> &road_lines_nodes)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
List<String> keys;
|
|
||||||
road_lines.get_key_list(&keys);
|
|
||||||
List<String>::Element *e = keys.front();
|
|
||||||
for (i = 0; i < (int)road_lines_nodes.size(); i++) {
|
|
||||||
int idx3 = i;
|
|
||||||
while (e) {
|
|
||||||
int j;
|
|
||||||
std::vector<int> segments;
|
|
||||||
String rkey = e->get();
|
|
||||||
create_segments(rkey, segments);
|
|
||||||
for (j = 0; j < (int)segments.size(); j += 3) {
|
|
||||||
int idx1 = segments[j];
|
|
||||||
int idx2 = segments[j + 1];
|
|
||||||
int idx = segments[j + 2];
|
|
||||||
/* Skip segment point */
|
|
||||||
if (idx3 == idx1 || idx3 == idx2)
|
|
||||||
continue;
|
|
||||||
Vector3 p1 = road_lines_nodes[idx1];
|
|
||||||
Vector3 p2 = road_lines_nodes[idx2];
|
|
||||||
Vector3 p3 = road_lines_nodes[idx3];
|
|
||||||
std::vector<Vector3> seg = { p1, p2 };
|
|
||||||
Vector3 closest = Geometry::
|
|
||||||
get_closest_point_to_segment(
|
|
||||||
p3, seg.data());
|
|
||||||
if (p3.distance_squared_to(closest) <
|
|
||||||
160) {
|
|
||||||
road_lines_nodes[idx3] =
|
|
||||||
closest;
|
|
||||||
road_lines[rkey].indices.insert(
|
|
||||||
road_lines[rkey].indices
|
|
||||||
.begin() +
|
|
||||||
idx,
|
|
||||||
idx3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e = e->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void update_road_lines_nodes(std::vector<Vector3> &road_lines_nodes)
|
|
||||||
{
|
|
||||||
List<String> keys;
|
|
||||||
|
|
||||||
road_lines.get_key_list(&keys);
|
|
||||||
std::unordered_map<uint32_t, std::tuple<String, String> > kcmp;
|
|
||||||
{
|
|
||||||
List<String>::Element *k = keys.front();
|
|
||||||
List<String>::Element *r = keys.front();
|
|
||||||
while (k) {
|
|
||||||
String kkey = k->get();
|
|
||||||
uint32_t kkey_hash = kkey.hash();
|
|
||||||
while (r) {
|
|
||||||
String rkey = r->get();
|
|
||||||
uint32_t rkey_hash = rkey.hash();
|
|
||||||
uint32_t key = kkey_hash ^ rkey_hash;
|
|
||||||
uint32_t key2 = rkey_hash ^ kkey_hash;
|
|
||||||
if (kcmp.find(key) == kcmp.end() &&
|
|
||||||
kcmp.find(key2) == kcmp.end())
|
|
||||||
kcmp[key] = std::make_tuple(
|
|
||||||
k->get(), r->get());
|
|
||||||
r = r->next();
|
|
||||||
}
|
|
||||||
k = k->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
using checks_tuple =
|
|
||||||
std::tuple<String, int, int, int, String, int, int, int>;
|
|
||||||
std::unordered_map<uint32_t, checks_tuple> checks;
|
|
||||||
std::unordered_map<uint32_t, checks_tuple>::iterator checks_it;
|
|
||||||
std::unordered_map<uint32_t,
|
|
||||||
std::tuple<String, String> >::iterator it;
|
|
||||||
for (it = kcmp.begin(); it != kcmp.end(); it++) {
|
|
||||||
int i, j;
|
|
||||||
std::tuple<String, String> data = kcmp[it->first];
|
|
||||||
const String &k = std::get<0>(data);
|
|
||||||
const String &r = std::get<1>(data);
|
|
||||||
if (road_lines[k].indices.size() < 2)
|
|
||||||
continue;
|
|
||||||
if (road_lines[r].indices.size() < 2)
|
|
||||||
continue;
|
|
||||||
for (i = 0; i < (int)road_lines[k].indices.size() - 1;
|
|
||||||
i++) {
|
|
||||||
for (j = 0;
|
|
||||||
j < (int)road_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 =
|
|
||||||
road_lines[k].indices[i];
|
|
||||||
int idx_a2 =
|
|
||||||
road_lines[k]
|
|
||||||
.indices[i + 1];
|
|
||||||
int idx_b1 =
|
|
||||||
road_lines[k].indices[j];
|
|
||||||
int idx_b2 =
|
|
||||||
road_lines[k]
|
|
||||||
.indices[j + 1];
|
|
||||||
std::vector<int> cmp1 = {
|
|
||||||
idx_a1, idx_a2
|
|
||||||
};
|
|
||||||
if (std::find(cmp1.begin(),
|
|
||||||
cmp1.end(),
|
|
||||||
idx_b1) !=
|
|
||||||
cmp1.end())
|
|
||||||
continue;
|
|
||||||
if (std::find(cmp1.begin(),
|
|
||||||
cmp1.end(),
|
|
||||||
idx_b2) !=
|
|
||||||
cmp1.end())
|
|
||||||
continue;
|
|
||||||
checks[key] = std::make_tuple(
|
|
||||||
k, i, idx_a1, idx_a2, r,
|
|
||||||
j, idx_b1, idx_b2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
for ch in checks.values():
|
|
||||||
var k = ch[0]
|
|
||||||
var i1 = ch[1]
|
|
||||||
var idx_a1 = ch[2]
|
|
||||||
var idx_a2 = ch[3]
|
|
||||||
var r = ch[4]
|
|
||||||
var j1 = ch[5]
|
|
||||||
var idx_b1 = ch[6]
|
|
||||||
var idx_b2 = ch[7]
|
|
||||||
var p_a1 = road_lines_nodes[idx_a1]
|
|
||||||
var p_a2 = road_lines_nodes[idx_a2]
|
|
||||||
var p_b1 = road_lines_nodes[idx_b1]
|
|
||||||
var p_b2 = road_lines_nodes[idx_b2]
|
|
||||||
var px = Geometry.get_closest_points_between_segments(p_a1, p_a2, p_b1, p_b2)
|
|
||||||
var d = px[0].distance_squared_to(px[1])
|
|
||||||
if d < 160:
|
|
||||||
var pxt = px[0].linear_interpolate(px[1], 0.5)
|
|
||||||
var nidx = road_lines_nodes.size()
|
|
||||||
road_lines_nodes.push_back(pxt)
|
|
||||||
var il = road_lines[k].indices.size()
|
|
||||||
assert(!nidx in road_lines[k].indices)
|
|
||||||
assert(!nidx in road_lines[r].indices)
|
|
||||||
road_lines[k].indices.insert(i1 + 1, nidx)
|
|
||||||
road_lines[r].indices.insert(j1 + 1, nidx)
|
|
||||||
##end
|
|
||||||
*/
|
|
||||||
for (checks_it = checks.begin(); checks_it != checks.end();
|
|
||||||
checks_it++) {
|
|
||||||
String k = std::get<0>(checks_it->second);
|
|
||||||
int i = std::get<1>(checks_it->second);
|
|
||||||
int idx_a1 = std::get<2>(checks_it->second);
|
|
||||||
int idx_a2 = std::get<3>(checks_it->second);
|
|
||||||
String r = std::get<4>(checks_it->second);
|
|
||||||
int j = std::get<5>(checks_it->second);
|
|
||||||
int idx_b1 = std::get<6>(checks_it->second);
|
|
||||||
int idx_b2 = std::get<7>(checks_it->second);
|
|
||||||
Vector3 p_a1 = road_lines_nodes[idx_a1];
|
|
||||||
Vector3 p_a2 = road_lines_nodes[idx_a2];
|
|
||||||
Vector3 p_b1 = road_lines_nodes[idx_b1];
|
|
||||||
Vector3 p_b2 = road_lines_nodes[idx_b2];
|
|
||||||
Vector3 px, px2;
|
|
||||||
Geometry::get_closest_points_between_segments(
|
|
||||||
p_a1, p_a2, p_b1, p_b2, px, px2);
|
|
||||||
float d = px.distance_squared_to(px2);
|
|
||||||
if (d < 160) {
|
|
||||||
Vector3 pxt = px.linear_interpolate(px2, 0.5f);
|
|
||||||
int nidx = road_lines_nodes.size();
|
|
||||||
road_lines_nodes.push_back(pxt);
|
|
||||||
// int il = (int)road_lines[k].indices.size();
|
|
||||||
assert(std::find(road_lines[k].indices.begin(),
|
|
||||||
road_lines[k].indices.end(),
|
|
||||||
nidx) ==
|
|
||||||
road_lines[k].indices.end());
|
|
||||||
assert(std::find(road_lines[r].indices.begin(),
|
|
||||||
road_lines[r].indices.end(),
|
|
||||||
nidx) ==
|
|
||||||
road_lines[r].indices.end());
|
|
||||||
road_lines[k].indices.insert(
|
|
||||||
road_lines[k].indices.begin() + i + 1,
|
|
||||||
nidx);
|
|
||||||
road_lines[r].indices.insert(
|
|
||||||
road_lines[k].indices.begin() + j + 1,
|
|
||||||
nidx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void create_nodes(const std::vector<Vector3> &road_lines_nodes)
|
void create_nodes(const std::vector<Vector3> &road_lines_nodes)
|
||||||
{
|
{
|
||||||
nodes.resize(road_lines_nodes.size());
|
nodes.resize(road_lines_nodes.size());
|
||||||
@@ -340,18 +55,19 @@ struct RoadLinesProcessing {
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
List<String> keys;
|
List<String> keys;
|
||||||
road_lines.get_key_list(&keys);
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
|
rld->get_road_lines_key_list(&keys);
|
||||||
List<String>::Element *e = keys.front();
|
List<String>::Element *e = keys.front();
|
||||||
while (e) {
|
while (e) {
|
||||||
const String &key = e->get();
|
const String &key = e->get();
|
||||||
if (road_lines[key].indices.size() < 2) {
|
if (rld->lines[key].indices.size() < 2) {
|
||||||
e = e->next();
|
e = e->next();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (i = 0; i < (int)road_lines[key].indices.size() - 1;
|
for (i = 0; i < (int)rld->lines[key].indices.size() - 1;
|
||||||
i++) {
|
i++) {
|
||||||
int idx1 = road_lines[key].indices[i];
|
int idx1 = rld->lines[key].indices[i];
|
||||||
int idx2 = road_lines[key].indices[i + 1];
|
int idx2 = rld->lines[key].indices[i + 1];
|
||||||
if (edges.find(idx1) == edges.end()) {
|
if (edges.find(idx1) == edges.end()) {
|
||||||
struct edgedata ed;
|
struct edgedata ed;
|
||||||
ed.neighbors.clear();
|
ed.neighbors.clear();
|
||||||
@@ -458,27 +174,6 @@ struct RoadLinesProcessing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void dump_lines(const std::vector<Vector3> &road_lines_nodes)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
List<String> keys;
|
|
||||||
road_lines.get_key_list(&keys);
|
|
||||||
List<String>::Element *e = keys.front();
|
|
||||||
while (e) {
|
|
||||||
String rkey = e->get();
|
|
||||||
struct road_line &pt = road_lines[rkey];
|
|
||||||
String outline = rkey + ": ";
|
|
||||||
for (i = 0; i < (int)pt.indices.size(); i++) {
|
|
||||||
outline += " " + itos(pt.indices[i]);
|
|
||||||
}
|
|
||||||
for (i = 0; i < (int)pt.indices.size(); i++) {
|
|
||||||
outline +=
|
|
||||||
" " + (road_lines_nodes[pt.indices[i]]
|
|
||||||
.operator String());
|
|
||||||
}
|
|
||||||
e = e->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~RoadLinesProcessing()
|
~RoadLinesProcessing()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -489,68 +184,21 @@ struct RoadLinesProcessing {
|
|||||||
singleton = nullptr;
|
singleton = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void road_setup(Node *base);
|
void road_setup(Node *base)
|
||||||
void read_road_lines_json(const String &road_lines_path);
|
|
||||||
};
|
|
||||||
void RoadLinesProcessing::road_setup(Node *base)
|
|
||||||
{
|
{
|
||||||
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
||||||
std::vector<Vector3> road_lines_nodes;
|
std::vector<Vector3> road_lines_nodes;
|
||||||
std::unordered_map<uint32_t, std::vector<Vector3> >
|
std::unordered_map<uint32_t, std::vector<Vector3> >
|
||||||
road_lines_nodes_hash;
|
road_lines_nodes_hash;
|
||||||
road_lines_nodes.clear();
|
road_lines_nodes.clear();
|
||||||
road_lines_nodes_hash.clear();
|
road_lines_nodes_hash.clear();
|
||||||
index_lines(road_lines_nodes_hash, road_lines_nodes);
|
rld->process_lines(road_lines_nodes_hash, road_lines_nodes);
|
||||||
insert_close_points(road_lines_nodes);
|
|
||||||
update_road_lines_nodes(road_lines_nodes);
|
|
||||||
dump_lines(road_lines_nodes);
|
|
||||||
create_nodes(road_lines_nodes);
|
create_nodes(road_lines_nodes);
|
||||||
create_edges();
|
create_edges();
|
||||||
build_wedges(wedges);
|
build_wedges(wedges);
|
||||||
print_line("ROAD SETUP DONE");
|
print_line("ROAD SETUP DONE");
|
||||||
}
|
}
|
||||||
void RoadLinesProcessing::read_road_lines_json(const String &road_lines_path)
|
};
|
||||||
{
|
|
||||||
int i;
|
|
||||||
String road_lines_json =
|
|
||||||
FileAccess::get_file_as_string(road_lines_path);
|
|
||||||
Variant json_v;
|
|
||||||
String es;
|
|
||||||
int eline;
|
|
||||||
Error status = JSON::parse(road_lines_json, json_v, es, eline);
|
|
||||||
ERR_FAIL_COND_MSG(status != OK, "Can't parse json: " + es +
|
|
||||||
" at line: " + itos(eline));
|
|
||||||
|
|
||||||
Dictionary json = json_v;
|
|
||||||
List<Variant> keys;
|
|
||||||
json.get_key_list(&keys);
|
|
||||||
List<Variant>::Element *e = keys.front();
|
|
||||||
while (e) {
|
|
||||||
String key = e->get();
|
|
||||||
if (!key.ends_with("_road")) {
|
|
||||||
e = e->next();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
struct road_line rline;
|
|
||||||
Array points = json[key].get("points");
|
|
||||||
Array indices = json[key].get("indices");
|
|
||||||
int lanes = json[key].get("lanes");
|
|
||||||
rline.points.resize(points.size());
|
|
||||||
rline.indices.resize(indices.size());
|
|
||||||
for (i = 0; i < (int)points.size(); i++) {
|
|
||||||
String point_s = points[i];
|
|
||||||
rline.points[i] = from_string<Transform>(point_s);
|
|
||||||
}
|
|
||||||
for (i = 0; i < (int)indices.size(); i++) {
|
|
||||||
int index = indices[i];
|
|
||||||
rline.indices[i] = index;
|
|
||||||
}
|
|
||||||
// TODO: wtf is flags?
|
|
||||||
rline.lanes = lanes;
|
|
||||||
road_lines[key] = rline;
|
|
||||||
e = e->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RoadLinesProcessing *RoadLinesProcessing::singleton;
|
RoadLinesProcessing *RoadLinesProcessing::singleton;
|
||||||
|
|
||||||
class RoadMeshProcessing {
|
class RoadMeshProcessing {
|
||||||
@@ -571,6 +219,7 @@ class RoadMeshProcessing {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
HashMap<String, struct mesh_data> road_meshes;
|
HashMap<String, struct mesh_data> road_meshes;
|
||||||
|
std::vector<MeshInstance *> nodes_mi;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void load_road_mesh(const String &category, const String &name,
|
void load_road_mesh(const String &category, const String &name,
|
||||||
@@ -936,6 +585,9 @@ public:
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
RoadLinesProcessing *r = RoadLinesProcessing::get_singleton();
|
RoadLinesProcessing *r = RoadLinesProcessing::get_singleton();
|
||||||
|
for (i = 0; i < (int)nodes_mi.size(); i++)
|
||||||
|
nodes_mi[i]->queue_delete();
|
||||||
|
nodes_mi.clear();
|
||||||
for (i = 0; i < (int)r->nodes.size(); i++) {
|
for (i = 0; i < (int)r->nodes.size(); i++) {
|
||||||
Ref<ArrayMesh> mesh =
|
Ref<ArrayMesh> mesh =
|
||||||
build_road(r->wedges[i], "common/center",
|
build_road(r->wedges[i], "common/center",
|
||||||
@@ -947,6 +599,7 @@ public:
|
|||||||
base->call_deferred("add_child", mi);
|
base->call_deferred("add_child", mi);
|
||||||
mi->set_transform(xform);
|
mi->set_transform(xform);
|
||||||
mi->call_deferred("show");
|
mi->call_deferred("show");
|
||||||
|
nodes_mi.push_back(mi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static RoadMeshProcessing *singleton;
|
static RoadMeshProcessing *singleton;
|
||||||
@@ -978,12 +631,11 @@ void RoadProcessing::road_setup(Node *target)
|
|||||||
|
|
||||||
void RoadProcessing::load_data()
|
void RoadProcessing::load_data()
|
||||||
{
|
{
|
||||||
|
/* Not needed but still */
|
||||||
|
RoadLinesData::get_singleton();
|
||||||
ConfigFile config;
|
ConfigFile config;
|
||||||
Error result = config.load("res://config/stream.conf");
|
Error result = config.load("res://config/stream.conf");
|
||||||
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
||||||
String road_lines_path = config.get_value("lines", "road_lines_path");
|
|
||||||
RoadLinesProcessing::get_singleton()->read_road_lines_json(
|
|
||||||
road_lines_path);
|
|
||||||
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
||||||
"common", "center", config.get_value("road", "center_mesh"));
|
"common", "center", config.get_value("road", "center_mesh"));
|
||||||
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
||||||
|
|||||||
@@ -554,6 +554,14 @@ void StreamWorld::run_command(const String &command, const Array &args)
|
|||||||
} else if (command == "remove_generated_stuff") {
|
} else if (command == "remove_generated_stuff") {
|
||||||
remove_generated_stuff();
|
remove_generated_stuff();
|
||||||
update_items();
|
update_items();
|
||||||
|
} else if (command == "place") {
|
||||||
|
if (args.size() == 0) {
|
||||||
|
print_error("bad command: not enough args: " + command);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String what = args[0];
|
||||||
|
if (what == "zebra")
|
||||||
|
place_zebras();
|
||||||
} else
|
} else
|
||||||
print_error("No command " + command);
|
print_error("No command " + command);
|
||||||
}
|
}
|
||||||
@@ -695,6 +703,9 @@ void StreamWorld::undo()
|
|||||||
update_view();
|
update_view();
|
||||||
update_items();
|
update_items();
|
||||||
}
|
}
|
||||||
|
void StreamWorld::place_zebras()
|
||||||
|
{
|
||||||
|
}
|
||||||
void StreamWorld::cleanup()
|
void StreamWorld::cleanup()
|
||||||
{
|
{
|
||||||
RoadProcessing::cleanup();
|
RoadProcessing::cleanup();
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ private:
|
|||||||
void remove_building(int index);
|
void remove_building(int index);
|
||||||
void checkpoint();
|
void checkpoint();
|
||||||
void undo();
|
void undo();
|
||||||
|
void place_zebras();
|
||||||
|
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user