#include #include #include #include #include #include #include #include #include #include #include "road_grid.h" RoadGrid::RoadGrid() { grid_width = 16; grid_height = 16; } RoadGrid::~RoadGrid() { } /* TODO: constants, configuration */ Dictionary RoadDiagram::build_diagram(Ref rnd, int npatches, int center_count, int center_step, int spread, int dim) { printf("build_diagram %d %d %d %d %d\n", npatches, center_count, center_step, spread, dim); Vector centers; /* zero is always used */ centers.push_back(Vector2i(0, 0)); float sa = rnd->randf() * 2.0 * Math_PI; int i, bad = 0, cx, cp; while (centers.size() < center_count) { int center_x = center_step * (int)((rnd->randi() % spread) - spread / 2); int center_y = center_step * (int)((rnd->randi() % spread) - spread / 2); center_x = CLAMP(center_x, -dim, dim); center_y = CLAMP(center_y, -dim, dim); Vector2i c(center_x, center_y); if (centers.find(c) < 0) { centers.push_back(c); bad = 0; } else bad++; if (bad > 1000) break; } assert(centers.size() > 1); Vector points; for (cx = 0; cx < centers.size(); cx++) { float maxr = 0.0f; for (cp = 0; cp < npatches * 8; cp++) { float a = sa + sqrtf((float)cp) * 8.0f; float r = (cp == 0) ? 0.0f : 100.0f + (float)cp * 100.0f + 50.0f * rnd->randf(); float x = floor(cosf(a) * r + (float)centers[cx].x); float y = floor(sinf(a) * r + (float)centers[cx].y); if (maxr < r) maxr = r; Vector2 p(x, y); if (points.find(p) < 0) points.push_back(p); } struct cluster cst; cst.c = centers[cx]; cst.r = maxr + 50.0f; clusters.push_back(cst); } PoolVector cpoints; cpoints.resize(points.size()); memcpy(cpoints.write().ptr(), points.ptr(), points.size() * sizeof(Vector2)); Dictionary diagram = Voronoi::get_singleton()->generate_diagram(cpoints, 11); return diagram; } const List &RoadDiagram::get_clusters() const { return clusters; } const Vector &RoadDiagram::get_map_sites() const { return map_sites; } const Vector &RoadDiagram::get_diagram_vertices() const { return diagram_vertices; } const Vector &RoadDiagram::get_map_hedges() const { return map_hedges; } bool RoadGrid::segment_intersects_rect(const Vector2 &a, const Vector2 &b, const Rect2 &rect) { real_t min = 0, max = 1; const Vector2 &p_from = a; const Vector2 &p_to = b; for (int i = 0; i < 2; i++) { real_t seg_from = p_from[i]; real_t seg_to = p_to[i]; real_t box_begin = rect.position[i]; real_t box_end = box_begin + rect.size[i]; real_t cmin, cmax; if (seg_from < seg_to) { if (seg_from > box_end || seg_to < box_begin) { return false; } real_t length = seg_to - seg_from; cmin = (seg_from < box_begin) ? ((box_begin - seg_from) / length) : 0; cmax = (seg_to > box_end) ? ((box_end - seg_from) / length) : 1; } else { if (seg_to > box_end || seg_from < box_begin) { return false; } real_t length = seg_to - seg_from; cmin = (seg_from > box_end) ? (box_end - seg_from) / length : 0; cmax = (seg_to < box_begin) ? (box_begin - seg_from) / length : 1; } if (cmin > min) { min = cmin; } if (cmax < max) { max = cmax; } if (max < min) { return false; } } return true; } /* This is heavy when rendered on top of 3D viewport! */ void RoadGrid::draw_debug(Node *drawable, int size_x, int size_y) const { int i, j, k; CanvasItem *ci = Object::cast_to(drawable); if (!ci) return; if (bounds.size.x <= 0.0f || bounds.size.y <= 0.0f) { printf("zero bounds %f %f\n", bounds.size.x, bounds.size.y); return; } for (i = 0; i < map_sites.size(); i++) { Vector2 a = (map_sites[i].pos - bounds.position) * Vector2(size_x, size_y) / bounds.size; ci->draw_circle(a, 4.0f, Color(0.0f, 0.5f, 0.5f, 1.0f)); } for (i = 0; i < map_hedges.size(); i++) { Vector2 xa = diagram_vertices[map_hedges[i]->a]; Vector2 xb = diagram_vertices[map_hedges[i]->b]; Vector2 a = (xa - bounds.position) * Vector2(size_x, size_y) / bounds.size; Vector2 b = (xb - bounds.position) * Vector2(size_x, size_y) / bounds.size; ci->draw_line(a, b, Color(0.0f, 0.7f, 0.7f, 1.0f), 3.0f, true); } Rect2i g = rect_to_grid(bounds); for (i = g.position.y - 1; i < g.position.y + g.size.y + 1; i++) { for (j = g.position.x - 1; j < g.position.x + g.size.x + 1; j++) { if (hedge_grid.has(j, i)) { const Vector &items = hedge_grid.get(j, i); for (k = 0; k < items.size(); k++) { struct half_edge *he = items[k]; assert(he->a >= 0); assert(he->b >= 0); assert(he->a != he->b); assert(he->site >= 0); Vector2 xa = diagram_vertices[he->a]; Vector2 xb = diagram_vertices[he->b]; const struct map_site *site = &map_sites[he->site]; Vector2 pos = (site->pos - bounds.position) * Vector2(size_x, size_y) / bounds.size; ci->draw_circle(pos, 3.0f, Color(0.2f, 0.2f, 0.5f, 1.0f)); Vector2 a = (xa - bounds.position) * Vector2(size_x, size_y) / bounds.size; Vector2 b = (xb - bounds.position) * Vector2(size_x, size_y) / bounds.size; ci->draw_line(a, b, Color(0.2f, 0.2f, 0.7f, 1.0f), 2.0f, true); } } } } } void RoadDiagram::index_site(struct map_site *site) { int i; site->vertices_ind.resize(site->vertices.size()); site->polygon_ind.resize(site->polygon.size()); /* slow as fuck */ for (i = 0; i < site->vertices.size(); i++) { Vector2 v = site->vertices[i].snapped(Vector2(2.0f, 2.0f)); int idx = diagram_vertices.find(v); if (idx < 0) { idx = diagram_vertices.size(); diagram_vertices.push_back(v); } site->vertices_ind.write[i] = idx; } for (i = 0; i < site->polygon.size(); i++) { Vector2 v = site->polygon[i].snapped(Vector2(2.0f, 2.0f)); int idx = diagram_vertices.find(v); if (idx < 0) { idx = diagram_vertices.size(); diagram_vertices.push_back(v); } site->polygon_ind.write[i] = idx; site->rect.expand_to(Vector2i((int)v.x, (int)v.y)); } site->rect.grow(1); site->hedges.resize(site->polygon.size()); int count = 0; for (i = 0; i < site->polygon.size(); i++) { int idx1 = site->polygon_ind[i]; int idx2 = site->polygon_ind[(i + 1) % site->polygon.size()]; if (idx1 == idx2) continue; struct half_edge he; he.a = idx1; he.b = idx2; he.site = site->index; /* use length to decide */ he.length = diagram_vertices[idx1].distance_to(diagram_vertices[idx2]); if (he.length < 50.0f) he.depth = 3.0f; else if (he.length < 100.0f) he.depth = 6.0f; else if (he.length < 200.0f) he.depth = 12.0f; else he.depth = 24.0f; site->hedges.write[count++] = he; } site->hedges.resize(count); } void RoadDiagram::process_diagram(const Dictionary &diagram) { const Array &sites = diagram["sites"]; int i, j; map_sites.resize(sites.size()); int hedge_count = 0, hedge_idx; printf("start processing sites\n"); for (i = 0; i < sites.size(); i++) { struct map_site site; /* We use Dictionary to build native structure only once, * then we use native data. */ const Dictionary &site_data = sites[i]; const Array &graphedges = site_data["graphedges"]; printf("processing site: %d\n", i); site.graphedges.resize(graphedges.size()); for (j = 0; j < graphedges.size(); j++) { const Dictionary &ge_data = graphedges[j]; struct graphedge ge; ge.a = ge_data["a"]; ge.b = ge_data["b"]; ge.edge = ge_data["edge"]; site.graphedges.write[j] = ge; } site.index = i; site.diagram_index = site_data["index"]; site.pos = site_data["pos"]; site.polygon = site_data["polygon"]; site.vertices = site_data["vertices"]; site.site_type = map_site::SITE_UNASSIGNED; site.cluster = -1; index_site(&site); hedge_count += site.hedges.size(); map_sites.write[i] = site; } printf("processing sites done\n"); /* Fill global half edges array and put in grid */ printf("processing %d half edges\n", hedge_count); map_hedges.resize(hedge_count); hedge_idx = 0; for (i = 0; i < map_sites.size(); i++) { for (j = 0; j < map_sites[i].hedges.size(); j++) { /* bad bad constness */ struct half_edge *hedge = &map_sites.write[i].hedges.write[j]; map_hedges.write[hedge_idx] = hedge; hedge_idx++; } } printf("processing half edges done\n"); classify_sites(); printf("processing done, sites count: %d\n", map_sites.size()); } RoadDiagram::RoadDiagram() { class_sizes[map_site::SITE_EMPTY] = 10000; class_sizes[map_site::SITE_FARM] = 100000; class_sizes[map_site::SITE_TOWN] = 240000; class_sizes[map_site::SITE_FOREST] = 1000000; class_sizes[map_site::SITE_UNASSIGNED] = 2000000; } void RoadDiagram::build(Ref rnd, int npatches, int center_count, int center_step, int spread, int dim) { Dictionary diagram = build_diagram(rnd, npatches, center_count, center_step, spread, dim); process_diagram(diagram); } void RoadGrid::build(Ref curve, Ref noise) { int i, j; RoadDiagram rd; rnd.instance(); rnd->randomize(); printf("build_diagram\n"); rd.build(rnd, 8, 2, 100, 100, 500); printf("build_diagram done\n"); const List &cl = rd.get_clusters(); const List::Element *e = cl.front(); for (e = cl.front(); e; e = e->next()) clusters.push_back(e->get()); map_sites.append_array(rd.get_map_sites()); diagram_vertices.append_array(rd.get_diagram_vertices()); map_hedges.append_array(rd.get_map_hedges()); for (i = 0; i < map_hedges.size(); i++) { struct half_edge *hedge = map_hedges.write[i]; add_hedge_to_grid(hedge); } printf("%d %d\n", curve.is_valid(), noise.is_valid()); assert(curve.is_valid() && noise.is_valid()); if (curve.is_valid() && noise.is_valid()) { printf("building 3rd dimention\n"); generate_3d_vertices(curve, noise); for (i = 0; i < map_sites.size(); i++) { float max_height = -10000.0f; float min_height = 10000.0f; for (j = 0; j < map_sites[i].polygon_ind.size(); j++) { float y = vertices[map_sites[i].polygon_ind[j]].y; if (max_height < y) max_height = y; if (min_height > y) min_height = y; } map_sites.write[i].avg_height = min_height * 0.7f + max_height * 0.3f; } generate_building_positions(); printf("building 3rd dimention done\n"); } keep_seed = rnd->get_state(); } Vector2 RoadGrid::get_influence(int x, int y, float radius) const { int rd = (int)(radius / grid_width) + 1; Vector hlist; const List::Element *e; int i = 0, j = 0; for (i = -rd; i < rd + 1; i++) for (j = -rd; j < rd + 1; j++) { if (hedge_grid.has(x / grid_width + i, y / grid_height + j)) { const Vector &tmp = hedge_grid.get(x / grid_width + i, y / grid_height + j); hlist.append_array(tmp); } } if (hlist.size() == 0) return Vector2(); for (i = 0; i < hlist.size(); i++) { struct half_edge *he = hlist[i]; Vector2 a = diagram_vertices[he->a]; Vector2 b = diagram_vertices[he->b]; Vector2 p(x, y); Vector2 seg[] = {a, b}; Vector2 pt = Geometry::get_closest_point_to_segment_2d(p, seg); float d = pt.distance_squared_to(p); if (d < radius * radius + he->depth * he->depth) { Vector2 ret; ret.x = 1.0f; assert(vertices.size() > he->a); assert(vertices.size() > he->b); float h1 = vertices[he->a].y; float h2 = vertices[he->b].y; float l = he->length; assert(l > 0.0f); float m1 = pt.distance_to(a) / l; float m2 = 1.0f - m1; m2 = CLAMP(m2, 0.0f, 1.0f); float h = h1 * (1.0f - m1) + h2 * (1.0f - m2); ret.y = h - 2.5f; return ret; } } return Vector2(); } void RoadGrid::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_debug", "drawable", "size_x", "size_y"), &RoadGrid::draw_debug); ClassDB::bind_method(D_METHOD("get_influence", "x", "y", "radius"), &RoadGrid::get_influence); ClassDB::bind_method(D_METHOD("build", "curve", "noise"), &RoadGrid::build); } int RoadGrid::find_edge(int a, int b) { int i; for (i = 0; i < map_hedges.size(); i++) { if (map_hedges[i]->a == a && map_hedges[i]->b == b) return i; } return -1; } void RoadGrid::setup_vshapes() { int i, j; List vdata_list; for (i = 0; i < map_hedges.size(); i++) { for (j = 0; j < map_hedges.size(); j++) { if (i == j) continue; if (map_hedges[i]->b != map_hedges[j]->a) continue; if (map_hedges[i]->site != map_hedges[j]->site) continue; int a, b1, b2; struct vshape v; /* star topology */ a = map_hedges[i]->b; b1 = map_hedges[i]->a; b2 = map_hedges[j]->b; v.e1 = i; v.e2 = j; v.site = map_hedges[i]->site; v.area.position = vertices[a]; v.area.expand_to(vertices[b1] + Vector3(0, 1, 0)); v.area.expand_to(vertices[b2] + Vector3(0, -1, 0)); v.instance = -1; v.depth1 = map_hedges[v.e1]->depth; v.depth2 = map_hedges[v.e2]->depth; Vector3 p1 = vertices[map_hedges[v.e1]->a]; Vector3 p2 = vertices[map_hedges[v.e1]->b]; Vector3 p3 = vertices[map_hedges[v.e2]->b]; p1 = (p2 + (p1 - p2) * 0.5f).snapped(Vector3(4.0f, 0.1f, 4.0f)); p3 = (p2 + (p3 - p2) * 0.5f).snapped(Vector3(4.0f, 0.1f, 4.0f)); p2 = p2.snapped(Vector3(4.0f, 0.1f, 4.0f)); v.p1 = p1; v.p2 = p2; v.p3 = p3; /* add v-shape only if we can actually generate it */ if (v.p1.distance_squared_to(v.p2) > 2.0f && v.p2.distance_squared_to(v.p3) > 2.0f && v.p1.distance_squared_to(v.p3) > 2.0f) vdata_list.push_back(v); } } vshapes.resize(vdata_list.size()); for (i = 0; i < vdata_list.size(); i++) vshapes.write()[i] = vdata_list[i]; for (i = 0; i < vshapes.size(); i++) { for (j = 0; j < vshapes.size(); j++) { if (i == j) continue; if (vshapes[i].e1 == vshapes[j].e1) vshapes.write()[j].p1 = vshapes[i].p1; if (vshapes[i].e2 == vshapes[j].e1) vshapes.write()[j].p1 = vshapes[i].p3; if (vshapes[i].e1 == vshapes[j].e2) vshapes.write()[j].p3 = vshapes[i].p1; if (vshapes[i].e2 == vshapes[j].e2) vshapes.write()[j].p3 = vshapes[i].p3; } } for (i = 0; i < vshapes.size(); i++) { const struct vshape &v = vshapes[i]; assert(map_hedges[v.e1]->site == map_hedges[v.e2]->site); assert(v.e1 >= 0 && v.e2 >= 0 && v.e1 != v.e2); int e1a = map_hedges[vshapes[i].e1]->a; int e1b = map_hedges[vshapes[i].e1]->b; int e2a = map_hedges[vshapes[i].e2]->a; int e2b = map_hedges[vshapes[i].e2]->b; printf("vshape %d: %d: %d: %f %f %f -> %d: %f %f %f -> %d: %d: %f %f %f -> %d: %f %f %f\n", i, vshapes[i].e1, e1a, vertices[e1a].x, vertices[e1a].y, vertices[e1a].z, e1b, vertices[e1b].x, vertices[e1b].y, vertices[e1b].z, vshapes[i].e2, e2a, vertices[e2a].x, vertices[e2a].y, vertices[e2a].z, e2b, vertices[e2b].x, vertices[e2b].y, vertices[e2b].z ); } } void RoadGrid::sort_angle(Vector &sort_data) { struct comparator { Vector3 *vertices; bool operator()(int a, int b) const { Vector3 p1 = vertices[a]; Vector3 p2 = vertices[b]; Vector2 rp1(p1.x, p1.z); Vector2 rp2(p2.x, p2.z); return rp1.angle() < rp2.angle(); } }; SortArray sorter; sorter.compare.vertices = vertices.write().ptr(); sorter.sort(sort_data.ptrw(), sort_data.size()); } void RoadGrid::generate_3d_vertices(Ref curve, Ref noise) { int i, j; Vector diagram_vertex_heights; diagram_vertex_heights.resize(diagram_vertices.size()); for (i = 0; i < diagram_vertices.size(); i++) { const Vector2 &v = diagram_vertices[i]; float n = noise->get_noise_2d(v.x, v.y); float t = (n + 1.0f) * 0.5f; float d = MAX(1.0f, curve->interpolate_baked(t)); d = CLAMP(d, 1.0f, 30.0f); diagram_vertex_heights.write[i] = d; } for (j = 0; j < 3; j++) { for (i = 0; i < map_hedges.size(); i++) { int x1 = map_hedges[i]->a; int x2 = map_hedges[i]->b; float xd = map_hedges[i]->length; float dh = fabsf(diagram_vertex_heights[x2] - diagram_vertex_heights[x1]); if (fabsf(dh / xd) > 0.01f) diagram_vertex_heights.write[x2] = diagram_vertex_heights[x1] + dh / fabsf(dh) * 0.01f * xd; } } vertices.resize(get_diagram_vertex_count()); for (i = 0; i < vertices.size(); i++) { vertices.write()[i].x = diagram_vertices[i].x; vertices.write()[i].y = diagram_vertex_heights[i]; vertices.write()[i].z = diagram_vertices[i].y; } } void RoadGrid::generate_building_positions() { int i; for (i = 0; i < map_sites.size(); i++) generate_site_building_positions(&map_sites[i]); } void RoadGrid::generate_site_building_positions(const struct map_site *site) { Vector border; Vector3 center_point; } int RoadGrid::get_site_from_point(int x, int z) { int i; for (i = 0; i < map_sites.size(); i++) if (map_sites[i].rect.has_point(Vector2i(x, z))) if (Geometry::is_point_in_polygon(Vector2((float)x, (float)z), map_sites[i].polygon)) return i; return -1; } static String var2str(const Variant &data) { String s; VariantWriter::write_to_string(data, s); return s; } template static Array avar2str(const Vector &data) { Array pdata; int i; pdata.resize(data.size()); for (i = 0; i < data.size(); i++) pdata[i] = var2str(data[i]); return pdata; } static Dictionary half_edge2dict(const struct half_edge *he) { Dictionary ret; ret["a"] = he->a; ret["b"] = he->b; ret["site"] = he->site; ret["depth"] = he->depth; ret["length"] = he->length; return ret; } static Array rect2i_array(const Rect2i &rect) { Array tmp; tmp.resize(4); tmp[0] = rect.position[0]; tmp[1] = rect.position[1]; tmp[2] = rect.size[0]; tmp[3] = rect.size[1]; return tmp; } static Dictionary map_site2dict(const struct map_site *ms) { int i; Dictionary ret; Array hedges; ret["index"] = ms->index; ret["pos"] = var2str(ms->pos); ret["vertices"] = avar2str(ms->vertices); ret["polygon"] = avar2str(ms->polygon); ret["vertices_ind"] = avar2str(ms->vertices_ind); ret["polygon_ind"] = avar2str(ms->polygon_ind); ret["site_type"] = ms->site_type; ret["cluster"] = ms->cluster; hedges.resize(ms->hedges.size()); for (i = 0; i < ms->hedges.size(); i++) hedges[i] = half_edge2dict(&ms->hedges[i]); ret["hedges"] = hedges; ret["rect"] = rect2i_array(ms->rect); ret["avg_height"] = ms->avg_height; return ret; } static Dictionary vshape2dict(const struct vshape *v) { Dictionary ret; ret["area"] = var2str(v->area); ret["instance"] = v->instance; ret["e1"] = v->e1; ret["e2"] = v->e2; ret["site"] = v->site; ret["p1"] = var2str(v->p1); ret["p2"] = var2str(v->p2); ret["p3"] = var2str(v->p3); ret["depth1"] = v->depth1; ret["depth2"] = v->depth2; return ret; } void RoadGrid::save_json(const String &path) { int i; String vars; FileAccess *f; Dictionary to_json; /* Clusters */ Array save_clusters; /* save clusters */ save_clusters.resize(clusters.size()); for (i = 0; i < clusters.size(); i++) { Dictionary cluster; cluster["pos_x"] = clusters[i].c.x; cluster["pos_y"] = clusters[i].c.y; cluster["radius"] = clusters[i].r; save_clusters[i] = cluster; } to_json["clusters"] = save_clusters; to_json["bounds"] = var2str(bounds); to_json["diagram_vertices"] = avar2str(diagram_vertices); Array msites, mvshapes; msites.resize(map_sites.size()); for (i = 0; i < map_sites.size(); i++) msites[i] = map_site2dict(&map_sites[i]); to_json["map_sites"] = msites; to_json["vertices"] = var2str(vertices); mvshapes.resize(vshapes.size()); for (i = 0; i < vshapes.size(); i++) { const struct vshape *v = &(vshapes.read()[i]); mvshapes[i] = vshape2dict(v); } to_json["vshapes"] = mvshapes; String json = JSON::print(to_json, "\t"); f = FileAccess::open(path, FileAccess::WRITE); if (f) { f->store_string(json); f->close(); } } PoolVector RoadGrid::get_site_border(int site) { const struct map_site &msite = map_sites[site]; List site_vshapes; List::Element *e; PoolVector ret; int i, j; for (i = 0; i < msite.polygon_ind.size(); i++) { int p1 = i; int p2 = (i + 1) % msite.polygon_ind.size(); int p3 = (i + 2) % msite.polygon_ind.size(); for (j = 0; j < vshapes.size(); j++) { struct vshape &v = vshapes.write()[j]; if (v.site != site) continue; struct half_edge *hedge1 = map_hedges[v.e1]; struct half_edge *hedge2 = map_hedges[v.e2]; if (hedge1->a != p1 || hedge1->b != p2 || hedge2->b != p3) continue; site_vshapes.push_back(&v); } } ret.resize(site_vshapes.size()); int count = 0; for (e = site_vshapes.front(); e; e = e->next()) { struct vshape *pv = e->get(); float l = pv->curve3->get_baked_length(); Vector3 bp = pv->curve3->interpolate_baked(l * 0.5f) + pv->p2; ret.write()[count++] = bp; } printf("polygon count %d border count %d\n", msite.polygon_ind.size(), ret.size()); assert(msite.polygon_ind.size() == ret.size()); return ret; }