Make the NavigationMesh generator and the TileMapNavigationGeometryParser use the new Clipper2 module. (Note that the clipper2 module is only temporary, it only exists to help with backporting the code.)

This commit is contained in:
Relintai 2023-06-06 19:02:33 +02:00
parent a65ad4d279
commit a5c03b77c1
6 changed files with 103 additions and 69 deletions

View File

@ -14,3 +14,9 @@ env_navigation.add_source_files(module_obj, "geometry_parser_2d/*.cpp")
env_navigation.add_source_files(module_obj, "geometry_parser_3d/*.cpp")
env.modules_sources += module_obj
# Temp TODO Remove
if env_navigation.msvc:
env_navigation.Append(CXXFLAGS=['/std:c++17'])
else:
env_navigation.Append(CXXFLAGS=['-std=c++17'])

View File

@ -35,6 +35,8 @@
#include "scene/resources/navigation_mesh_source_geometry_data_2d.h"
#include "scene/resources/navigation_polygon.h"
#include "modules/modules_enabled.gen.h"
#ifdef CLIPPER_ENABLED
#include "thirdparty/clipper2/include/clipper2/clipper.h"
#endif // CLIPPER_ENABLED

View File

@ -35,6 +35,8 @@
#include "scene/resources/navigation_mesh_source_geometry_data_2d.h"
#include "scene/resources/navigation_polygon.h"
#include "modules/modules_enabled.gen.h"
#ifdef CLIPPER_ENABLED
#include "thirdparty/clipper2/include/clipper2/clipper.h"
#endif // CLIPPER_ENABLED

View File

