Path: blob/master/scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp
9903 views
/**************************************************************************/1/* navigation_mesh_source_geometry_data_3d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "navigation_mesh_source_geometry_data_3d.h"3132void NavigationMeshSourceGeometryData3D::set_vertices(const Vector<float> &p_vertices) {33RWLockWrite write_lock(geometry_rwlock);34vertices = p_vertices;35bounds_dirty = true;36}3738const Vector<float> &NavigationMeshSourceGeometryData3D::get_vertices() const {39RWLockRead read_lock(geometry_rwlock);40return vertices;41}4243void NavigationMeshSourceGeometryData3D::set_indices(const Vector<int> &p_indices) {44ERR_FAIL_COND(vertices.size() < p_indices.size());45RWLockWrite write_lock(geometry_rwlock);46indices = p_indices;47bounds_dirty = true;48}4950const Vector<int> &NavigationMeshSourceGeometryData3D::get_indices() const {51RWLockRead read_lock(geometry_rwlock);52return indices;53}5455void NavigationMeshSourceGeometryData3D::append_arrays(const Vector<float> &p_vertices, const Vector<int> &p_indices) {56RWLockWrite write_lock(geometry_rwlock);5758const int64_t number_of_vertices_before_merge = vertices.size();59const int64_t number_of_indices_before_merge = indices.size();6061vertices.append_array(p_vertices);62indices.append_array(p_indices);6364for (int64_t i = number_of_indices_before_merge; i < indices.size(); i++) {65indices.set(i, indices[i] + number_of_vertices_before_merge / 3);66}67bounds_dirty = true;68}6970bool NavigationMeshSourceGeometryData3D::has_data() {71RWLockRead read_lock(geometry_rwlock);72return vertices.size() && indices.size();73}7475void NavigationMeshSourceGeometryData3D::clear() {76RWLockWrite write_lock(geometry_rwlock);77vertices.clear();78indices.clear();79_projected_obstructions.clear();80bounds_dirty = true;81}8283void NavigationMeshSourceGeometryData3D::clear_projected_obstructions() {84RWLockWrite write_lock(geometry_rwlock);85_projected_obstructions.clear();86bounds_dirty = true;87}8889void NavigationMeshSourceGeometryData3D::_add_vertex(const Vector3 &p_vec3) {90vertices.push_back(p_vec3.x);91vertices.push_back(p_vec3.y);92vertices.push_back(p_vec3.z);93}9495void NavigationMeshSourceGeometryData3D::_add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform) {96int current_vertex_count;97for (int i = 0; i < p_mesh->get_surface_count(); i++) {98current_vertex_count = vertices.size() / 3;99100if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {101continue;102}103104int index_count = 0;105if (p_mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {106index_count = p_mesh->surface_get_array_index_len(i);107} else {108index_count = p_mesh->surface_get_array_len(i);109}110111ERR_CONTINUE((index_count == 0 || (index_count % 3) != 0));112113int face_count = index_count / 3;114115Array a = p_mesh->surface_get_arrays(i);116ERR_CONTINUE(a.is_empty() || (a.size() != Mesh::ARRAY_MAX));117118Vector<Vector3> mesh_vertices = a[Mesh::ARRAY_VERTEX];119ERR_CONTINUE(mesh_vertices.is_empty());120const Vector3 *vr = mesh_vertices.ptr();121122if (p_mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {123Vector<int> mesh_indices = a[Mesh::ARRAY_INDEX];124ERR_CONTINUE(mesh_indices.is_empty() || (mesh_indices.size() != index_count));125const int *ir = mesh_indices.ptr();126127for (int j = 0; j < mesh_vertices.size(); j++) {128_add_vertex(p_xform.xform(vr[j]));129}130131for (int j = 0; j < face_count; j++) {132// CCW133indices.push_back(current_vertex_count + (ir[j * 3 + 0]));134indices.push_back(current_vertex_count + (ir[j * 3 + 2]));135indices.push_back(current_vertex_count + (ir[j * 3 + 1]));136}137} else {138ERR_CONTINUE(mesh_vertices.size() != index_count);139face_count = mesh_vertices.size() / 3;140for (int j = 0; j < face_count; j++) {141_add_vertex(p_xform.xform(vr[j * 3 + 0]));142_add_vertex(p_xform.xform(vr[j * 3 + 2]));143_add_vertex(p_xform.xform(vr[j * 3 + 1]));144145indices.push_back(current_vertex_count + (j * 3 + 0));146indices.push_back(current_vertex_count + (j * 3 + 1));147indices.push_back(current_vertex_count + (j * 3 + 2));148}149}150}151}152153void NavigationMeshSourceGeometryData3D::_add_mesh_array(const Array &p_mesh_array, const Transform3D &p_xform) {154ERR_FAIL_COND(p_mesh_array.size() != Mesh::ARRAY_MAX);155156Vector<Vector3> mesh_vertices = p_mesh_array[Mesh::ARRAY_VERTEX];157ERR_FAIL_COND(mesh_vertices.is_empty());158const Vector3 *vr = mesh_vertices.ptr();159160Vector<int> mesh_indices = p_mesh_array[Mesh::ARRAY_INDEX];161ERR_FAIL_COND(mesh_indices.is_empty());162const int *ir = mesh_indices.ptr();163164const int face_count = mesh_indices.size() / 3;165const int current_vertex_count = vertices.size() / 3;166167for (int j = 0; j < mesh_vertices.size(); j++) {168_add_vertex(p_xform.xform(vr[j]));169}170171for (int j = 0; j < face_count; j++) {172// CCW173indices.push_back(current_vertex_count + (ir[j * 3 + 0]));174indices.push_back(current_vertex_count + (ir[j * 3 + 2]));175indices.push_back(current_vertex_count + (ir[j * 3 + 1]));176}177}178179void NavigationMeshSourceGeometryData3D::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform) {180ERR_FAIL_COND(p_faces.is_empty());181ERR_FAIL_COND(p_faces.size() % 3 != 0);182int face_count = p_faces.size() / 3;183int current_vertex_count = vertices.size() / 3;184185for (int j = 0; j < face_count; j++) {186_add_vertex(p_xform.xform(p_faces[j * 3 + 0]));187_add_vertex(p_xform.xform(p_faces[j * 3 + 1]));188_add_vertex(p_xform.xform(p_faces[j * 3 + 2]));189190indices.push_back(current_vertex_count + (j * 3 + 0));191indices.push_back(current_vertex_count + (j * 3 + 2));192indices.push_back(current_vertex_count + (j * 3 + 1));193}194}195196void NavigationMeshSourceGeometryData3D::add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform) {197ERR_FAIL_COND(p_mesh.is_null());198199#ifdef DEBUG_ENABLED200if (!Engine::get_singleton()->is_editor_hint()) {201WARN_PRINT_ONCE("Source geometry parsing for navigation mesh baking had to parse RenderingServer meshes at runtime.\n\202This poses a significant performance issues as visual meshes store geometry data on the GPU and transferring this data back to the CPU blocks the rendering.\n\203For runtime (re)baking navigation meshes use and parse collision shapes as source geometry or create geometry data procedurally in scripts.");204}205#endif206207_add_mesh(p_mesh, root_node_transform * p_xform);208}209210void NavigationMeshSourceGeometryData3D::add_mesh_array(const Array &p_mesh_array, const Transform3D &p_xform) {211ERR_FAIL_COND(p_mesh_array.size() != Mesh::ARRAY_MAX);212RWLockWrite write_lock(geometry_rwlock);213_add_mesh_array(p_mesh_array, root_node_transform * p_xform);214bounds_dirty = true;215}216217void NavigationMeshSourceGeometryData3D::add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform) {218ERR_FAIL_COND(p_faces.size() % 3 != 0);219RWLockWrite write_lock(geometry_rwlock);220_add_faces(p_faces, root_node_transform * p_xform);221bounds_dirty = true;222}223224void NavigationMeshSourceGeometryData3D::merge(const Ref<NavigationMeshSourceGeometryData3D> &p_other_geometry) {225ERR_FAIL_COND(p_other_geometry.is_null());226227Vector<float> other_vertices;228Vector<int> other_indices;229Vector<ProjectedObstruction> other_projected_obstructions;230231p_other_geometry->get_data(other_vertices, other_indices, other_projected_obstructions);232233RWLockWrite write_lock(geometry_rwlock);234const int64_t number_of_vertices_before_merge = vertices.size();235const int64_t number_of_indices_before_merge = indices.size();236237vertices.append_array(other_vertices);238indices.append_array(other_indices);239240for (int64_t i = number_of_indices_before_merge; i < indices.size(); i++) {241indices.set(i, indices[i] + number_of_vertices_before_merge / 3);242}243244_projected_obstructions.append_array(other_projected_obstructions);245bounds_dirty = true;246}247248void NavigationMeshSourceGeometryData3D::add_projected_obstruction(const Vector<Vector3> &p_vertices, float p_elevation, float p_height, bool p_carve) {249ERR_FAIL_COND(p_vertices.size() < 3);250ERR_FAIL_COND(p_height < 0.0);251252ProjectedObstruction projected_obstruction;253projected_obstruction.vertices.resize(p_vertices.size() * 3);254projected_obstruction.elevation = p_elevation;255projected_obstruction.height = p_height;256projected_obstruction.carve = p_carve;257258float *obstruction_vertices_ptrw = projected_obstruction.vertices.ptrw();259260int vertex_index = 0;261for (const Vector3 &vertex : p_vertices) {262obstruction_vertices_ptrw[vertex_index++] = vertex.x;263obstruction_vertices_ptrw[vertex_index++] = vertex.y;264obstruction_vertices_ptrw[vertex_index++] = vertex.z;265}266267RWLockWrite write_lock(geometry_rwlock);268_projected_obstructions.push_back(projected_obstruction);269bounds_dirty = true;270}271272void NavigationMeshSourceGeometryData3D::set_projected_obstructions(const Array &p_array) {273clear_projected_obstructions();274275for (int i = 0; i < p_array.size(); i++) {276Dictionary data = p_array[i];277ERR_FAIL_COND(!data.has("version"));278279uint32_t po_version = data["version"];280281if (po_version == 1) {282ERR_FAIL_COND(!data.has("vertices"));283ERR_FAIL_COND(!data.has("elevation"));284ERR_FAIL_COND(!data.has("height"));285ERR_FAIL_COND(!data.has("carve"));286}287288ProjectedObstruction projected_obstruction;289projected_obstruction.vertices = Vector<float>(data["vertices"]);290projected_obstruction.elevation = data["elevation"];291projected_obstruction.height = data["height"];292projected_obstruction.carve = data["carve"];293294RWLockWrite write_lock(geometry_rwlock);295_projected_obstructions.push_back(projected_obstruction);296bounds_dirty = true;297}298}299300Vector<NavigationMeshSourceGeometryData3D::ProjectedObstruction> NavigationMeshSourceGeometryData3D::_get_projected_obstructions() const {301RWLockRead read_lock(geometry_rwlock);302return _projected_obstructions;303}304305Array NavigationMeshSourceGeometryData3D::get_projected_obstructions() const {306RWLockRead read_lock(geometry_rwlock);307308Array ret;309ret.resize(_projected_obstructions.size());310311for (int i = 0; i < _projected_obstructions.size(); i++) {312const ProjectedObstruction &projected_obstruction = _projected_obstructions[i];313314Dictionary data;315data["version"] = (int)ProjectedObstruction::VERSION;316data["vertices"] = projected_obstruction.vertices;317data["elevation"] = projected_obstruction.elevation;318data["height"] = projected_obstruction.height;319data["carve"] = projected_obstruction.carve;320321ret[i] = data;322}323324return ret;325}326327bool NavigationMeshSourceGeometryData3D::_set(const StringName &p_name, const Variant &p_value) {328if (p_name == "projected_obstructions") {329set_projected_obstructions(p_value);330return true;331}332return false;333}334335bool NavigationMeshSourceGeometryData3D::_get(const StringName &p_name, Variant &r_ret) const {336if (p_name == "projected_obstructions") {337r_ret = get_projected_obstructions();338return true;339}340return false;341}342343void NavigationMeshSourceGeometryData3D::set_data(const Vector<float> &p_vertices, const Vector<int> &p_indices, Vector<ProjectedObstruction> &p_projected_obstructions) {344RWLockWrite write_lock(geometry_rwlock);345vertices = p_vertices;346indices = p_indices;347_projected_obstructions = p_projected_obstructions;348bounds_dirty = true;349}350351void NavigationMeshSourceGeometryData3D::get_data(Vector<float> &r_vertices, Vector<int> &r_indices, Vector<ProjectedObstruction> &r_projected_obstructions) {352RWLockRead read_lock(geometry_rwlock);353r_vertices = vertices;354r_indices = indices;355r_projected_obstructions = _projected_obstructions;356}357358AABB NavigationMeshSourceGeometryData3D::get_bounds() {359geometry_rwlock.read_lock();360361if (bounds_dirty) {362geometry_rwlock.read_unlock();363RWLockWrite write_lock(geometry_rwlock);364365bounds_dirty = false;366bounds = AABB();367bool first_vertex = true;368369for (int i = 0; i < vertices.size() / 3; i++) {370const Vector3 vertex = Vector3(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);371if (first_vertex) {372first_vertex = false;373bounds.position = vertex;374} else {375bounds.expand_to(vertex);376}377}378for (const ProjectedObstruction &projected_obstruction : _projected_obstructions) {379for (int i = 0; i < projected_obstruction.vertices.size() / 3; i++) {380const Vector3 vertex = Vector3(projected_obstruction.vertices[i * 3], projected_obstruction.vertices[i * 3 + 1], projected_obstruction.vertices[i * 3 + 2]);381if (first_vertex) {382first_vertex = false;383bounds.position = vertex;384} else {385bounds.expand_to(vertex);386}387}388}389} else {390geometry_rwlock.read_unlock();391}392393RWLockRead read_lock(geometry_rwlock);394return bounds;395}396397void NavigationMeshSourceGeometryData3D::_bind_methods() {398ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationMeshSourceGeometryData3D::set_vertices);399ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationMeshSourceGeometryData3D::get_vertices);400401ClassDB::bind_method(D_METHOD("set_indices", "indices"), &NavigationMeshSourceGeometryData3D::set_indices);402ClassDB::bind_method(D_METHOD("get_indices"), &NavigationMeshSourceGeometryData3D::get_indices);403404ClassDB::bind_method(D_METHOD("append_arrays", "vertices", "indices"), &NavigationMeshSourceGeometryData3D::append_arrays);405406ClassDB::bind_method(D_METHOD("clear"), &NavigationMeshSourceGeometryData3D::clear);407ClassDB::bind_method(D_METHOD("has_data"), &NavigationMeshSourceGeometryData3D::has_data);408409ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "xform"), &NavigationMeshSourceGeometryData3D::add_mesh);410ClassDB::bind_method(D_METHOD("add_mesh_array", "mesh_array", "xform"), &NavigationMeshSourceGeometryData3D::add_mesh_array);411ClassDB::bind_method(D_METHOD("add_faces", "faces", "xform"), &NavigationMeshSourceGeometryData3D::add_faces);412ClassDB::bind_method(D_METHOD("merge", "other_geometry"), &NavigationMeshSourceGeometryData3D::merge);413414ClassDB::bind_method(D_METHOD("add_projected_obstruction", "vertices", "elevation", "height", "carve"), &NavigationMeshSourceGeometryData3D::add_projected_obstruction);415ClassDB::bind_method(D_METHOD("clear_projected_obstructions"), &NavigationMeshSourceGeometryData3D::clear_projected_obstructions);416ClassDB::bind_method(D_METHOD("set_projected_obstructions", "projected_obstructions"), &NavigationMeshSourceGeometryData3D::set_projected_obstructions);417ClassDB::bind_method(D_METHOD("get_projected_obstructions"), &NavigationMeshSourceGeometryData3D::get_projected_obstructions);418419ClassDB::bind_method(D_METHOD("get_bounds"), &NavigationMeshSourceGeometryData3D::get_bounds);420421ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");422ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "indices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_indices", "get_indices");423ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "projected_obstructions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_projected_obstructions", "get_projected_obstructions");424}425426427