Worked on buildings in lines
This commit is contained in:
@@ -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