@ -32,12 +32,16 @@
//#include "scene/2d/tile_map.h"
#include "scene/resources/navigation_polygon.h"
#include "modules/tile_map/tile_map.h"
#include "modules/tile_map/tile_set.h"
#include "scene/resources/navigation_mesh_source_geometry_data_2d.h"
#include "scene/resources/navigation_polygon.h"
#ifdef CLIPPER_ENABLED
#include "thirdparty/clipper2/include/clipper2/clipper.h"
#endif // CLIPPER_ENABLED
#include "modules/modules_enabled.gen.h"
#ifdef MODULE_CLIPPER2_ENABLED
#include "modules/clipper2/lib/include/clipper2/clipper.h"
#endif // MODULE_CLIPPER2_ENABLED
bool TileMap2DNavigationGeometryParser2D::parses_node(Node *p_node) {
//return (Object::cast_to<TileMap>(p_node) != nullptr);
@ -45,61 +49,51 @@ bool TileMap2DNavigationGeometryParser2D::parses_node(Node *p_node) {
}
void TileMap2DNavigationGeometryParser2D::parse_geometry(Node *p_node, Ref<NavigationPolygon> p_navigation_polygon, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry) {
#ifdef CLIPPER_ENABLED
#ifdef MODULE_CLIPPER2_ENABLED
TileMap *tilemap = Object::cast_to<TileMap>(p_node);
NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_polygon->get_parsed_geometry_type();
uint32_t navigation_polygon_collision_mask = p_navigation_polygon->get_collision_mask();
//NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_polygon->get_parsed_geometry_type();
//uint32_t navigation_polygon_collision_mask = p_navigation_polygon->get_collision_mask();
if (tilemap) {
if (tilemap->get_layers_count() <= 0) {
return;
}
int tilemap_layer = 0; // only main tile map layer is supported
Ref<TileSet> tile_set = tilemap->get_tileset();
if (!tile_set.is_valid()) {
return;
}
int physics_layers_count = tile_set->get_physics_layers_count();
int navigation_layers_count = tile_set->get_navigation_layers_count();
if (physics_layers_count <= 0 && navigation_layers_count <= 0) {
return;
}
const Transform2D tilemap_xform = tilemap->get_transform();
TypedArray<Vector2i> used_cells = tilemap->get_used_cells(tilemap_layer);
Array used_cells = tilemap->get_used_cells();
for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) {
const Vector2i &cell = used_cells[used_cell_index];
Vector2 cell = used_cells[used_cell_index];
const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false);
int cell_id = tilemap->get_cell(cell.x, cell.y);
Transform2D tile_transform;
tile_transform.set_origin(tilemap->map_to_local(cell));
tile_transform.set_origin(tilemap->to_local(cell));
const Transform2D tile_transform_offset = tilemap_xform * tile_transform;
if (navigation_layers_count > 0) {
Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer);
Ref<NavigationPolygon> navigation_polygon = tile_set->tile_get_navigation_polygon(cell_id);
if (navigation_polygon.is_valid()) {
for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
Vector<Vector2> traversable_outline = navigation_polygon->get_outline(outline_index);
PoolVector<Vector2> traversable_outline = navigation_polygon->get_outline(outline_index);
Vector<Vector2> traversable_outline_new;
traversable_outline_new.resize(traversable_outline.size());
for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
traversable_outline.write[traversable_outline_index] = tile_transform_offset.xform(traversable_outline[traversable_outline_index]);
traversable_outline_new.write[traversable_outline_index] = tile_transform_offset.xform(traversable_outline[traversable_outline_index]);
}
p_source_geometry->_add_traversable_outline(traversable_outline);
}
p_source_geometry->_add_traversable_outline(traversable_outline_new);
}
}
if (physics_layers_count > 0 && parsed_geometry_type != NavigationPolygon::PARSED_GEOMETRY_MESH_INSTANCES && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & navigation_polygon_collision_mask)) {
for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) {
Vector<Vector2> obstruction_outline = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
/*
TODO
if (parsed_geometry_type != NavigationPolygon::PARSED_GEOMETRY_MESH_INSTANCES && (tilemap->get_collision_layer() & navigation_polygon_collision_mask)) {
for (int collision_polygon_index = 0; collision_polygon_index < tile_set->tile_get_shape_count(cell_id); collision_polygon_index++) {
Vector<Vector2> obstruction_outline = tile_set->get_collision_polygon_points(collision_polygon_index);
for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
obstruction_outline.write[obstruction_outline_index] = tile_transform_offset.xform(obstruction_outline[obstruction_outline_index]);
@ -108,7 +102,8 @@ void TileMap2DNavigationGeometryParser2D::parse_geometry(Node *p_node, Ref<Navig
p_source_geometry->_add_obstruction_outline(obstruction_outline);
}
}
*/
}
}
#endif // CLIPPER_ENABLED
}
#endif // MODULE_CLIPPER2_ENABLED

View File

@ -47,5 +47,11 @@ if env["tools"]:
env.modules_sources += module_obj
# Temp TODO Remove
if env_navigation_mesh_generator.msvc:
env_navigation_mesh_generator.Append(CXXFLAGS=['/std:c++17'])
else:
env_navigation_mesh_generator.Append(CXXFLAGS=['-std=c++17'])
# Needed to force rebuilding the module files when the thirdparty library is updated.
#env.Depends(module_obj, thirdparty_obj)

View File

