#ifndef ROAD_GRID_H #define ROAD_GRID_H #include #include #include #include #include #include class CanvasItem; /* TODO: * a * - Implement diagram edges with site reference. * - Implement draw edges according to current position, * indicating which are drawn. * - Implement removal of draw edges by distance * * - Rewrite debug draw using distance logic. * - Implement 3D position for road vertices based on heightmap object; * - Implement SDF influence calculation based on distance to road * - Implement SDF calculation for roads (height cutoff by segment) * b * - Implement nodes (intersections) for drawing road intersections * - Implement draw edge splitting and position improvement. * - Find "wall" edges? * c * - Implement lot system based on sites * - Split lots to place buildings and other environment * objects * d * - Implement 3D positions and geometry generation */ class RoadGrid: public Reference { GDCLASS(RoadGrid, Object) protected: Ref rnd; struct cluster { Vector2i c; float r; }; List clusters; Dictionary build_diagram(int npatches, int center_count, int center_step, int spread, int dim); HashMap class_sizes; struct half_edge; Rect2 bounds; void set_class_size(int cl, int sz) { class_sizes[cl] = sz; } static void _bind_methods(); enum { SITE_UNASSIGNED = 0, SITE_FOREST, SITE_FARM, SITE_TOWN, SITE_EMPTY, SITE_MAX }; struct graphedge { int a, b; int edge; }; struct half_edge { int a, b; int site; float depth; float length; }; struct map_site { int index; Vector2 pos; Vector graphedges; Vector vertices; Vector polygon; Vector vertices_ind; Vector polygon_ind; int site_type; int cluster; Vector hedges; }; void index_site(struct map_site *site); Vector diagram_vertices; Vector diagram_vertex_heights; Vector map_sites; Vector map_hedges; void classify_sites() { int i, j; for (j = 0; j < map_sites.size(); j++) { Rect2 r; for (i = 0; i < map_sites[j].polygon.size(); i++) { if (i == 0) { r.position = map_sites[j].polygon[0]; r.size = Vector2(); } else { r.expand_to(map_sites[j].polygon[i]); } } int cl_area = (int)(r.get_area() + 1.0f); for (i = 0; i < SITE_MAX; i++) { if (class_sizes.has(i)) if (cl_area <= class_sizes[i]) { map_sites.write[j].site_type = i; break; } } printf("area: %d class: %d\n", cl_area, map_sites[j].site_type); } } void process_diagram(const Dictionary &diagram); bool segment_intersects_rect(const Vector2 &a, const Vector2 &b, const Rect2 &rect); inline bool segment_in_grid_rect(const Vector2 &a, const Vector2 &b, int x, int y) { Rect2 r((float)(x * grid_width), (float)(y * grid_height), grid_width, grid_height); return segment_intersects_rect(a, b, r); } inline Rect2 segment_to_rect(const Vector2 &a, const Vector2 &b) const { Rect2 r(a, Vector2()); r.expand_to(b); return r; } inline Rect2i rect_to_grid(const Rect2 &r) const { Rect2i ret; ret.position.x = get_grid_x(r.position.x); ret.position.y = get_grid_y(r.position.y); ret.size.x = get_grid_x(r.size.x) + 1; ret.size.y = get_grid_y(r.size.y) + 1; return ret; } inline Rect2 get_grid_rect(int x, int y) const { Rect2 rect; rect.position.x = (float)x * grid_width; rect.position.y = (float)y * grid_height; rect.size.x = grid_width; rect.size.x = grid_height; return rect; } class hg { typedef Vector tvalue; std::unordered_map > > hedge_grid; public: inline const tvalue get(int x, int y) const { return hedge_grid.at(x).at(y); } inline bool has(int x, int y) const { if (hedge_grid.find(x) != hedge_grid.end() && hedge_grid.at(x).find(y) != hedge_grid.at(x).end()) return true; return false; } inline void set(int x, int y, struct half_edge *hedge) { Vector items; if (has(x, y)) items = get(x, y); items.resize(items.size() + 1); items.write[items.size() - 1] = hedge; hedge_grid[x][y] = items; } }; class hg hedge_grid; inline void insert_hedge_to_grid_cell(int x, int y, struct half_edge *hedge) { static int count = 0; count++; hedge_grid.set(x, y, hedge); printf("count: %d\n", count); } inline void add_hedge_to_grid(struct half_edge *hedge) { Vector2 a = diagram_vertices[hedge->a]; Vector2 b = diagram_vertices[hedge->b]; if (bounds.position.length_squared() == 0.0f && bounds.position.length_squared() == 0.0f) { bounds.position.x = a.x; bounds.position.y = a.y; } else bounds.expand_to(a); bounds.expand_to(b); Rect2 r = segment_to_rect(a, b).grow(1.0f); Rect2i rgrid = rect_to_grid(r); int x, y; for (y = 0; y < rgrid.size.y; y++) { for (x = 0; x < rgrid.size.x; x++) { int px = rgrid.position.x + x; int py = rgrid.position.y + y; Rect2 xr = get_grid_rect(px, py).grow(16.0f); if (segment_intersects_rect(a, b, xr)) insert_hedge_to_grid_cell(px, py, hedge); } } } inline int get_grid_x(float x) const { return (int)(x / grid_width); } inline int get_grid_y(float y) const { return (int)(y / grid_height); } float grid_width, grid_height; PoolVector vertices; public: struct vshape { AABB area; int instance; int e1, e2; int site; Vector3 p1, p2, p3; }; protected: PoolVector vshapes; void sort_angle(Vector &sort_data); public: void build(Ref curve, Ref noise); void draw_debug(Node *drawable, int size_x, int size_y) const; int find_edge(int a, int b); void setup_vshapes(); inline const PoolVector &get_vshapes() const { const PoolVector &ret = vshapes; return ret; } inline PoolVector &get_vshapes() { PoolVector &ret = vshapes; return ret; } Vector2 get_influence(int x, int y, float radius) const; RoadGrid(); ~RoadGrid(); inline int get_diagram_vertex_count() const { return diagram_vertices.size(); } inline int get_map_hedges_count() const { return map_hedges.size(); } void build_building_positions(); }; #endif