From 2afa4feee8a9f82888f8c595f929c7749922a42a Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Mon, 3 Mar 2025 10:00:13 +0300 Subject: [PATCH] Updated generation of lots --- godot/astream/road_lines.json | 138 +++---- godot/config/stream.conf | 1 + src/modules/stream/contours.cpp | 30 ++ src/modules/stream/contours.h | 15 + src/modules/stream/road_lines_data.cpp | 98 +++-- src/modules/stream/road_lines_data.h | 16 +- src/modules/stream/road_lines_editor.cpp | 126 ++++-- src/modules/stream/road_processing.cpp | 485 +++++++++++++++++------ 8 files changed, 622 insertions(+), 287 deletions(-) create mode 100644 src/modules/stream/contours.cpp create mode 100644 src/modules/stream/contours.h diff --git a/godot/astream/road_lines.json b/godot/astream/road_lines.json index 4f6e365..f412157 100644 --- a/godot/astream/road_lines.json +++ b/godot/astream/road_lines.json @@ -3327,14 +3327,14 @@ "sideroad_dir_offset": 0, "sideroad_y_offset": 0, "sideroad_y_rotation": 0, - "sideroad_type": "Null", + "sideroad_type": "", "lot": 1, "lot_depth": 46, "lot_offset": 0, "lot_dir_offset": 0, "lot_y_offset": 0, "lot_y_rotation": 0, - "lot_type": "Null", + "lot_type": "", "lot_buildings": ":0, 0, 0:0" }, "right": { @@ -3348,14 +3348,14 @@ "sideroad_dir_offset": 0, "sideroad_y_offset": 0, "sideroad_y_rotation": 0, - "sideroad_type": "Null", - "lot": 0, + "sideroad_type": "", + "lot": 1, "lot_depth": 9.663863, "lot_offset": 0, "lot_dir_offset": 0, "lot_y_offset": 0, "lot_y_rotation": 0, - "lot_type": "Null", + "lot_type": "", "lot_buildings": ":0, 0, 0:0" } }, @@ -3371,14 +3371,14 @@ "sideroad_dir_offset": 0, "sideroad_y_offset": 0, "sideroad_y_rotation": 0, - "sideroad_type": "Null", + "sideroad_type": "", "lot": 1, "lot_depth": 52.253078, "lot_offset": 0, "lot_dir_offset": 0, "lot_y_offset": 0, "lot_y_rotation": 0, - "lot_type": "Null", + "lot_type": "", "lot_buildings": ":0, 0, 0:0" }, "right": { @@ -3392,14 +3392,14 @@ "sideroad_dir_offset": 0, "sideroad_y_offset": 0, "sideroad_y_rotation": 0, - "sideroad_type": "Null", - "lot": 0, + "sideroad_type": "", + "lot": 1, "lot_depth": 86.428551, "lot_offset": 0, "lot_dir_offset": 0, "lot_y_offset": 0, "lot_y_rotation": 0, - "lot_type": "Null", + "lot_type": "", "lot_buildings": ":0, 0, 0:0" } } @@ -4373,7 +4373,7 @@ "sideroad_y_rotation": 0, "sideroad_type": "Null", "lot": 1, - "lot_depth": 58.483521, + "lot_depth": 58.498596, "lot_offset": 0, "lot_dir_offset": 0, "lot_y_offset": 0, @@ -4737,9 +4737,9 @@ "points": [ "Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -740, 0.036499, -560 )", "Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -735, 0.0276184, -595 )", - "Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -715, 0.0155029, -750 )", - "Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -710, 0.0388794, -800 )", - "Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -670, 0.0308838, -800 )", + "Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -728, 0.000350952, -752 )", + "Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -712, 0.000152588, -790 )", + "Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -670, 0.000167847, -804 )", "Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -445, 0.0236511, -805 )", "Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -320, 0.0359802, -805 )" ], @@ -4778,8 +4778,8 @@ "sideroad_y_offset": 0, "sideroad_y_rotation": 0, "sideroad_type": "Null", - "lot": 0, - "lot_depth": 74.268272, + "lot": 1, + "lot_depth": 73.84967, "lot_offset": 0, "lot_dir_offset": 0, "lot_y_offset": 0, @@ -4822,8 +4822,8 @@ "sideroad_y_offset": 0, "sideroad_y_rotation": 0, "sideroad_type": "Null", - "lot": 0, - "lot_depth": 80.475876, + "lot": 1, + "lot_depth": 100, "lot_offset": 0, "lot_dir_offset": 0, "lot_y_offset": 0, @@ -4866,8 +4866,8 @@ "sideroad_y_offset": 0, "sideroad_y_rotation": 0, "sideroad_type": "Null", - "lot": 0, - "lot_depth": 17.667665, + "lot": 1, + "lot_depth": 40.091198, "lot_offset": 0, "lot_dir_offset": 0, "lot_y_offset": 0, @@ -4899,29 +4899,6 @@ "lot_buildings": ":0, 0, 0:0" }, "right": { - "transit_stop_count": 0, - "transit_stop_type": "", - "transit_stop_offset": 0, - "transit_stop_dir_offset": 0, - "transit_stop_y_rotation": 0, - "sideroad": 0, - "sideroad_offset": 0, - "sideroad_dir_offset": 0, - "sideroad_y_offset": 0, - "sideroad_y_rotation": 0, - "sideroad_type": "Null", - "lot": 0, - "lot_depth": 20.278347, - "lot_offset": 0, - "lot_dir_offset": 0, - "lot_y_offset": 0, - "lot_y_rotation": 0, - "lot_type": "Null", - "lot_buildings": ":0, 0, 0:0" - } - }, - { - "left": { "transit_stop_count": 0, "transit_stop_type": "", "transit_stop_offset": 0, @@ -4934,28 +4911,7 @@ "sideroad_y_rotation": 0, "sideroad_type": "Null", "lot": 1, - "lot_depth": 38.619808, - "lot_offset": 0, - "lot_dir_offset": 0, - "lot_y_offset": 0, - "lot_y_rotation": 0, - "lot_type": "Null", - "lot_buildings": ":0, 0, 0:0" - }, - "right": { - "transit_stop_count": 0, - "transit_stop_type": "", - "transit_stop_offset": 0, - "transit_stop_dir_offset": 0, - "transit_stop_y_rotation": 0, - "sideroad": 0, - "sideroad_offset": 0, - "sideroad_dir_offset": 0, - "sideroad_y_offset": 0, - "sideroad_y_rotation": 0, - "sideroad_type": "Null", - "lot": 0, - "lot_depth": 74.593224, + "lot_depth": 49.743282, "lot_offset": 0, "lot_dir_offset": 0, "lot_y_offset": 0, @@ -4998,7 +4954,51 @@ "sideroad_y_offset": 0, "sideroad_y_rotation": 0, "sideroad_type": "Null", - "lot": 0, + "lot": 1, + "lot_depth": 61.328331, + "lot_offset": 0, + "lot_dir_offset": 0, + "lot_y_offset": 0, + "lot_y_rotation": 0, + "lot_type": "Null", + "lot_buildings": ":0, 0, 0:0" + } + }, + { + "left": { + "transit_stop_count": 0, + "transit_stop_type": "", + "transit_stop_offset": 0, + "transit_stop_dir_offset": 0, + "transit_stop_y_rotation": 0, + "sideroad": 0, + "sideroad_offset": 0, + "sideroad_dir_offset": 0, + "sideroad_y_offset": 0, + "sideroad_y_rotation": 0, + "sideroad_type": "Null", + "lot": 1, + "lot_depth": 100, + "lot_offset": 0, + "lot_dir_offset": 0, + "lot_y_offset": 0, + "lot_y_rotation": 0, + "lot_type": "Null", + "lot_buildings": ":0, 0, 0:0" + }, + "right": { + "transit_stop_count": 0, + "transit_stop_type": "", + "transit_stop_offset": 0, + "transit_stop_dir_offset": 0, + "transit_stop_y_rotation": 0, + "sideroad": 0, + "sideroad_offset": 0, + "sideroad_dir_offset": 0, + "sideroad_y_offset": 0, + "sideroad_y_rotation": 0, + "sideroad_type": "Null", + "lot": 1, "lot_depth": 12.020815, "lot_offset": 0, "lot_dir_offset": 0, @@ -7407,7 +7407,7 @@ "sideroad_y_offset": 0, "sideroad_y_rotation": 0, "sideroad_type": "Null", - "lot": 0, + "lot": 1, "lot_depth": 100, "lot_offset": 0, "lot_dir_offset": 0, @@ -7451,7 +7451,7 @@ "sideroad_y_offset": 0, "sideroad_y_rotation": 0, "sideroad_type": "Null", - "lot": 0, + "lot": 1, "lot_depth": 100, "lot_offset": 0, "lot_dir_offset": 0, @@ -11413,7 +11413,7 @@ "sideroad_y_rotation": 0, "sideroad_type": "Null", "lot": 0, - "lot_depth": 73.214561, + "lot_depth": 72.343361, "lot_offset": 0, "lot_dir_offset": 0, "lot_y_offset": 0, diff --git a/godot/config/stream.conf b/godot/config/stream.conf index b4be139..fde5773 100644 --- a/godot/config/stream.conf +++ b/godot/config/stream.conf @@ -61,6 +61,7 @@ sidewalk_start_mesh = "res://astream/road/road-lanes_road-sidewalk-start.mesh" sidewalk_end_mesh = "res://astream/road/road-lanes_road-sidewalk-end.mesh" sidewalk_sideroad_mesh = "res://astream/road/road-lanes_road-sidewalk-sideroad.mesh" lot_mesh = "res://astream/road/road-lanes_road-lot.mesh" +lot_depth = 200.0 [lines] road_lines_path = "res://astream/road_lines.json" gen_prefixes = ["empty", "foundation30", "foundation60", "sideroad-start", diff --git a/src/modules/stream/contours.cpp b/src/modules/stream/contours.cpp new file mode 100644 index 0000000..9f37417 --- /dev/null +++ b/src/modules/stream/contours.cpp @@ -0,0 +1,30 @@ +#include +#include "contours.h" + +Contours *Contours::singleton = nullptr; + +Contours *Contours::get_singleton() +{ + if (!singleton) + singleton = memnew(Contours); + return singleton; +} + +Contours::Contours() +{ +} + +Contours::~Contours() +{ +} + +bool Contours::is_in_closed_contour(const struct wedge *w) +{ + int i, j; + bool found = false; + for (i = 0; i < (int)wedge_contours.size(); i++) + for (j = 0; j < (int)wedge_contours[i].size(); j++) + if (wedge_contours[i][j] == w) + return true; + return false; +} \ No newline at end of file diff --git a/src/modules/stream/contours.h b/src/modules/stream/contours.h new file mode 100644 index 0000000..bc439bc --- /dev/null +++ b/src/modules/stream/contours.h @@ -0,0 +1,15 @@ +/* ~/godot-projects/streaming_world/src/modules/stream/contours.h */ +#ifndef CONTOURS_H_ +#define CONTOURS_H_ +#include + +struct Contours { + std::vector > wedge_contours; + static Contours *singleton; + static Contours *get_singleton(); + Contours(); + virtual ~Contours(); + bool is_in_closed_contour(const struct wedge *w); +}; + +#endif // CONTOURS_H_ \ No newline at end of file diff --git a/src/modules/stream/road_lines_data.cpp b/src/modules/stream/road_lines_data.cpp index c25a88c..1b5f614 100644 --- a/src/modules/stream/road_lines_data.cpp +++ b/src/modules/stream/road_lines_data.cpp @@ -23,6 +23,9 @@ struct CLine { struct CLineIndex { struct RoadLinesData::road_line_index index; }; +struct CLineEdges { + std::vector edges; +}; class LinesAccessor; struct CLinesCommon { Node *debug; @@ -97,22 +100,22 @@ public: get_line_edge(const String &key, int edge) const { flecs::entity e = lookup(key); - const struct CLine *cl = e.get(); - return cl->line.edges[edge]; + const struct CLineEdges *cl = e.get(); + return cl->edges[edge]; } void set_line_edge(const String &key, int edge_id, const struct RoadLinesData::road_edge &edge) { flecs::entity e = lookup(key); - struct CLine *cl = e.get_mut(); - cl->line.edges[edge_id] = edge; - e.modified(); + struct CLineEdges *cl = e.get_mut(); + cl->edges[edge_id] = edge; + e.modified(); } inline int get_line_edge_count(const String &key) const { flecs::entity e = lookup(key); - const struct CLine *cl = e.get(); - return cl->line.edges.size(); + const struct CLineEdges *cl = e.get(); + return cl->edges.size(); } void set_line_edge_left(const String &key, int edge_id, @@ -121,11 +124,11 @@ public: // print_line("set_line_edge_left: " + key + " " + itos(edge_id) + // " lot: " + itos(side.lot)); flecs::entity e = lookup(key); - struct CLine *cl = e.get_mut(); - cl->line.edges[edge_id].left = side; - e.modified(); - cl = e.get_mut(); - assert(cl->line.edges[edge_id].left.lot == side.lot); + struct CLineEdges *cl = e.get_mut(); + cl->edges[edge_id].left = side; + e.modified(); + cl = e.get_mut(); + assert(cl->edges[edge_id].left.lot == side.lot); } void set_line_edge_right(const String &key, int edge_id, @@ -134,25 +137,25 @@ public: // print_line("set_line_edge_right: " + key + " " + itos(edge_id) + // " lot: " + itos(side.lot)); flecs::entity e = lookup(key); - struct CLine *cl = e.get_mut(); - cl->line.edges[edge_id].right = side; - e.modified(); - cl = e.get_mut(); - assert(cl->line.edges[edge_id].right.lot == side.lot); + struct CLineEdges *cl = e.get_mut(); + cl->edges[edge_id].right = side; + e.modified(); + cl = e.get_mut(); + assert(cl->edges[edge_id].right.lot == side.lot); } struct RoadLinesData::road_edge_side get_line_edge_left(const String &key, int edge_id) const { flecs::entity e = lookup(key); - const struct CLine *cl = e.get(); - return cl->line.edges[edge_id].left; + const struct CLineEdges *cl = e.get(); + return cl->edges[edge_id].left; } struct RoadLinesData::road_edge_side get_line_edge_right(const String &key, int edge_id) const { flecs::entity e = lookup(key); - const struct CLine *cl = e.get(); - return cl->line.edges[edge_id].right; + const struct CLineEdges *cl = e.get(); + return cl->edges[edge_id].right; } inline struct RoadLinesData::road_line get_line(const String &key) { @@ -184,12 +187,19 @@ public: inline void set_line(const String &key, const struct RoadLinesData::road_line &line) { - flecs::entity e = lookup_create(key); + flecs::entity e; + if (!has(key)) + e = lookup_create(key); + else + e = lookup(key); e.set({ line }); - CLine *cl = e.get_mut(); - if (cl->line.edges.size() != cl->line.points.size() - 1) - cl->line.edges.resize(cl->line.points.size() - 1); + e.emplace(); + CLineEdges *cle = e.get_mut(); + const CLine *cl = e.get(); + if (cle->edges.size() != cl->line.points.size() - 1) + cle->edges.resize(cl->line.points.size() - 1); e.modified(); + e.modified(); } void update_line(const String &key) { @@ -201,17 +211,23 @@ public: { flecs::entity e = lookup(key); struct CLine *cl = e.get_mut(); + struct CLineEdges *cle = e.get_mut(); cl->line.points.insert(cl->line.points.begin() + index, xform); - if (cl->line.edges.size() != cl->line.points.size() - 1) - cl->line.edges.resize(cl->line.points.size() - 1); + if (cle->edges.size() != cl->line.points.size() - 1) + cle->edges.resize(cl->line.points.size() - 1); + e.modified(); + e.modified(); } inline void erase_line_point(const String &key, int index) { flecs::entity e = lookup(key); struct CLine *cl = e.get_mut(); + struct CLineEdges *cle = e.get_mut(); cl->line.points.erase(cl->line.points.begin() + index); - if (cl->line.edges.size() != cl->line.points.size() - 1) - cl->line.edges.resize(cl->line.points.size() - 1); + if (cle->edges.size() != cl->line.points.size() - 1) + cle->edges.resize(cl->line.points.size() - 1); + e.modified(); + e.modified(); } inline void set_line_point_position(const String &key, int index, const Vector3 &position) @@ -416,13 +432,13 @@ RoadLinesData::get_line_ptr(const String &key) const const LinesAccessor *lines = root_e.get(); return lines->get_line_ptr(key); } -RoadLinesData::road_edge RoadLinesData::get_line_edge(const String &key, - int edge) const +const RoadLinesData::road_edge &RoadLinesData::get_line_edge(const String &key, + int edge) const { flecs::entity root_e = BaseData::get_singleton()->get().lookup("lines"); assert(root_e.is_valid()); const LinesAccessor *lines = root_e.get(); - return lines->get_line_ptr(key)->edges[edge]; + return lines->get_line_edge(key, edge); } RoadLinesData::road_edge_side RoadLinesData::get_line_edge_left(const String &key, int edge) const @@ -702,18 +718,19 @@ void RoadLinesData::load_data() int pattern = entry.get("pattern", -1); rline.pattern = pattern; rline.points.resize(points.size()); - rline.edges.resize(edges.size()); for (i = 0; i < (int)points.size(); i++) { String point_s = points[i]; rline.points[i] = from_string(point_s); } - for (i = 0; i < (int)edges.size(); i++) { - const Dictionary &d = edges[i]; - rline.edges[i].from_dict(rline.edges[i], d); - } // TODO: wtf is flags? rline.lanes = lanes; set_line(key, rline); + for (i = 0; i < (int)edges.size(); i++) { + const Dictionary &d = edges[i]; + RoadLinesData::road_edge edge; + edge.from_dict(edge, d); + set_line_edge(key, i, edge); + } RoadLinesData::road_line_index index; line_indices.set_index(key, index); e = e->next(); @@ -747,14 +764,13 @@ void RoadLinesData::save_data() Dictionary pvalues; Array points, edges, indices; points.resize(lines->get_line(e->get()).points.size()); - edges.resize(lines->get_line(e->get()).edges.size()); + edges.resize(lines->get_line_edge_count(e->get())); for (i = 0; i < (int)lines->get_line(e->get()).points.size(); i++) points[i] = to_string(lines->get_line(e->get()).points[i]); - for (i = 0; i < (int)lines->get_line(e->get()).edges.size(); - i++) - edges[i] = lines->get_line(e->get()).edges[i].to_dict(); + for (i = 0; i < (int)lines->get_line_edge_count(e->get()); i++) + edges[i] = lines->get_line_edge(e->get(), i).to_dict(); indices.resize(this->indices(e->get()).indices.size()); for (i = 0; i < (int)this->indices(e->get()).indices.size(); i++) diff --git a/src/modules/stream/road_lines_data.h b/src/modules/stream/road_lines_data.h index 7480f4a..da73347 100644 --- a/src/modules/stream/road_lines_data.h +++ b/src/modules/stream/road_lines_data.h @@ -205,6 +205,7 @@ public: test_p[0] = other.test_p[0]; test_p[1] = other.test_p[1]; lot_depth_eff = other.lot_depth_eff; + lot_points = other.lot_points; return *this; } }; @@ -217,12 +218,10 @@ public: test_edge(const String &key, int index) : line_key(key) , edge_index(index) - , left(RoadLinesData::get_singleton() - ->lines(key) - .edges[index]) - , right(RoadLinesData::get_singleton() - ->lines(key) - .edges[index]) + , left(RoadLinesData::get_singleton()->get_line_edge( + key, index)) + , right(RoadLinesData::get_singleton()->get_line_edge( + key, index)) { update_from_line(); } @@ -328,8 +327,6 @@ public: struct road_line { std::vector points; - std::vector edges; - public: std::vector segments; int lanes; @@ -399,7 +396,8 @@ public: void set_line(const String &key, const struct road_line &line); void update_line(const String &key); const struct road_line *get_line_ptr(const String &key) const; - struct road_edge get_line_edge(const String &key, int edge) const; + const struct road_edge &get_line_edge(const String &key, + int edge) const; struct road_edge_side get_line_edge_left(const String &key, int edge) const; struct road_edge_side get_line_edge_right(const String &key, diff --git a/src/modules/stream/road_lines_editor.cpp b/src/modules/stream/road_lines_editor.cpp index bfdba59..1ca6d42 100644 --- a/src/modules/stream/road_lines_editor.cpp +++ b/src/modules/stream/road_lines_editor.cpp @@ -1020,15 +1020,19 @@ void RoadLinesEditor::event_handler(const String &event, const Dictionary &data = args[1]; print_line("Update for index: " + itos(index)); print_line("Update: " + to_string(data)); - RoadLinesData::road_line rl = rld->get_line(current_line); - if (index < 0 || index >= (int)rl.edges.size()) { + // RoadLinesData::road_line rl = rld->get_line(current_line); + if (index < 0 || + index >= (int)rld->get_line_edge_count(current_line)) { print_error("Invalid index: " + itos(index)); print_error("Edge count: " + - itos((int)rl.edges.size())); + itos((int)rld->get_line_edge_count( + current_line))); return; } - RoadLinesData::road_edge::from_dict(rl.edges[index], data); - rld->set_line(current_line, rl); + RoadLinesData::road_edge edge; + RoadLinesData::road_edge::from_dict(edge, data); + // rld->set_line(current_line, rl); + rld->set_line_edge(current_line, index, edge); rld->update_line_edges(); print_line("Update for index: " + itos(index) + " done"); } @@ -1272,43 +1276,62 @@ class EdgeEditorHandler { rld->get_line(current_line); String pname = get_pname(menu, id); if (pname.begins_with("lot-")) { + RoadLinesData::road_edge_side side = + rld->get_line_edge_left(current_line, + index); float dir_offt = rl.points[index + 1].origin.distance_to( rl.points[index].origin) / 2.0f; - set_lot(rl.edges[index].left, pname, dir_offt); - } else if (pname.begins_with("residental-")) { + set_lot(side, pname, dir_offt); + rld->set_line_edge_left(current_line, index, + side); + } else if (pname.begins_with("residental-") || + pname.begins_with("business-")) { + RoadLinesData::road_edge_side side = + rld->get_line_edge_left(current_line, + index); struct RoadLinesData::road_edge_side::buildings b; b.id = pname; b.offsets = Vector3(); b.y_rotation = 0.0f; - rl.edges[index].left.buildings.push_back(b); - if (rl.edges[index].left.lot > 0) { - String lot_id = - rl.edges[index].left.lot_type; - if (rl.edges[index] - .left.buildings.size() > - 1) { + + side.buildings.push_back(b); + if (side.lot > 0) { + String lot_id = side.lot_type; + if (side.buildings.size() > 1) { const AABB &aabb_lot = BuildingsData::get_singleton() ->building_aabbs ["lot-" + lot_id]; - bool pack_result = pack_buildings( - aabb_lot, - rl.edges[index] - .left.buildings, - 2.0f); + bool pack_result = + pack_buildings( + aabb_lot, + side.buildings, + 2.0f); assert(pack_result); } } + rld->set_line_edge_left(current_line, index, + side); } else if (pname == "clear") { - rl.edges[index].left.lot_type = ""; - rl.edges[index].left.lot = 0; - rl.edges[index].left.buildings.clear(); + RoadLinesData::road_edge_side side = + rld->get_line_edge_left(current_line, + index); + side.lot_type = ""; + side.lot = 0; + side.buildings.clear(); + rld->set_line_edge_left(current_line, index, + side); } else if (pname == "clear-buildings") { - rl.edges[index].right.buildings.clear(); + RoadLinesData::road_edge_side side = + rld->get_line_edge_left(current_line, + index); + side.buildings.clear(); + rld->set_line_edge_left(current_line, index, + side); } rld->set_line(current_line, rl); print_line("line updated: " + current_line); @@ -1327,41 +1350,58 @@ class EdgeEditorHandler { rl.points[index + 1].origin.distance_to( rl.points[index].origin) / 2.0f; - set_lot(rl.edges[index].right, pname, dir_offt); + RoadLinesData::road_edge_side side = + rld->get_line_edge_right(current_line, + index); + set_lot(side, pname, dir_offt); + rld->set_line_edge_right(current_line, index, + side); } else if (pname.begins_with("residental-") || pname.begins_with("business-")) { + RoadLinesData::road_edge_side side = + rld->get_line_edge_right(current_line, + index); struct RoadLinesData::road_edge_side::buildings b; b.id = pname; b.offsets = Vector3(); b.y_rotation = 0.0f; - rl.edges[index].right.buildings.push_back(b); - if (rl.edges[index].right.lot > 0) { - String lot_id = - rl.edges[index].right.lot_type; - if (rl.edges[index] - .right.buildings.size() > - 1) { + side.buildings.push_back(b); + if (side.lot > 0) { + String lot_id = side.lot_type; + if (side.buildings.size() > 1) { const AABB &aabb_lot = BuildingsData::get_singleton() ->building_aabbs ["lot-" + lot_id]; - bool pack_result = pack_buildings( - aabb_lot, - rl.edges[index] - .right.buildings, - 2.0f); + bool pack_result = + pack_buildings( + aabb_lot, + side.buildings, + 2.0f); assert(pack_result); } } + rld->set_line_edge_right(current_line, index, + side); } else if (pname == "clear") { - rl.edges[index].right.lot_type = ""; - rl.edges[index].right.lot = 0; - rl.edges[index].right.buildings.clear(); + RoadLinesData::road_edge_side side = + rld->get_line_edge_right(current_line, + index); + side.lot_type = ""; + side.lot = 0; + side.buildings.clear(); + rld->set_line_edge_right(current_line, index, + side); } else if (pname == "clear-buildings") { - rl.edges[index].right.buildings.clear(); + RoadLinesData::road_edge_side side = + rld->get_line_edge_right(current_line, + index); + side.buildings.clear(); + rld->set_line_edge_right(current_line, index, + side); } rld->set_line(current_line, rl); rld->update_line_edges(); @@ -1387,8 +1427,8 @@ public: assert(index >= 0 && index < (int)rld->lines(current_line).points.size() - 1); assert(index >= 0 && - index < (int)rld->lines(current_line).edges.size()); - data = rld->lines(current_line).edges[index].to_dict(); + index < (int)rld->get_line_edge_count(current_line)); + data = rld->get_line_edge(current_line, index).to_dict(); const Dictionary &left = data["left"], &right = data["right"]; PanelContainer *p = memnew(PanelContainer); top->call_deferred("add_child", p); @@ -1551,7 +1591,7 @@ void RoadLinesEditor::create_edge_editor_ui(Control *top) int index = get_line_index(); if (index < 0) return; - if ((int)rld->lines(current_line).edges.size() < index) + if ((int)rld->get_line_edge_count(current_line) < index) return; print_line("created with index: " + itos(index)); if (edge_editor) diff --git a/src/modules/stream/road_processing.cpp b/src/modules/stream/road_processing.cpp index d234071..13ccb26 100644 --- a/src/modules/stream/road_processing.cpp +++ b/src/modules/stream/road_processing.cpp @@ -21,6 +21,7 @@ #include "road_debug.h" #include "road_lines_data.h" #include "buildings_data.h" +#include "contours.h" #include "road_processing.h" struct side_ref { @@ -39,23 +40,12 @@ struct wedge { class DebugGeo : public ImmediateGeometry { Ref imm_mat; int vertex_count; -#if 0 - RID im; - bool empty; - AABB aabb; -#endif public: DebugGeo() : ImmediateGeometry() , vertex_count(0) { -#if 0 - im = RID_PRIME( - VisualServer::get_singleton()->immediate_create()); - set_base(im); - empty = true; -#endif if (!imm_mat.is_valid()) { imm_mat.instance(); imm_mat->set_flag( @@ -83,49 +73,6 @@ public: print_line("total vertex count: " + itos(vertex_count)); vertex_count = 0; } -#if 0 - - PoolVector get_faces(uint32_t p_usage_flags) const - { - return PoolVector(); - } - AABB get_aabb() const - { - return aabb; - } - void begin_lines() - { - VisualServer::get_singleton()->immediate_begin( - im, VisualServer::PRIMITIVE_LINES, RID()); - } - void end() - { - VisualServer::get_singleton()->immediate_end(im); - } - void set_color(const Color &c) - { - VisualServer::get_singleton()->immediate_color(im, c); - } - void add_vertex(const Vector3 &v) - { - VisualServer::get_singleton()->immediate_vertex(im, v); - if (empty) { - aabb.position = v; - aabb.size = Vector3(); - empty = false; - } else - aabb.expand_to(v); - } - void clear() - { - VisualServer::get_singleton()->immediate_clear(im); - empty = true; - } - ~DebugGeo() - { - VisualServer::get_singleton()->free(im); - } -#endif }; static Ref dbg_mat; @@ -143,9 +90,6 @@ struct RoadLinesProcessing { (std::hash()(key.second) << 8); } }; - std::unordered_map, - const RoadLinesData::road_edge_side *, side_hash> - sides; std::unordered_map, struct side_ref, side_hash> side_refs; std::unordered_map > wedges; @@ -159,9 +103,14 @@ struct RoadLinesProcessing { singleton = memnew(RoadLinesProcessing); return singleton; } + DebugGeo *dbg; + ConfigFile config; RoadLinesProcessing() + : dbg(nullptr) { singleton = this; + Error err = config.load("res://config/stream.conf"); + assert(err == OK); } void create_nodes(const std::vector &road_lines_nodes) @@ -397,7 +346,7 @@ out2:; bool ok = true; while (e) { const String &key = e->get(); - for (i = 0; i < (int)rld->lines(key).edges.size(); + for (i = 0; i < (int)rld->get_line_edge_count(key); i++) { if (key == ignore_key && i == ignore_index) continue; @@ -428,12 +377,12 @@ out2:; List::Element *e = keys.front(); while (e) { const String &key = e->get(); - for (i = 0; i < (int)rld->lines(key).edges.size(); + for (i = 0; i < (int)rld->get_line_edge_count(key); i++) { - assert(rld->lines(key).edges[i].left.pmid[0] == - rld->lines(key).edges[i].right.pmid[0]); - assert(rld->lines(key).edges[i].left.pmid[1] == - rld->lines(key).edges[i].right.pmid[1]); + assert(rld->get_line_edge_left(key, i).pmid[0] == + rld->get_line_edge_right(key, i).pmid[0]); + assert(rld->get_line_edge_left(key, i).pmid[1] == + rld->get_line_edge_right(key, i).pmid[1]); } e = e->next(); } @@ -452,22 +401,30 @@ out2:; RoadLinesData::road_edge_side left = rld->get_line_edge_left(key, i); left.lot = 1; - left.lot_depth = 100.0f; - left.lot_depth_eff = 100.0f; + left.lot_depth = config.get_value( + "road", "lot_depth", 200.0f); + left.lot_depth_eff = config.get_value( + "road", "lot_depth", 200.0f); rld->set_line_edge_left(key, i, left); RoadLinesData::road_edge_side right = rld->get_line_edge_right(key, i); right.lot = 1; - right.lot_depth = 100.0f; - right.lot_depth_eff = 100.0f; - rld->set_line_edge_left(key, i, right); + right.lot_depth = config.get_value( + "road", "lot_depth", 200.0f); + right.lot_depth_eff = config.get_value( + "road", "lot_depth", 200.0f); + rld->set_line_edge_right(key, i, right); } e = e->next(); } } + /* FIXME: need to generate lots from wedges, not lines (because intersections) + and join lots on the same line segment if they are adjacent and of similar depth + and not too narrow */ void update_lot_depths() { - int i, j; +#if 0 + int i, j, k; struct line_check { struct side_ref side; Vector3 normal; @@ -475,19 +432,26 @@ out2:; Vector3 startp; AABB rect; }; + LocalVector check_lines; RoadLinesProcessing *r = RoadLinesProcessing::get_singleton(); if (r->nodes.size() == 0) return; - DebugGeo *dbg = memnew(DebugGeo); if (r->nodes.empty()) goto out_skip_end; // dbg->set_material_override(dbg_mat); - SceneTree::get_singleton()->get_current_scene()->add_child(dbg); + if (!dbg && + VisualServer::get_singleton()->is_render_loop_enabled()) { + dbg = memnew(DebugGeo); + SceneTree::get_singleton() + ->get_current_scene() + ->call_deferred("add_child", dbg); + } print_line("wedges size:" + itos(r->nodes.size())); dbg->clear(); dbg->begin(Mesh::PRIMITIVE_LINES); dbg->set_color(Color(1, 0, 0, 1)); + dbg->set_color(Color(1, 0, 0, 1)); for (i = 0; i < (int)r->nodes.size(); i++) { const std::vector &ws = wedges[i]; int wsize = ws.size(); @@ -511,9 +475,9 @@ out2:; Vector3 n2 = (w.p[1] - w.y[1]).normalized(); Vector3 n3 = (w.p[2] - w.y[2]).normalized(); mside1.lot_depth_eff = - MAX(mside1.lot_depth_eff, 100.0f); + MAX(mside1.lot_depth_eff, 200.0f); mside2.lot_depth_eff = - MAX(mside2.lot_depth_eff, 100.0f); + MAX(mside2.lot_depth_eff, 200.0f); assert(mside1.lot_depth_eff > 0.001); assert(mside2.lot_depth_eff > 0.001); struct line_check lc1, lc2; @@ -543,6 +507,70 @@ out2:; } } assert(check_lines.size() > 0); + for (i = 0; i < (int)check_lines.size(); i++) { + for (j = 0; j < (int)r->nodes.size(); j++) { + const std::vector &ws = wedges[j]; + int wsize = ws.size(); + for (k = 0; k < wsize; k++) { + const struct wedge &w = ws[k]; + Vector3 p0 = check_lines[i].startp; + Vector3 p1 = + p0 + + check_lines[i].normal * + check_lines[i].depth; + Vector3 p2 = w.p[0]; + Vector3 p3 = w.p[1]; + Vector3 s, t; + /* samey segments do not intersect */ + if (p0.is_equal_approx(p2) && + p1.is_equal_approx(p3)) + continue; + if (p0.is_equal_approx(p3) && + p1.is_equal_approx(p2)) + continue; + /* segments which share a point do not intersect */ + if (p0.is_equal_approx(p2)) + continue; + if (p0.is_equal_approx(p3)) + continue; + if (p1.is_equal_approx(p3)) + continue; + if (p1.is_equal_approx(p2)) + continue; + assert(!p0.is_equal_approx(p1) && + !p2.is_equal_approx(p3)); + Geometry::get_closest_points_between_segments( + p0, p1, p2, p3, s, t); + if (s.is_equal_approx(p0)) + continue; + if (s.is_equal_approx(p1)) + continue; + if (t.is_equal_approx(p2)) + continue; + if (t.is_equal_approx(p3)) + continue; + assert(!s.is_equal_approx(p0)); + assert(!s.is_equal_approx(p1)); + assert(!t.is_equal_approx(p2)); + assert(!t.is_equal_approx(p3)); + Vector3 mx(t.x, s.y, t.z); + if (!s.is_equal_approx(mx)) + continue; + if (Math::abs(s.y - t.y) < 5.0f) { + if (s.is_equal_approx(mx)) { + float l1 = + p0.distance_to( + s); + check_lines[i] + .depth = MIN( + check_lines[i] + .depth, + l1); + } + } + } + } + } for (i = 0; i < (int)check_lines.size(); i++) { Vector3 p0 = check_lines[i].startp; Vector3 p1 = p0 + check_lines[i].normal * @@ -645,8 +673,19 @@ out2:; side1.side); mside1.lot_depth_eff = check_lines[i].depth; mside1.lot_depth = mside1.lot_depth_eff; - mside1.lot_points.push_back(p0); - mside1.lot_points.push_back(p1); + int bad_count = 0; + int lot_points = mside1.lot_points.size(); + assert(lot_points == 0 || lot_points == 2); + for (j = 0; j < mside1.lot_points.size(); j++) { + if (!mside1.lot_points[j].is_equal_approx(p0)) + bad_count++; + if (!mside1.lot_points[j].is_equal_approx(p1)) + bad_count++; + } + if (bad_count < 2) { + mside1.lot_points.push_back(p0); + mside1.lot_points.push_back(p1); + } if (side1.side == 0) RoadLinesData::get_singleton() ->set_line_edge_left(side1.line_key, @@ -659,7 +698,116 @@ out2:; mside1); } dbg->end(); + dbg->begin(Mesh::PRIMITIVE_LINES); + dbg->set_color(Color(0, 1, 1, 1)); + { + List line_keys; + List::Element *line_e; + RoadLinesData *rld = RoadLinesData::get_singleton(); + rld->get_road_lines_key_list(&line_keys); + line_e = line_keys.front(); + while (line_e) { + const String &key = line_e->get(); + print_line("line: " + key); + int edges = rld->get_line_edge_count(key); + for (i = 0; i < edges; i++) { + RoadLinesData::road_edge_side left = + rld->get_line_edge_left(key, i); + RoadLinesData::road_edge_side right = + rld->get_line_edge_right(key, + i); + print_line("edge: " + itos(i) + + " left: lot: " + + itos(left.lot)); + print_line("edge: " + itos(i) + + " right: lot: " + + itos(right.lot)); + print_line( + "lot_points: left: " + + itos(left.lot_points.size())); + print_line( + "lot_points: right: " + + itos(right.lot_points.size())); + for (j = 0; + j < (int)left.lot_points.size(); + j++) { + dbg->add_vertex( + left.lot_points[j] + + Vector3(0, 20, 0)); + dbg->add_vertex( + left.lot_points[j] + + Vector3(0, 200, 0)); + } + if (left.lot_points.size() == 6) { + int index[] = { 0, 1, 1, 3, + 3, 5, 5, 4 }; + for (j = 0; j < 8; j++) { + dbg->add_vertex( + left.lot_points + [index[j]] + + Vector3(0, 25, + 0)); + print_line( + itos(j) + ": " + + left.lot_points[index[j]] + . + operator String()); + } + assert(false); + } else if (left.lot_points.size() == + 4) { + int index[] = { 0, 1, 1, 3, + 3, 2, 2, 0 }; + for (j = 0; j < 8; j++) + dbg->add_vertex( + left.lot_points + [index[j]] + + Vector3(0, 25, + 0)); + } + for (j = 0; + j < (int)right.lot_points.size(); + j++) { + dbg->add_vertex( + right.lot_points[j] + + Vector3(0, 20, 0)); + dbg->add_vertex( + right.lot_points[j] + + Vector3(0, 200, 0)); + } + if (right.lot_points.size() == 6) { + dbg->add_vertex( + right.lot_points[0] + + Vector3(0, 25, 0)); + dbg->add_vertex( + right.lot_points[1] + + Vector3(0, 25, 0)); + dbg->add_vertex( + right.lot_points[1] + + Vector3(0, 25, 0)); + dbg->add_vertex( + right.lot_points[3] + + Vector3(0, 25, 0)); + dbg->add_vertex( + right.lot_points[3] + + Vector3(0, 25, 0)); + dbg->add_vertex( + right.lot_points[2] + + Vector3(0, 25, 0)); + dbg->add_vertex( + right.lot_points[2] + + Vector3(0, 25, 0)); + dbg->add_vertex( + right.lot_points[0] + + Vector3(0, 25, 0)); + } + } + line_e = line_e->next(); + } + } + dbg->end(); out_skip_end:; +#endif } void create_structures() { @@ -677,19 +825,21 @@ out_skip_end:; e = e->next(); continue; } - if (rld->lines(key).edges.size() != - rld->lines(key).points.size() - 1) { + if (rld->get_line_edge_count(key) != + (int)rld->lines(key).points.size() - 1) { e = e->next(); continue; } print_line("line: " + key + " edges count: " + - itos((int)rld->lines(key).edges.size())); - for (i = 0; i < (int)rld->lines(key).edges.size(); + itos((int)rld->get_line_edge_count(key))); + for (i = 0; i < (int)rld->get_line_edge_count(key); i++) { const RoadLinesData::road_edge &edge = - rld->lines(key).edges[i]; - const Vector3 &p0 = edge.left.pmid[0]; - const Vector3 &p1 = edge.left.pmid[1]; + rld->get_line_edge(key, i); + const RoadLinesData::road_edge_side side = + rld->get_line_edge_left(key, i); + const Vector3 &p0 = side.pmid[0]; + const Vector3 &p1 = side.pmid[1]; Vector3 dir = (p1 - p0).normalized(); /* lots */ structures_generated += @@ -741,8 +891,6 @@ out_skip_end:; idx2) == edges[idx1].neighbors.end()) { edges[idx1].neighbors.push_back(idx2); - sides[{ idx1, idx2 }] = - &rld->lines(key).edges[i].left; side_refs[{ idx1, idx2 }] = { key, i, 0 }; } @@ -751,8 +899,6 @@ out_skip_end:; idx1) == edges[idx2].neighbors.end()) { edges[idx2].neighbors.push_back(idx1); - sides[{ idx2, idx1 }] = - &rld->lines(key).edges[i].right; side_refs[{ idx2, idx1 }] = { key, i, 1 }; } @@ -833,9 +979,6 @@ out_skip_end:; edges[k].neighbors.end(), n1) == edges[k].neighbors.end()) { edges[k].neighbors.push_back(n1); - assert(sides.find({ n2, n1 }) != - sides.end()); - sides[{ k, n1 }] = sides[{ n2, n1 }]; side_refs[{ k, n1 }] = side_refs[{ n2, n1 }]; } @@ -843,7 +986,6 @@ out_skip_end:; edges[k].neighbors.end(), n2) == edges[k].neighbors.end()) { edges[k].neighbors.push_back(n2); - sides[{ k, n2 }] = sides[{ n1, n2 }]; side_refs[{ k, n2 }] = side_refs[{ n1, n2 }]; } @@ -851,7 +993,6 @@ out_skip_end:; edges[n1].neighbors.end(), k) == edges[n1].neighbors.end()) { edges[n1].neighbors.push_back(k); - sides[{ n1, k }] = sides[{ n1, n2 }]; side_refs[{ n1, k }] = side_refs[{ n1, n2 }]; } @@ -859,7 +1000,6 @@ out_skip_end:; edges[n2].neighbors.end(), k) == edges[n2].neighbors.end()) { edges[n2].neighbors.push_back(k); - sides[{ n2, k }] = sides[{ n2, n1 }]; side_refs[{ n2, k }] = side_refs[{ n2, n1 }]; } @@ -1004,6 +1144,108 @@ out_skip_end:; } } } + void find_closed_contours() + { + int i, j; + Contours *contours = Contours::get_singleton(); + RoadLinesProcessing *r = RoadLinesProcessing::get_singleton(); + if (r->nodes.size() == 0) + return; + struct wedge_data { + int node; + int neighbor_num; + }; + std::vector wedges_flat; + std::vector > wedges_ref; + for (i = 0; i < (int)r->nodes.size(); i++) { + const std::vector &ws = wedges[i]; + for (j = 0; j < (int)ws.size(); j++) { + wedges_flat.push_back(&ws[j]); + wedges_ref.push_back({ i, j }); + } + } + std::vector used; + int contour_count = 0; + int base = 0; + while (true) { + std::vector contour; + bool finished = false; + std::pair &wref0 = wedges_ref[base]; + struct wedge *wbase = + &wedges[wref0.first] + [wref0.second]; /* previous point */ + if (contour.empty()) + contour.push_back(base); + while (true) { + int added = 0; + for (j = 0; j < (int)wedges_ref.size(); j++) { + if (j == base) + continue; + if (std::find(used.begin(), used.end(), + j) != used.end()) + continue; + std::pair &wref_prev = + wedges_ref[contour.back()]; + std::pair &wref = + wedges_ref[j]; + struct wedge *wprev = + &wedges[wref_prev.first] + [wref_prev.second]; /* previous point */ + struct wedge *wcurrent = + &wedges[wref.first] + [wref.second]; /* current point */ + if (wprev->p[2].is_equal_approx( + wcurrent->p[0])) { + contour.push_back(j); + added++; + if (wbase->p[0].is_equal_approx( + wcurrent->p[2])) { + finished = true; + break; + } + } + } + if (finished) + break; + if (added == 0) + break; + } + if (finished) { + int k; + print_line("complete contour"); + std::vector wedge_contour; + Vector polygon; + for (k = 0; k < (int)contour.size(); k++) { + std::pair &wr = + wedges_ref[contour[k]]; + wedge_contour.push_back( + &wedges[wr.first][wr.second]); + print_line(itos(k) + ": " + + itos(contour[k])); + Vector3 p1 = + wedges[wr.first][wr.second].p[0]; + Vector3 p2 = + wedges[wr.first][wr.second].p[1]; + Vector3 p3 = + wedges[wr.first][wr.second].p[2]; + polygon.push_back(Vector2(p1.x, p1.z)); + polygon.push_back(Vector2(p2.x, p2.z)); + polygon.push_back(Vector2(p3.x, p3.z)); + used.push_back(contour[k]); + } + if (Geometry::is_polygon_clockwise(polygon)) + contours->get_singleton() + ->wedge_contours.push_back( + wedge_contour); + contour.clear(); + contour_count++; + } else + contour.clear(); + base++; + if (base >= (int)wedges_ref.size()) + break; + } + } ~RoadLinesProcessing() { } @@ -1042,7 +1284,8 @@ out_skip_end:; sort_neighbors(); wedges.clear(); build_wedges(wedges); - update_lot_depths(); + find_closed_contours(); + // update_lot_depths(); ImmediateGeometry *d = rld->get_debug_node(); d->clear(); if (debug_flags & 1) { @@ -1269,7 +1512,6 @@ public: out_arrays[ArrayMesh::ARRAY_INDEX]; out_index_orig.append_array(out_index); out_arrays[ArrayMesh::ARRAY_INDEX] = out_index_orig; - // out_arrays[ArrayMesh::ARRAY_INDEX] = indices; } void init_surface(Array &surface) @@ -1363,12 +1605,6 @@ public: lane.use_mesh = use_mesh; assert(use_mesh.length() > 0); assert(lane.use_mesh.length() > 0); -#if 0 - lane.xform1 = Transform(Basis(), lane.p[0]); - lane.xform_m1 = Transform(Basis(), lane.p[1]); - lane.xform_m2 = Transform(Basis(), lane.p[1]); - lane.xform2 = Transform(Basis(), lane.p[2]); -#endif Transform xform1 = Transform().looking_at(params.dir1, Vector3(0, 1, 0)); xform1.origin = lane.p[0]; @@ -1563,10 +1799,6 @@ public: wedge.side2_ref.side); print_line("m1: " + String::num(mside1.lot_depth_eff)); print_line("m2: " + String::num(mside2.lot_depth_eff)); - // mside1.lot_depth_eff = 100.0f; - // mside2.lot_depth_eff = 100.0f; - // assert(mside1.lot_depth_eff >= 0.98f); - // assert(mside2.lot_depth_eff >= 0.98f); /* for each lane */ for (k = 0; k < (int)lanes.size(); k++) { std::vector surfaces; @@ -1682,17 +1914,19 @@ public: out_surfaces[h], 0.0f); } else if (k == params.nlanes + 1 && mside1.lot > 0) { /* lot */ - // assert(mside1.lot_depth_eff >= 0.98f); - build_split_segment( - lanes[k].xform1, - lanes[k].xform_m1, - mside1.lot_depth_eff, - MIN(mside1.lot_depth_eff, - mside2.lot_depth_eff), // mside1.lot_depth_eff, - // get_lot_depth(wedge), - surfaces[h], out_surfaces[h], - 0.0f, - get_split_level(wedge) + 1); + if (!Contours::get_singleton() + ->is_in_closed_contour( + &wedge)) + build_split_segment( + lanes[k].xform1, + lanes[k].xform_m1, + mside1.lot_depth_eff, + MIN(mside1.lot_depth_eff, + mside2.lot_depth_eff), + surfaces[h], + out_surfaces[h], 0.0f, + get_split_level(wedge) + + 1); } else if (k <= params.nlanes) /* normal lane */ build_segment(lanes[k].xform1, @@ -1759,14 +1993,17 @@ public: "m2: " + String::num( mside2.lot_depth_eff)); - // assert(mside2.lot_depth_eff >= 0.98f); - build_split_segment( - lanes[k].xform_m2, - lanes[k].xform2, 100.0f, - 100.0f, // get_lot_depth(wedge), - // mside2.lot_depth_eff, - surfaces[h], out_surfaces[h], - 0.0f, get_split_level(wedge)); + if (!Contours::get_singleton() + ->is_in_closed_contour( + &wedge)) + build_split_segment( + lanes[k].xform_m2, + lanes[k].xform2, + get_lot_depth(wedge), + mside2.lot_depth_eff, + surfaces[h], + out_surfaces[h], 0.0f, + get_split_level(wedge)); } else if (k <= params.nlanes) /* normal lane */ build_segment(lanes[k].xform_m2, lanes[k].xform2, @@ -1788,8 +2025,6 @@ public: int surf_count = road_meshes[center].arrays.size(); out_surfaces.resize(surf_count); out_materials.resize(surf_count); - // Transform mesh_xform = - // Transform().rotated(Vector3(0, 1, 0), Math_PI); for (i = 0; i < (int)wedges.size(); i++) { build_wedge_mesh(wedges[i], center, mid, edge, lot, out_surfaces, out_materials);