@ -44,10 +44,12 @@
#include "scene/3d/mesh_instance.h"
#endif // _3D_DISABLED
#ifdef CLIPPER_ENABLED
#include "thirdparty/clipper2/include/clipper2/clipper.h"
#include "thirdparty/misc/polypartition.h"
#endif // CLIPPER_ENABLED
#include "modules/modules_enabled.gen.h"
#ifdef MODULE_CLIPPER2_ENABLED
#include "modules/clipper2/lib/include/clipper2/clipper.h"
#include "modules/clipper2/polypartition.h"
#endif
#ifndef _3D_DISABLED
#include <Recast.h>
@ -290,7 +292,7 @@ void PandemoniumNavigationMeshGenerator::_static_parse_2d_source_geometry_data(R
}
// rewrite this to use clipper 1
#ifdef CLIPPER_ENABLED
#ifdef MODULE_CLIPPER2_ENABLED
static void _recursive_process_polytree_items(List<TPPLPoly> &p_tppl_in_polygon, const Clipper2Lib::PolyPath64 *p_polypath_item) {
using namespace Clipper2Lib;
@ -319,18 +321,18 @@ static void _recursive_process_polytree_items(List<TPPLPoly> &p_tppl_in_polygon,
_recursive_process_polytree_items(p_tppl_in_polygon, polypath_item);
}
}
#endif // CLIPPER_ENABLED
#endif // MODULE_CLIPPER2_ENABLED
void PandemoniumNavigationMeshGenerator::_static_bake_2d_from_source_geometry_data(Ref<NavigationPolygon> p_navigation_polygon, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data) {
ERR_FAIL_COND_MSG(!p_navigation_polygon.is_valid(), "Invalid navigation polygon.");
ERR_FAIL_COND_MSG(!p_source_geometry_data.is_valid(), "Invalid source geometry data.");
ERR_FAIL_COND_MSG(p_navigation_polygon->get_outline_count() == 0 && !p_source_geometry_data->has_data(), "NavigationMeshSourceGeometryData2D is empty. Parse source geometry first.");
//const Vector<Vector<Vector2>> &traversable_outlines = p_source_geometry_data->_get_traversable_outlines();
//const Vector<Vector<Vector2>> &obstruction_outlines = p_source_geometry_data->_get_obstruction_outlines();
const Vector<Vector<Vector2>> &traversable_outlines = p_source_geometry_data->_get_traversable_outlines();
const Vector<Vector<Vector2>> &obstruction_outlines = p_source_geometry_data->_get_obstruction_outlines();
// rewrite this to use clipper 1
#ifdef CLIPPER_ENABLED
#ifdef MODULE_CLIPPER2_ENABLED
using namespace Clipper2Lib;
Paths64 traversable_polygon_paths;
@ -338,27 +340,39 @@ void PandemoniumNavigationMeshGenerator::_static_bake_2d_from_source_geometry_da
int outline_count = p_navigation_polygon->get_outline_count();
for (int i = 0; i < outline_count; i++) {
const Vector<Vector2> &traversable_outline = p_navigation_polygon->get_outline(i);
PoolVector<Vector2> traversable_outline = p_navigation_polygon->get_outline(i);
Path64 subject_path;
for (const Vector2 &traversable_point : traversable_outline) {
for (int j = 0; j < traversable_outline.size(); ++j) {
Vector2 traversable_point = traversable_outline[j];
const Point64 &point = Point64(traversable_point.x, traversable_point.y);
subject_path.push_back(point);
}
traversable_polygon_paths.push_back(subject_path);
}
for (const Vector<Vector2> &traversable_outline : traversable_outlines) {
for (int i = 0; i < traversable_outlines.size(); i++) {
Vector<Vector2> traversable_outline = traversable_outlines[i];
Path64 subject_path;
for (const Vector2 &traversable_point : traversable_outline) {
for (int j = 0; j < traversable_outline.size(); ++j) {
Vector2 traversable_point = traversable_outline[j];
const Point64 &point = Point64(traversable_point.x, traversable_point.y);
subject_path.push_back(point);
}
traversable_polygon_paths.push_back(subject_path);
}
for (const Vector<Vector2> &obstruction_outline : obstruction_outlines) {
for (int i = 0; i < obstruction_outlines.size(); i++) {
const Vector<Vector2> &obstruction_outline = obstruction_outlines[i];
Path64 clip_path;
for (const Vector2 &obstruction_point : obstruction_outline) {
for (int j = 0; j < obstruction_outline.size(); ++j) {
const Vector2 &obstruction_point = obstruction_outline[j];
const Point64 &point = Point64(obstruction_point.x, obstruction_point.y);
clip_path.push_back(point);
}
@ -420,30 +434,39 @@ void PandemoniumNavigationMeshGenerator::_static_bake_2d_from_source_geometry_da
}
//path_solution = RamerDouglasPeucker(path_solution, 0.025); //
Vector<Vector<Vector2>> new_baked_outlines;
Vector<PoolVector<Vector2>> new_baked_outlines;
for (uint32_t i = 0; i < path_solution.size(); i++) {
const Path64 &scaled_path = path_solution[i];
PoolVector<Vector2> polypath;
for (uint32_t j = 0; j < scaled_path.size(); ++j) {
const Point64 &scaled_point = scaled_path[j];
for (const Path64 &scaled_path : path_solution) {
Vector<Vector2> polypath;
for (const Point64 &scaled_point : scaled_path) {
polypath.push_back(Vector2(static_cast<real_t>(scaled_point.x), static_cast<real_t>(scaled_point.y)));
}
new_baked_outlines.push_back(polypath);
}
p_navigation_polygon->internal_set_baked_outlines(new_baked_outlines);
p_navigation_polygon->set_baked_outlines(new_baked_outlines);
if (new_baked_outlines.size() == 0) {
p_navigation_polygon->set_vertices(Vector<Vector2>());
p_navigation_polygon->internal_set_polygons(Vector<Vector<int>>());
p_navigation_polygon->set_vertices(PoolVector<Vector2>());
p_navigation_polygon->set_polygons(Vector<Vector<int>>());
p_navigation_polygon->commit_changes();
return;
}
Paths64 polygon_paths;
for (const Vector<Vector2> &baked_outline : new_baked_outlines) {
for (int i = 0; i < new_baked_outlines.size(); i++) {
const PoolVector<Vector2> &baked_outline = new_baked_outlines[i];
Path64 polygon_path;
for (const Vector2 &baked_outline_point : baked_outline) {
for (int j = 0; j < baked_outline.size(); ++j) {
const Vector2 &baked_outline_point = baked_outline[j];
const Point64 &point = Point64(baked_outline_point.x, baked_outline_point.y);
polygon_path.push_back(point);
}
@ -468,13 +491,13 @@ void PandemoniumNavigationMeshGenerator::_static_bake_2d_from_source_geometry_da
TPPLPartition tpart;
if (tpart.ConvexPartition_HM(&tppl_in_polygon, &tppl_out_polygon) == 0) { //failed!
ERR_PRINT("NavigationPolygon Convex partition failed. Unable to create a valid NavigationMesh from defined polygon outline paths.");
p_navigation_polygon->set_vertices(Vector<Vector2>());
p_navigation_polygon->internal_set_polygons(Vector<Vector<int>>());
p_navigation_polygon->set_vertices(PoolVector<Vector2>());
p_navigation_polygon->set_polygons(Vector<Vector<int>>());
p_navigation_polygon->commit_changes();
return;
}
Vector<Vector2> new_vertices;
PoolVector<Vector2> new_vertices;
Vector<Vector<int>> new_polygons;
HashMap<Vector2, int> points;
@ -484,20 +507,20 @@ void PandemoniumNavigationMeshGenerator::_static_bake_2d_from_source_geometry_da
Vector<int> new_polygon;
for (int64_t i = 0; i < tp.GetNumPoints(); i++) {
HashMap<Vector2, int>::Iterator E = points.find(tp[i]);
HashMap<Vector2, int>::Element *E = points.find(tp[i]);
if (!E) {
E = points.insert(tp[i], new_vertices.size());
new_vertices.push_back(tp[i]);
}
new_polygon.push_back(E->value);
new_polygon.push_back(E->value());
}
new_polygons.push_back(new_polygon);
}
p_navigation_polygon->set_vertices(new_vertices);
p_navigation_polygon->internal_set_polygons(new_polygons);
#endif // CLIPPER_ENABLED
p_navigation_polygon->set_polygons(new_polygons);
#endif // MODULE_CLIPPER2_ENABLED
p_navigation_polygon->commit_changes();
}