room_manager.cpp 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281
  1. /*************************************************************************/
  2. /* room_manager.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "room_manager.h"
  31. #include "core/bitfield_dynamic.h"
  32. #include "core/engine.h"
  33. #include "core/math/quick_hull.h"
  34. #include "core/os/os.h"
  35. #include "editor/editor_node.h"
  36. #include "mesh_instance.h"
  37. #include "multimesh_instance.h"
  38. #include "portal.h"
  39. #include "room_group.h"
  40. #include "scene/3d/camera.h"
  41. #include "scene/3d/light.h"
  42. #include "scene/3d/sprite_3d.h"
  43. #include "visibility_notifier.h"
  44. #ifdef TOOLS_ENABLED
  45. #include "editor/plugins/spatial_editor_plugin.h"
  46. #endif
  47. #include "modules/modules_enabled.gen.h" // For csg.
  48. #ifdef MODULE_CSG_ENABLED
  49. #include "modules/csg/csg_shape.h"
  50. #endif
  51. // #define GODOT_PORTALS_USE_BULLET_CONVEX_HULL
  52. #ifdef GODOT_PORTALS_USE_BULLET_CONVEX_HULL
  53. #include "core/math/convex_hull.h"
  54. #endif
  55. // This needs to be static because it cannot easily be propagated to portals
  56. // during load (as the RoomManager may be loaded before Portals enter the scene tree)
  57. real_t RoomManager::_default_portal_margin = 1.0;
  58. #ifdef TOOLS_ENABLED
  59. RoomManager *RoomManager::active_room_manager = nullptr;
  60. // static versions of functions for use from editor toolbars
  61. void RoomManager::static_rooms_set_active(bool p_active) {
  62. if (active_room_manager) {
  63. active_room_manager->rooms_set_active(p_active);
  64. active_room_manager->property_list_changed_notify();
  65. }
  66. }
  67. bool RoomManager::static_rooms_get_active() {
  68. if (active_room_manager) {
  69. return active_room_manager->rooms_get_active();
  70. }
  71. return false;
  72. }
  73. bool RoomManager::static_rooms_get_active_and_loaded() {
  74. if (active_room_manager) {
  75. if (active_room_manager->rooms_get_active()) {
  76. Ref<World> world = active_room_manager->get_world();
  77. RID scenario = world->get_scenario();
  78. return active_room_manager->rooms_get_active() && VisualServer::get_singleton()->rooms_is_loaded(scenario);
  79. }
  80. }
  81. return false;
  82. }
  83. void RoomManager::static_rooms_convert() {
  84. if (active_room_manager) {
  85. return active_room_manager->rooms_convert();
  86. }
  87. }
  88. #endif
  89. RoomManager::RoomManager() {
  90. // some high value, we want room manager to be processed after other
  91. // nodes because the camera should be moved first
  92. set_process_priority(10000);
  93. }
  94. RoomManager::~RoomManager() {
  95. }
  96. String RoomManager::get_configuration_warning() const {
  97. String warning = Spatial::get_configuration_warning();
  98. if (_settings_path_roomlist == NodePath()) {
  99. if (!warning.empty()) {
  100. warning += "\n\n";
  101. }
  102. warning += TTR("The RoomList has not been assigned.");
  103. } else {
  104. Spatial *roomlist = _resolve_path<Spatial>(_settings_path_roomlist);
  105. if (!roomlist) {
  106. // possibly also check (roomlist->get_class_name() != StringName("Spatial"))
  107. if (!warning.empty()) {
  108. warning += "\n\n";
  109. }
  110. warning += TTR("The RoomList node should be a Spatial (or derived from Spatial).");
  111. }
  112. }
  113. if (_settings_portal_depth_limit == 0) {
  114. if (!warning.empty()) {
  115. warning += "\n\n";
  116. }
  117. warning += TTR("Portal Depth Limit is set to Zero.\nOnly the Room that the Camera is in will render.");
  118. }
  119. if (Room::detect_nodes_of_type<RoomManager>(this)) {
  120. if (!warning.empty()) {
  121. warning += "\n\n";
  122. }
  123. warning += TTR("There should only be one RoomManager in the SceneTree.");
  124. }
  125. return warning;
  126. }
  127. void RoomManager::_preview_camera_update() {
  128. Ref<World> world = get_world();
  129. RID scenario = world->get_scenario();
  130. if (_godot_preview_camera_ID != (ObjectID)-1) {
  131. Camera *cam = Object::cast_to<Camera>(ObjectDB::get_instance(_godot_preview_camera_ID));
  132. if (!cam) {
  133. _godot_preview_camera_ID = (ObjectID)-1;
  134. } else {
  135. // get camera position and direction
  136. Vector3 camera_pos = cam->get_global_transform().origin;
  137. Vector<Plane> planes = cam->get_frustum();
  138. // only update the visual server when there is a change.. as it will request a screen redraw
  139. // this is kinda silly, but the other way would be keeping track of the override camera in visual server
  140. // and tracking the camera deletes, which might be more error prone for a debug feature...
  141. bool changed = false;
  142. if (camera_pos != _godot_camera_pos) {
  143. changed = true;
  144. }
  145. // check planes
  146. if (!changed) {
  147. if (planes.size() != _godot_camera_planes.size()) {
  148. changed = true;
  149. }
  150. }
  151. if (!changed) {
  152. // num of planes must be identical
  153. for (int n = 0; n < planes.size(); n++) {
  154. if (planes[n] != _godot_camera_planes[n]) {
  155. changed = true;
  156. break;
  157. }
  158. }
  159. }
  160. if (changed) {
  161. _godot_camera_pos = camera_pos;
  162. _godot_camera_planes = planes;
  163. VisualServer::get_singleton()->rooms_override_camera(scenario, true, camera_pos, &planes);
  164. }
  165. }
  166. }
  167. }
  168. void RoomManager::_notification(int p_what) {
  169. switch (p_what) {
  170. case NOTIFICATION_ENTER_TREE: {
  171. if (Engine::get_singleton()->is_editor_hint()) {
  172. set_process_internal(_godot_preview_camera_ID != (ObjectID)-1);
  173. #ifdef TOOLS_ENABLED
  174. // note this mechanism may fail to work correctly if the user creates two room managers,
  175. // but should not create major problems as it is just used to auto update when portals etc
  176. // are changed in the editor, and there is a check for nullptr.
  177. active_room_manager = this;
  178. SpatialEditor *spatial_editor = SpatialEditor::get_singleton();
  179. if (spatial_editor) {
  180. spatial_editor->update_portal_tools();
  181. }
  182. #endif
  183. } else {
  184. if (_settings_gameplay_monitor_enabled) {
  185. set_process_internal(true);
  186. }
  187. }
  188. } break;
  189. case NOTIFICATION_EXIT_TREE: {
  190. #ifdef TOOLS_ENABLED
  191. active_room_manager = nullptr;
  192. if (Engine::get_singleton()->is_editor_hint()) {
  193. SpatialEditor *spatial_editor = SpatialEditor::get_singleton();
  194. if (spatial_editor) {
  195. spatial_editor->update_portal_tools();
  196. }
  197. }
  198. #endif
  199. } break;
  200. case NOTIFICATION_INTERNAL_PROCESS: {
  201. // can't call visual server if not inside world
  202. if (!is_inside_world()) {
  203. return;
  204. }
  205. if (Engine::get_singleton()->is_editor_hint()) {
  206. _preview_camera_update();
  207. return;
  208. }
  209. if (_settings_gameplay_monitor_enabled) {
  210. Ref<World> world = get_world();
  211. RID scenario = world->get_scenario();
  212. List<Camera *> cameras;
  213. world->get_camera_list(&cameras);
  214. Vector<Vector3> positions;
  215. for (int n = 0; n < cameras.size(); n++) {
  216. positions.push_back(cameras[n]->get_global_transform().origin);
  217. }
  218. VisualServer::get_singleton()->rooms_update_gameplay_monitor(scenario, positions);
  219. }
  220. } break;
  221. }
  222. }
  223. void RoomManager::_bind_methods() {
  224. BIND_ENUM_CONSTANT(PVS_MODE_DISABLED);
  225. BIND_ENUM_CONSTANT(PVS_MODE_PARTIAL);
  226. BIND_ENUM_CONSTANT(PVS_MODE_FULL);
  227. // main functions
  228. ClassDB::bind_method(D_METHOD("rooms_convert"), &RoomManager::rooms_convert);
  229. ClassDB::bind_method(D_METHOD("rooms_clear"), &RoomManager::rooms_clear);
  230. ClassDB::bind_method(D_METHOD("set_pvs_mode", "pvs_mode"), &RoomManager::set_pvs_mode);
  231. ClassDB::bind_method(D_METHOD("get_pvs_mode"), &RoomManager::get_pvs_mode);
  232. ClassDB::bind_method(D_METHOD("set_roomlist_path", "p_path"), &RoomManager::set_roomlist_path);
  233. ClassDB::bind_method(D_METHOD("get_roomlist_path"), &RoomManager::get_roomlist_path);
  234. // These are commented out for now, but available in case we want to cache PVS to disk, the functionality exists
  235. // ClassDB::bind_method(D_METHOD("set_pvs_filename", "pvs_filename"), &RoomManager::set_pvs_filename);
  236. // ClassDB::bind_method(D_METHOD("get_pvs_filename"), &RoomManager::get_pvs_filename);
  237. // just some macros to make setting inspector values easier
  238. #define LPORTAL_STRINGIFY(x) #x
  239. #define LPORTAL_TOSTRING(x) LPORTAL_STRINGIFY(x)
  240. #define LIMPL_PROPERTY(P_TYPE, P_NAME, P_SET, P_GET) \
  241. ClassDB::bind_method(D_METHOD(LPORTAL_TOSTRING(P_SET), LPORTAL_TOSTRING(P_NAME)), &RoomManager::P_SET); \
  242. ClassDB::bind_method(D_METHOD(LPORTAL_TOSTRING(P_GET)), &RoomManager::P_GET); \
  243. ADD_PROPERTY(PropertyInfo(P_TYPE, LPORTAL_TOSTRING(P_NAME)), LPORTAL_TOSTRING(P_SET), LPORTAL_TOSTRING(P_GET));
  244. #define LIMPL_PROPERTY_RANGE(P_TYPE, P_NAME, P_SET, P_GET, P_RANGE_STRING) \
  245. ClassDB::bind_method(D_METHOD(LPORTAL_TOSTRING(P_SET), LPORTAL_TOSTRING(P_NAME)), &RoomManager::P_SET); \
  246. ClassDB::bind_method(D_METHOD(LPORTAL_TOSTRING(P_GET)), &RoomManager::P_GET); \
  247. ADD_PROPERTY(PropertyInfo(P_TYPE, LPORTAL_TOSTRING(P_NAME), PROPERTY_HINT_RANGE, P_RANGE_STRING), LPORTAL_TOSTRING(P_SET), LPORTAL_TOSTRING(P_GET));
  248. ADD_GROUP("Main", "");
  249. LIMPL_PROPERTY(Variant::BOOL, active, rooms_set_active, rooms_get_active);
  250. ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "roomlist", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"), "set_roomlist_path", "get_roomlist_path");
  251. ADD_GROUP("PVS", "");
  252. ADD_PROPERTY(PropertyInfo(Variant::INT, "pvs_mode", PROPERTY_HINT_ENUM, "Disabled,Partial,Full"), "set_pvs_mode", "get_pvs_mode");
  253. // ADD_PROPERTY(PropertyInfo(Variant::STRING, "pvs_filename", PROPERTY_HINT_FILE, "*.pvs"), "set_pvs_filename", "get_pvs_filename");
  254. ADD_GROUP("Gameplay", "");
  255. LIMPL_PROPERTY(Variant::BOOL, gameplay_monitor, set_gameplay_monitor_enabled, get_gameplay_monitor_enabled);
  256. LIMPL_PROPERTY(Variant::BOOL, use_secondary_pvs, set_use_secondary_pvs, get_use_secondary_pvs);
  257. ADD_GROUP("Optimize", "");
  258. LIMPL_PROPERTY(Variant::BOOL, merge_meshes, set_merge_meshes, get_merge_meshes);
  259. ADD_GROUP("Debug", "");
  260. LIMPL_PROPERTY(Variant::BOOL, show_margins, set_show_margins, get_show_margins);
  261. LIMPL_PROPERTY(Variant::BOOL, debug_sprawl, set_debug_sprawl, get_debug_sprawl);
  262. LIMPL_PROPERTY_RANGE(Variant::INT, overlap_warning_threshold, set_overlap_warning_threshold, get_overlap_warning_threshold, "1,1000,1");
  263. LIMPL_PROPERTY(Variant::NODE_PATH, preview_camera, set_preview_camera_path, get_preview_camera_path);
  264. ADD_GROUP("Advanced", "");
  265. LIMPL_PROPERTY_RANGE(Variant::INT, portal_depth_limit, set_portal_depth_limit, get_portal_depth_limit, "0,255,1");
  266. LIMPL_PROPERTY_RANGE(Variant::REAL, room_simplify, set_room_simplify, get_room_simplify, "0.0,1.0,0.005");
  267. LIMPL_PROPERTY_RANGE(Variant::REAL, default_portal_margin, set_default_portal_margin, get_default_portal_margin, "0.0, 10.0, 0.01");
  268. LIMPL_PROPERTY_RANGE(Variant::REAL, roaming_expansion_margin, set_roaming_expansion_margin, get_roaming_expansion_margin, "0.0, 3.0, 0.01");
  269. #undef LIMPL_PROPERTY
  270. #undef LIMPL_PROPERTY_RANGE
  271. #undef LPORTAL_STRINGIFY
  272. #undef LPORTAL_TOSTRING
  273. }
  274. void RoomManager::_refresh_from_project_settings() {
  275. _settings_use_simple_pvs = GLOBAL_GET("rendering/portals/pvs/use_simple_pvs");
  276. _settings_log_pvs_generation = GLOBAL_GET("rendering/portals/pvs/pvs_logging");
  277. _settings_use_signals = GLOBAL_GET("rendering/portals/gameplay/use_signals");
  278. _settings_remove_danglers = GLOBAL_GET("rendering/portals/optimize/remove_danglers");
  279. _show_debug = GLOBAL_GET("rendering/portals/debug/logging");
  280. Portal::_portal_plane_convention = GLOBAL_GET("rendering/portals/advanced/flip_imported_portals");
  281. // force not to show logs when not in editor
  282. if (!Engine::get_singleton()->is_editor_hint()) {
  283. _show_debug = false;
  284. _settings_log_pvs_generation = false;
  285. }
  286. }
  287. void RoomManager::set_roomlist_path(const NodePath &p_path) {
  288. _settings_path_roomlist = p_path;
  289. update_configuration_warning();
  290. }
  291. void RoomManager::set_preview_camera_path(const NodePath &p_path) {
  292. _settings_path_preview_camera = p_path;
  293. resolve_preview_camera_path();
  294. bool camera_on = _godot_preview_camera_ID != (ObjectID)-1;
  295. // make sure the cached camera planes are invalid, this will
  296. // force an update to the visual server on the next internal_process
  297. _godot_camera_planes.clear();
  298. // if in the editor, turn processing on or off
  299. // according to whether the camera is overridden
  300. if (Engine::get_singleton()->is_editor_hint()) {
  301. if (is_inside_tree()) {
  302. set_process_internal(camera_on);
  303. }
  304. }
  305. // if we are turning camera override off, must inform visual server
  306. if (!camera_on && is_inside_world() && get_world().is_valid() && get_world()->get_scenario().is_valid()) {
  307. VisualServer::get_singleton()->rooms_override_camera(get_world()->get_scenario(), false, Vector3(), nullptr);
  308. }
  309. // we couldn't resolve the path, let's set it to null
  310. if (!camera_on) {
  311. _settings_path_preview_camera = NodePath();
  312. }
  313. }
  314. void RoomManager::set_room_simplify(real_t p_value) {
  315. _room_simplify_info.set_simplify(p_value);
  316. }
  317. real_t RoomManager::get_room_simplify() const {
  318. return _room_simplify_info._plane_simplify;
  319. }
  320. void RoomManager::set_portal_depth_limit(int p_limit) {
  321. _settings_portal_depth_limit = p_limit;
  322. if (is_inside_world() && get_world().is_valid()) {
  323. VisualServer::get_singleton()->rooms_set_params(get_world()->get_scenario(), p_limit, _settings_roaming_expansion_margin);
  324. }
  325. }
  326. void RoomManager::set_roaming_expansion_margin(real_t p_dist) {
  327. _settings_roaming_expansion_margin = p_dist;
  328. if (is_inside_world() && get_world().is_valid()) {
  329. VisualServer::get_singleton()->rooms_set_params(get_world()->get_scenario(), _settings_portal_depth_limit, _settings_roaming_expansion_margin);
  330. }
  331. }
  332. void RoomManager::set_default_portal_margin(real_t p_dist) {
  333. _default_portal_margin = p_dist;
  334. // send to portals
  335. Spatial *roomlist = _resolve_path<Spatial>(_settings_path_roomlist);
  336. if (!roomlist) {
  337. return;
  338. }
  339. _update_portal_gizmos(roomlist);
  340. }
  341. void RoomManager::_update_portal_gizmos(Spatial *p_node) {
  342. Portal *portal = Object::cast_to<Portal>(p_node);
  343. if (portal) {
  344. portal->update_gizmo();
  345. }
  346. // recurse
  347. for (int n = 0; n < p_node->get_child_count(); n++) {
  348. Spatial *child = Object::cast_to<Spatial>(p_node->get_child(n));
  349. if (child) {
  350. _update_portal_gizmos(child);
  351. }
  352. }
  353. }
  354. real_t RoomManager::get_default_portal_margin() const {
  355. return _default_portal_margin;
  356. }
  357. void RoomManager::set_show_margins(bool p_show) {
  358. Portal::_settings_gizmo_show_margins = p_show;
  359. Spatial *roomlist = _resolve_path<Spatial>(_settings_path_roomlist);
  360. if (!roomlist) {
  361. return;
  362. }
  363. _update_gizmos_recursive(roomlist);
  364. }
  365. bool RoomManager::get_show_margins() const {
  366. return Portal::_settings_gizmo_show_margins;
  367. }
  368. void RoomManager::set_debug_sprawl(bool p_enable) {
  369. if (is_inside_world() && get_world().is_valid()) {
  370. VisualServer::get_singleton()->rooms_set_debug_feature(get_world()->get_scenario(), VisualServer::ROOMS_DEBUG_SPRAWL, p_enable);
  371. _debug_sprawl = p_enable;
  372. }
  373. }
  374. bool RoomManager::get_debug_sprawl() const {
  375. return _debug_sprawl;
  376. }
  377. void RoomManager::set_merge_meshes(bool p_enable) {
  378. _settings_merge_meshes = p_enable;
  379. }
  380. bool RoomManager::get_merge_meshes() const {
  381. return _settings_merge_meshes;
  382. }
  383. void RoomManager::show_warning(const String &p_string, const String &p_extra_string, bool p_alert) {
  384. if (p_extra_string != "") {
  385. WARN_PRINT(p_string + " " + p_extra_string);
  386. #ifdef TOOLS_ENABLED
  387. if (p_alert && Engine::get_singleton()->is_editor_hint()) {
  388. EditorNode::get_singleton()->show_warning(TTRGET(p_string) + "\n" + TTRGET(p_extra_string));
  389. }
  390. #endif
  391. } else {
  392. WARN_PRINT(p_string);
  393. // OS::get_singleton()->alert(p_string, p_title);
  394. #ifdef TOOLS_ENABLED
  395. if (p_alert && Engine::get_singleton()->is_editor_hint()) {
  396. EditorNode::get_singleton()->show_warning(TTRGET(p_string));
  397. }
  398. #endif
  399. }
  400. }
  401. void RoomManager::debug_print_line(String p_string, int p_priority) {
  402. if (_show_debug) {
  403. if (!p_priority) {
  404. print_verbose(p_string);
  405. } else {
  406. print_line(p_string);
  407. }
  408. }
  409. }
  410. void RoomManager::rooms_set_active(bool p_active) {
  411. if (is_inside_world() && get_world().is_valid()) {
  412. VisualServer::get_singleton()->rooms_set_active(get_world()->get_scenario(), p_active);
  413. _active = p_active;
  414. #ifdef TOOLS_ENABLED
  415. if (Engine::get_singleton()->is_editor_hint()) {
  416. SpatialEditor *spatial_editor = SpatialEditor::get_singleton();
  417. if (spatial_editor) {
  418. spatial_editor->update_portal_tools();
  419. }
  420. }
  421. #endif
  422. }
  423. }
  424. bool RoomManager::rooms_get_active() const {
  425. return _active;
  426. }
  427. void RoomManager::set_pvs_mode(PVSMode p_mode) {
  428. _pvs_mode = p_mode;
  429. }
  430. RoomManager::PVSMode RoomManager::get_pvs_mode() const {
  431. return _pvs_mode;
  432. }
  433. void RoomManager::set_pvs_filename(String p_filename) {
  434. _pvs_filename = p_filename;
  435. }
  436. String RoomManager::get_pvs_filename() const {
  437. return _pvs_filename;
  438. }
  439. void RoomManager::_rooms_changed(String p_reason) {
  440. _rooms.clear();
  441. if (is_inside_world() && get_world().is_valid()) {
  442. VisualServer::get_singleton()->rooms_unload(get_world()->get_scenario(), p_reason);
  443. }
  444. }
  445. void RoomManager::rooms_clear() {
  446. _rooms.clear();
  447. if (is_inside_world() && get_world().is_valid()) {
  448. VisualServer::get_singleton()->rooms_and_portals_clear(get_world()->get_scenario());
  449. }
  450. }
  451. void RoomManager::rooms_flip_portals() {
  452. // this is a helper emergency function to deal with situations where the user has ended up with Portal nodes
  453. // pointing in the wrong direction (by doing initial conversion with flip_portal_meshes set incorrectly).
  454. _roomlist = _resolve_path<Spatial>(_settings_path_roomlist);
  455. if (!_roomlist) {
  456. WARN_PRINT("Cannot resolve nodepath");
  457. show_warning(TTR("RoomList path is invalid.\nPlease check the RoomList branch has been assigned in the RoomManager."));
  458. return;
  459. }
  460. _flip_portals_recursive(_roomlist);
  461. _rooms_changed("flipped Portals");
  462. }
  463. void RoomManager::rooms_convert() {
  464. // set all error conditions to false
  465. _warning_misnamed_nodes_detected = false;
  466. _warning_portal_link_room_not_found = false;
  467. _warning_portal_autolink_failed = false;
  468. _warning_room_overlap_detected = false;
  469. _refresh_from_project_settings();
  470. _roomlist = _resolve_path<Spatial>(_settings_path_roomlist);
  471. if (!_roomlist) {
  472. WARN_PRINT("Cannot resolve nodepath");
  473. show_warning(TTR("RoomList path is invalid.\nPlease check the RoomList branch has been assigned in the RoomManager."));
  474. return;
  475. }
  476. ERR_FAIL_COND(!is_inside_world() || !get_world().is_valid());
  477. // every time we run convert we increment this,
  478. // to prevent individual rooms / portals being converted
  479. // more than once in one run
  480. _conversion_tick++;
  481. rooms_clear();
  482. // first check that the roomlist is valid, and the user hasn't made
  483. // a silly scene tree
  484. if (!_check_roomlist_validity(_roomlist)) {
  485. return;
  486. }
  487. LocalVector<Portal *> portals;
  488. LocalVector<RoomGroup *> roomgroups;
  489. // find the rooms and portals
  490. _convert_rooms_recursive(_roomlist, portals, roomgroups);
  491. if (!_rooms.size()) {
  492. rooms_clear();
  493. show_warning(TTR("RoomList contains no Rooms, aborting."));
  494. return;
  495. }
  496. // add portal links
  497. _second_pass_portals(_roomlist, portals);
  498. // create the statics
  499. _second_pass_rooms(roomgroups, portals);
  500. // third pass
  501. // autolink portals that are not already manually linked
  502. // and finalize the portals
  503. _autolink_portals(_roomlist, portals);
  504. // Find the statics AGAIN and only this time add them to the PortalRenderer.
  505. // We need to do this twice because the room points determine the room bound...
  506. // but the bound is needed for autolinking,
  507. // and the autolinking needs to be done BEFORE adding to the PortalRenderer so that
  508. // the static objects will correctly sprawl. It is a chicken and egg situation.
  509. // Also finalize the room hulls.
  510. _third_pass_rooms(portals);
  511. // now we run autoplace to place any statics that have not been explicitly placed in rooms.
  512. // These will by definition not affect the room bounds, but is convenient for users to edit
  513. // levels in a more freeform manner
  514. _autoplace_recursive(_roomlist);
  515. bool generate_pvs = false;
  516. bool pvs_cull = false;
  517. switch (_pvs_mode) {
  518. default: {
  519. } break;
  520. case PVS_MODE_PARTIAL: {
  521. generate_pvs = true;
  522. } break;
  523. case PVS_MODE_FULL: {
  524. generate_pvs = true;
  525. pvs_cull = true;
  526. } break;
  527. }
  528. VisualServer::get_singleton()->rooms_finalize(get_world()->get_scenario(), generate_pvs, pvs_cull, _settings_use_secondary_pvs, _settings_use_signals, _pvs_filename, _settings_use_simple_pvs, _settings_log_pvs_generation);
  529. // refresh portal depth limit
  530. set_portal_depth_limit(get_portal_depth_limit());
  531. #ifdef TOOLS_ENABLED
  532. _generate_room_overlap_zones();
  533. #endif
  534. // just delete any intermediate data
  535. _cleanup_after_conversion();
  536. // display error dialogs
  537. if (_warning_misnamed_nodes_detected) {
  538. show_warning(TTR("Misnamed nodes detected, check output log for details. Aborting."));
  539. rooms_clear();
  540. }
  541. if (_warning_portal_link_room_not_found) {
  542. show_warning(TTR("Portal link room not found, check output log for details."));
  543. }
  544. if (_warning_portal_autolink_failed) {
  545. show_warning(TTR("Portal autolink failed, check output log for details.\nCheck the portal is facing outwards from the source room."));
  546. }
  547. if (_warning_room_overlap_detected) {
  548. show_warning(TTR("Room overlap detected, cameras may work incorrectly in overlapping area.\nCheck output log for details."));
  549. }
  550. }
  551. void RoomManager::_second_pass_room(Room *p_room, const LocalVector<RoomGroup *> &p_roomgroups, const LocalVector<Portal *> &p_portals) {
  552. if (_settings_merge_meshes) {
  553. _merge_meshes_in_room(p_room);
  554. }
  555. // find statics and manual bound
  556. bool manual_bound_found = false;
  557. // points making up the room geometry, in world space, to create the convex hull
  558. Vector<Vector3> room_pts;
  559. for (int n = 0; n < p_room->get_child_count(); n++) {
  560. Spatial *child = Object::cast_to<Spatial>(p_room->get_child(n));
  561. if (child) {
  562. if (_node_is_type<Portal>(child) || child->is_queued_for_deletion()) {
  563. // the adding of portal points is done after this stage, because
  564. // we need to take into account incoming as well as outgoing portals
  565. } else if (_name_ends_with(child, "-bound")) {
  566. manual_bound_found = _convert_manual_bound(p_room, child, p_portals);
  567. } else {
  568. // don't add the instances to the portal renderer on the first pass of _find_statics,
  569. // just find the geometry points in order to make sure the bound is correct.
  570. _find_statics_recursive(p_room, child, room_pts, false);
  571. }
  572. }
  573. }
  574. // Has the bound been specified using points in the room?
  575. // in that case, overwrite the room_pts
  576. if (p_room->_bound_pts.size() && p_room->is_inside_tree()) {
  577. Transform tr = p_room->get_global_transform();
  578. room_pts.clear();
  579. room_pts.resize(p_room->_bound_pts.size());
  580. for (int n = 0; n < room_pts.size(); n++) {
  581. room_pts.set(n, tr.xform(p_room->_bound_pts[n]));
  582. }
  583. // we override and manual bound with the room points
  584. manual_bound_found = false;
  585. }
  586. if (!manual_bound_found) {
  587. // rough aabb for checking portals for warning conditions
  588. AABB aabb;
  589. aabb.create_from_points(room_pts);
  590. for (int n = 0; n < p_room->_portals.size(); n++) {
  591. int portal_id = p_room->_portals[n];
  592. Portal *portal = p_portals[portal_id];
  593. // only checking portals out from source room
  594. if (portal->_linkedroom_ID[0] != p_room->_room_ID) {
  595. continue;
  596. }
  597. // don't add portals to the world bound that are internal to this room!
  598. if (portal->is_portal_internal(p_room->_room_ID)) {
  599. continue;
  600. }
  601. // check portal for suspect conditions, like a long way from the room AABB,
  602. // or possibly flipped the wrong way
  603. _check_portal_for_warnings(portal, aabb);
  604. }
  605. // create convex hull
  606. _convert_room_hull_preliminary(p_room, room_pts, p_portals);
  607. }
  608. // add the room to roomgroups
  609. for (int n = 0; n < p_room->_roomgroups.size(); n++) {
  610. int roomgroup_id = p_room->_roomgroups[n];
  611. p_roomgroups[roomgroup_id]->add_room(p_room);
  612. }
  613. }
  614. void RoomManager::_second_pass_rooms(const LocalVector<RoomGroup *> &p_roomgroups, const LocalVector<Portal *> &p_portals) {
  615. for (int n = 0; n < _rooms.size(); n++) {
  616. _second_pass_room(_rooms[n], p_roomgroups, p_portals);
  617. }
  618. }
  619. #ifdef TOOLS_ENABLED
  620. void RoomManager::_generate_room_overlap_zones() {
  621. for (int n = 0; n < _rooms.size(); n++) {
  622. Room *room = _rooms[n];
  623. // no planes .. no overlap
  624. if (!room->_planes.size()) {
  625. continue;
  626. }
  627. for (int c = n + 1; c < _rooms.size(); c++) {
  628. if (c == n) {
  629. continue;
  630. }
  631. Room *other = _rooms[c];
  632. // do a quick reject AABB
  633. if (!room->_aabb.intersects(other->_aabb) || (!other->_planes.size())) {
  634. continue;
  635. }
  636. // if the room priorities are different (i.e. an internal room), they are allowed to overlap
  637. if (room->_room_priority != other->_room_priority) {
  638. continue;
  639. }
  640. // get all the planes of both rooms in a contiguous list
  641. LocalVector<Plane, int32_t> planes;
  642. planes.resize(room->_planes.size() + other->_planes.size());
  643. Plane *dest = planes.ptr();
  644. memcpy(dest, &room->_planes[0], room->_planes.size() * sizeof(Plane));
  645. dest += room->_planes.size();
  646. memcpy(dest, &other->_planes[0], other->_planes.size() * sizeof(Plane));
  647. Vector<Vector3> overlap_pts = Geometry::compute_convex_mesh_points(planes.ptr(), planes.size());
  648. if (overlap_pts.size() < 4) {
  649. continue;
  650. }
  651. // there is an overlap, create a mesh from the points
  652. Geometry::MeshData md;
  653. Error err = _build_convex_hull(overlap_pts, md);
  654. if (err != OK) {
  655. WARN_PRINT("QuickHull failed building room overlap hull");
  656. continue;
  657. }
  658. // only if the volume is more than some threshold
  659. real_t volume = Geometry::calculate_convex_hull_volume(md);
  660. if (volume > _overlap_warning_threshold) {
  661. WARN_PRINT("Room overlap of " + String(Variant(volume)) + " detected between " + room->get_name() + " and " + other->get_name());
  662. room->_gizmo_overlap_zones.push_back(md);
  663. _warning_room_overlap_detected = true;
  664. }
  665. }
  666. }
  667. }
  668. #endif
  669. void RoomManager::_third_pass_rooms(const LocalVector<Portal *> &p_portals) {
  670. bool found_errors = false;
  671. for (int n = 0; n < _rooms.size(); n++) {
  672. Room *room = _rooms[n];
  673. // no need to do all these string operations if we are not debugging and don't need logs
  674. if (_show_debug) {
  675. String room_short_name = _find_name_before(room, "-room", true);
  676. convert_log("ROOM\t" + room_short_name);
  677. // log output the portals associated with this room
  678. for (int p = 0; p < room->_portals.size(); p++) {
  679. const Portal &portal = *p_portals[room->_portals[p]];
  680. bool portal_links_out = portal._linkedroom_ID[0] == room->_room_ID;
  681. int linked_room_id = (portal_links_out) ? portal._linkedroom_ID[1] : portal._linkedroom_ID[0];
  682. // this shouldn't be out of range, but just in case
  683. if ((linked_room_id >= 0) && (linked_room_id < _rooms.size())) {
  684. Room *linked_room = _rooms[linked_room_id];
  685. String portal_link_room_name = _find_name_before(linked_room, "-room", true);
  686. String in_or_out = (portal_links_out) ? "POUT" : "PIN ";
  687. // display the name of the room linked to
  688. convert_log("\t\t" + in_or_out + "\t" + portal_link_room_name);
  689. } else {
  690. WARN_PRINT_ONCE("linked_room_id is out of range");
  691. }
  692. }
  693. } // if _show_debug
  694. // do a second pass finding the statics, where they are
  695. // finally added to the rooms in the portal_renderer.
  696. Vector<Vector3> room_pts;
  697. // the true indicates we DO want to add to the portal renderer this second time
  698. // we call _find_statics_recursive
  699. _find_statics_recursive(room, room, room_pts, true);
  700. if (!_convert_room_hull_final(room, p_portals)) {
  701. found_errors = true;
  702. }
  703. room->update_gizmo();
  704. room->update_configuration_warning();
  705. }
  706. if (found_errors) {
  707. show_warning(TTR("Error calculating room bounds.\nEnsure all rooms contain geometry or manual bounds."));
  708. }
  709. }
  710. void RoomManager::_second_pass_portals(Spatial *p_roomlist, LocalVector<Portal *> &r_portals) {
  711. for (unsigned int n = 0; n < r_portals.size(); n++) {
  712. Portal *portal = r_portals[n];
  713. // we have a choice here.
  714. // If we are importing, we will try linking using the naming convention method.
  715. // We do this by setting the assigned nodepath if we find the link room, then
  716. // the resolving links is done in the usual manner from the nodepath.
  717. if (portal->_importing_portal) {
  718. String string_link_room_shortname = _find_name_before(portal, "-portal");
  719. String string_link_room = string_link_room_shortname + "-room";
  720. if (string_link_room_shortname != "") {
  721. // try the room name plus the postfix first, this will be the most common case during import
  722. Room *linked_room = Object::cast_to<Room>(p_roomlist->find_node(string_link_room, true, false));
  723. // try the short name as a last ditch attempt
  724. if (!linked_room) {
  725. linked_room = Object::cast_to<Room>(p_roomlist->find_node(string_link_room_shortname, true, false));
  726. }
  727. if (linked_room) {
  728. NodePath path = portal->get_path_to(linked_room);
  729. portal->set_linked_room_internal(path);
  730. } else {
  731. WARN_PRINT("Portal link room : " + string_link_room + " not found.");
  732. _warning_portal_link_room_not_found = true;
  733. }
  734. }
  735. }
  736. // get the room we are linking from
  737. int room_from_id = portal->_linkedroom_ID[0];
  738. if (room_from_id != -1) {
  739. Room *room_from = _rooms[room_from_id];
  740. portal->resolve_links(_rooms, room_from->_room_rid);
  741. // add the portal id to the room from and the room to.
  742. // These are used so we can later add the portal geometry to the room bounds.
  743. room_from->_portals.push_back(n);
  744. int room_to_id = portal->_linkedroom_ID[1];
  745. if (room_to_id != -1) {
  746. Room *room_to = _rooms[room_to_id];
  747. room_to->_portals.push_back(n);
  748. // make the portal internal if necessary
  749. portal->_internal = room_from->_room_priority > room_to->_room_priority;
  750. }
  751. }
  752. }
  753. }
  754. void RoomManager::_autolink_portals(Spatial *p_roomlist, LocalVector<Portal *> &r_portals) {
  755. for (unsigned int n = 0; n < r_portals.size(); n++) {
  756. Portal *portal = r_portals[n];
  757. // all portals should have a source room
  758. DEV_ASSERT(portal->_linkedroom_ID[0] != -1);
  759. const Room *source_room = _rooms[portal->_linkedroom_ID[0]];
  760. if (portal->_linkedroom_ID[1] != -1) {
  761. // already manually linked
  762. continue;
  763. }
  764. bool autolink_found = false;
  765. // try to autolink
  766. // try points iteratively out from the portal center and find the first that is in a room that isn't the source room
  767. for (int attempt = 0; attempt < 4; attempt++) {
  768. // found
  769. if (portal->_linkedroom_ID[1] != -1) {
  770. break;
  771. }
  772. // these numbers are arbitrary .. we could alternatively reuse the portal margins for this?
  773. real_t dist = 0.01;
  774. switch (attempt) {
  775. default: {
  776. dist = 0.01;
  777. } break;
  778. case 1: {
  779. dist = 0.1;
  780. } break;
  781. case 2: {
  782. dist = 1.0;
  783. } break;
  784. case 3: {
  785. dist = 2.0;
  786. } break;
  787. }
  788. Vector3 test_pos = portal->_pt_center_world + (dist * portal->_plane.normal);
  789. int best_priority = -1000;
  790. int best_room = -1;
  791. for (int r = 0; r < _rooms.size(); r++) {
  792. Room *room = _rooms[r];
  793. if (room->_room_ID == portal->_linkedroom_ID[0]) {
  794. // can't link back to the source room
  795. continue;
  796. }
  797. // first do a rough aabb check
  798. if (!room->_aabb.has_point(test_pos)) {
  799. continue;
  800. }
  801. bool outside = false;
  802. for (int p = 0; p < room->_preliminary_planes.size(); p++) {
  803. const Plane &plane = room->_preliminary_planes[p];
  804. if (plane.distance_to(test_pos) > 0.0) {
  805. outside = true;
  806. break;
  807. }
  808. } // for through planes
  809. if (!outside) {
  810. // we found a suitable room, but we want the highest priority in
  811. // case there are internal rooms...
  812. if (room->_room_priority > best_priority) {
  813. best_priority = room->_room_priority;
  814. best_room = r;
  815. }
  816. }
  817. } // for through rooms
  818. // found a suitable link room
  819. if (best_room != -1) {
  820. Room *room = _rooms[best_room];
  821. // great, we found a linked room!
  822. convert_log("\t\tAUTOLINK OK from " + source_room->get_name() + " to " + room->get_name(), 1);
  823. portal->_linkedroom_ID[1] = best_room;
  824. // add the portal to the portals list for the receiving room
  825. room->_portals.push_back(n);
  826. // send complete link to visual server so the portal will be active in the visual server room system
  827. VisualServer::get_singleton()->portal_link(portal->_portal_rid, source_room->_room_rid, room->_room_rid, portal->_settings_two_way);
  828. // make the portal internal if necessary
  829. // (this prevents the portal plane clipping the room bound)
  830. portal->_internal = source_room->_room_priority > room->_room_priority;
  831. autolink_found = true;
  832. break;
  833. }
  834. } // for attempt
  835. // error condition
  836. if (!autolink_found) {
  837. WARN_PRINT("Portal AUTOLINK failed for " + portal->get_name() + " from " + source_room->get_name());
  838. _warning_portal_autolink_failed = true;
  839. #ifdef TOOLS_ENABLED
  840. portal->_warning_autolink_failed = true;
  841. portal->update_gizmo();
  842. #endif
  843. }
  844. } // for portal
  845. }
  846. // to prevent users creating mistakes for themselves, we limit what can be put into the room list branch.
  847. // returns invalid node, or NULL
  848. bool RoomManager::_check_roomlist_validity(Node *p_node) {
  849. // restrictions lifted here, but we can add more if required
  850. return true;
  851. }
  852. void RoomManager::_convert_rooms_recursive(Spatial *p_node, LocalVector<Portal *> &r_portals, LocalVector<RoomGroup *> &r_roomgroups, int p_roomgroup) {
  853. // is this a room?
  854. if (_node_is_type<Room>(p_node) || _name_ends_with(p_node, "-room")) {
  855. _convert_room(p_node, r_portals, r_roomgroups, p_roomgroup);
  856. }
  857. // is this a roomgroup?
  858. if (_node_is_type<RoomGroup>(p_node) || _name_ends_with(p_node, "-roomgroup")) {
  859. p_roomgroup = _convert_roomgroup(p_node, r_roomgroups);
  860. }
  861. // recurse through children
  862. for (int n = 0; n < p_node->get_child_count(); n++) {
  863. Spatial *child = Object::cast_to<Spatial>(p_node->get_child(n));
  864. if (child) {
  865. _convert_rooms_recursive(child, r_portals, r_roomgroups, p_roomgroup);
  866. }
  867. }
  868. }
  869. int RoomManager::_convert_roomgroup(Spatial *p_node, LocalVector<RoomGroup *> &r_roomgroups) {
  870. String string_full_name = p_node->get_name();
  871. // is it already a roomgroup?
  872. RoomGroup *roomgroup = Object::cast_to<RoomGroup>(p_node);
  873. // if not already a RoomGroup, convert the node and move all children
  874. if (!roomgroup) {
  875. // create a RoomGroup
  876. roomgroup = _change_node_type<RoomGroup>(p_node, "G");
  877. } else {
  878. // already hit this tick?
  879. if (roomgroup->_conversion_tick == _conversion_tick) {
  880. return roomgroup->_roomgroup_ID;
  881. }
  882. }
  883. convert_log("convert_roomgroup : " + string_full_name, 1);
  884. // make sure the roomgroup is blank, especially if already created
  885. roomgroup->clear();
  886. // make sure the object ID is sent to the visual server
  887. VisualServer::get_singleton()->roomgroup_prepare(roomgroup->_room_group_rid, roomgroup->get_instance_id());
  888. // mark so as only to convert once
  889. roomgroup->_conversion_tick = _conversion_tick;
  890. roomgroup->_roomgroup_ID = r_roomgroups.size();
  891. r_roomgroups.push_back(roomgroup);
  892. return r_roomgroups.size() - 1;
  893. }
  894. void RoomManager::_convert_room(Spatial *p_node, LocalVector<Portal *> &r_portals, const LocalVector<RoomGroup *> &p_roomgroups, int p_roomgroup) {
  895. String string_full_name = p_node->get_name();
  896. // is it already an lroom?
  897. Room *room = Object::cast_to<Room>(p_node);
  898. // if not already a Room, convert the node and move all children
  899. if (!room) {
  900. // create a Room
  901. room = _change_node_type<Room>(p_node, "G");
  902. } else {
  903. // already hit this tick?
  904. if (room->_conversion_tick == _conversion_tick) {
  905. return;
  906. }
  907. }
  908. // make sure the room is blank, especially if already created
  909. room->clear();
  910. // mark so as only to convert once
  911. room->_conversion_tick = _conversion_tick;
  912. // set roomgroup
  913. if (p_roomgroup != -1) {
  914. room->_roomgroups.push_back(p_roomgroup);
  915. room->_room_priority = p_roomgroups[p_roomgroup]->_settings_priority;
  916. VisualServer::get_singleton()->room_prepare(room->_room_rid, room->_room_priority);
  917. }
  918. // add to the list of rooms
  919. room->_room_ID = _rooms.size();
  920. _rooms.push_back(room);
  921. _find_portals_recursive(room, room, r_portals);
  922. }
  923. void RoomManager::_find_portals_recursive(Spatial *p_node, Room *p_room, LocalVector<Portal *> &r_portals) {
  924. MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
  925. if (_node_is_type<Portal>(p_node) || (mi && _name_ends_with(mi, "-portal"))) {
  926. _convert_portal(p_room, p_node, r_portals);
  927. }
  928. for (int n = 0; n < p_node->get_child_count(); n++) {
  929. Spatial *child = Object::cast_to<Spatial>(p_node->get_child(n));
  930. if (child) {
  931. _find_portals_recursive(child, p_room, r_portals);
  932. }
  933. }
  934. }
  935. void RoomManager::_check_portal_for_warnings(Portal *p_portal, const AABB &p_room_aabb_without_portals) {
  936. #ifdef TOOLS_ENABLED
  937. AABB bb = p_room_aabb_without_portals;
  938. bb = bb.grow(bb.get_longest_axis_size() * 0.5);
  939. bool changed = false;
  940. // far outside the room?
  941. const Vector3 &pos = p_portal->get_global_transform().origin;
  942. bool old_outside = p_portal->_warning_outside_room_aabb;
  943. p_portal->_warning_outside_room_aabb = !bb.has_point(pos);
  944. if (p_portal->_warning_outside_room_aabb != old_outside) {
  945. changed = true;
  946. }
  947. if (p_portal->_warning_outside_room_aabb) {
  948. WARN_PRINT(String(p_portal->get_name()) + " possibly in the wrong room.");
  949. }
  950. // facing wrong way?
  951. Vector3 offset = pos - bb.get_center();
  952. real_t dot = offset.dot(p_portal->_plane.normal);
  953. bool old_facing = p_portal->_warning_facing_wrong_way;
  954. p_portal->_warning_facing_wrong_way = dot < 0.0;
  955. if (p_portal->_warning_facing_wrong_way != old_facing) {
  956. changed = true;
  957. }
  958. if (p_portal->_warning_facing_wrong_way) {
  959. WARN_PRINT(String(p_portal->get_name()) + " possibly facing the wrong way.");
  960. }
  961. // handled later
  962. p_portal->_warning_autolink_failed = false;
  963. if (changed) {
  964. p_portal->update_gizmo();
  965. }
  966. #endif
  967. }
  968. bool RoomManager::_autoplace_object(VisualInstance *p_vi) {
  969. // note we could alternatively use the portal_renderer to do this more efficiently
  970. // (as it has a BSP) but at a cost of returning result from the visual server
  971. AABB bb = p_vi->get_transformed_aabb();
  972. Vector3 centre = bb.get_center();
  973. // in order to deal with internal rooms, we can't just stop at the first
  974. // room the point is within, as there could be later rooms with a higher priority
  975. int best_priority = -INT32_MAX;
  976. Room *best_room = nullptr;
  977. // if not set to zero (no preference) this can override a preference
  978. // for a certain RoomGroup priority to ensure the instance gets placed in the correct
  979. // RoomGroup (e.g. outside, for building exteriors)
  980. int preferred_priority = p_vi->get_portal_autoplace_priority();
  981. for (int n = 0; n < _rooms.size(); n++) {
  982. Room *room = _rooms[n];
  983. if (room->contains_point(centre)) {
  984. // the standard routine autoplaces in the highest priority room
  985. if (room->_room_priority > best_priority) {
  986. best_priority = room->_room_priority;
  987. best_room = room;
  988. }
  989. // if we override the preferred priority we always choose this
  990. if (preferred_priority && (room->_room_priority == preferred_priority)) {
  991. best_room = room;
  992. break;
  993. }
  994. }
  995. }
  996. if (best_room) {
  997. // just dummies, we won't use these this time
  998. Vector<Vector3> room_pts;
  999. // we can reuse this function
  1000. _process_static(best_room, p_vi, room_pts, true);
  1001. return true;
  1002. }
  1003. return false;
  1004. }
  1005. void RoomManager::_autoplace_recursive(Spatial *p_node) {
  1006. if (p_node->is_queued_for_deletion()) {
  1007. return;
  1008. }
  1009. // as soon as we hit a room, quit the recursion as the objects
  1010. // will already have been added inside rooms
  1011. if (Object::cast_to<Room>(p_node)) {
  1012. return;
  1013. }
  1014. VisualInstance *vi = Object::cast_to<VisualInstance>(p_node);
  1015. // we are only interested in VIs with static or dynamic mode
  1016. if (vi) {
  1017. switch (vi->get_portal_mode()) {
  1018. default: {
  1019. } break;
  1020. case CullInstance::PORTAL_MODE_DYNAMIC:
  1021. case CullInstance::PORTAL_MODE_STATIC: {
  1022. _autoplace_object(vi);
  1023. } break;
  1024. }
  1025. }
  1026. for (int n = 0; n < p_node->get_child_count(); n++) {
  1027. Spatial *child = Object::cast_to<Spatial>(p_node->get_child(n));
  1028. if (child) {
  1029. _autoplace_recursive(child);
  1030. }
  1031. }
  1032. }
  1033. void RoomManager::_process_static(Room *p_room, Spatial *p_node, Vector<Vector3> &r_room_pts, bool p_add_to_portal_renderer) {
  1034. bool ignore = false;
  1035. VisualInstance *vi = Object::cast_to<VisualInstance>(p_node);
  1036. bool is_dynamic = false;
  1037. // we are only interested in VIs with static or dynamic mode
  1038. if (vi) {
  1039. switch (vi->get_portal_mode()) {
  1040. default: {
  1041. ignore = true;
  1042. } break;
  1043. case CullInstance::PORTAL_MODE_DYNAMIC: {
  1044. is_dynamic = true;
  1045. } break;
  1046. case CullInstance::PORTAL_MODE_STATIC:
  1047. break;
  1048. }
  1049. }
  1050. if (!ignore) {
  1051. // We'll have a done flag. This isn't strictly speaking necessary
  1052. // because the types should be mutually exclusive, but this would
  1053. // break if something changes the inheritance hierarchy of the nodes
  1054. // at a later date, so having a done flag makes it more robust.
  1055. bool done = false;
  1056. Light *light = Object::cast_to<Light>(p_node);
  1057. if (!done && light) {
  1058. done = true;
  1059. // lights (don't affect bound, so aren't added in first pass)
  1060. if (p_add_to_portal_renderer) {
  1061. Vector<Vector3> dummy_pts;
  1062. VisualServer::get_singleton()->room_add_instance(p_room->_room_rid, light->get_instance(), light->get_transformed_aabb(), dummy_pts);
  1063. convert_log("\t\t\tLIGT\t" + light->get_name());
  1064. }
  1065. }
  1066. GeometryInstance *gi = Object::cast_to<GeometryInstance>(p_node);
  1067. if (!done && gi) {
  1068. done = true;
  1069. // MeshInstance is the most interesting type for portalling, so we handle this explicitly
  1070. MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
  1071. if (mi) {
  1072. if (p_add_to_portal_renderer) {
  1073. convert_log("\t\t\tMESH\t" + mi->get_name());
  1074. }
  1075. Vector<Vector3> object_pts;
  1076. AABB aabb;
  1077. // get the object points and don't immediately add to the room
  1078. // points, as we want to use these points for sprawling algorithm in
  1079. // the visual server.
  1080. if (_bound_findpoints_mesh_instance(mi, object_pts, aabb)) {
  1081. // need to keep track of room bound
  1082. // NOTE the is_visible check MAY cause problems if conversion run on nodes that
  1083. // aren't properly in the tree. It can optionally be removed. Certainly calling is_visible_in_tree
  1084. // DID cause problems.
  1085. if (!is_dynamic && mi->get_include_in_bound() && mi->is_visible()) {
  1086. r_room_pts.append_array(object_pts);
  1087. }
  1088. if (p_add_to_portal_renderer) {
  1089. VisualServer::get_singleton()->room_add_instance(p_room->_room_rid, mi->get_instance(), mi->get_transformed_aabb(), object_pts);
  1090. }
  1091. } // if bound found points
  1092. } else {
  1093. // geometry instance but not a mesh instance ..
  1094. if (p_add_to_portal_renderer) {
  1095. convert_log("\t\t\tGEOM\t" + gi->get_name());
  1096. }
  1097. Vector<Vector3> object_pts;
  1098. AABB aabb;
  1099. // attempt to recognise this GeometryInstance and read back the geometry
  1100. // Note: never attempt to add dynamics to the room aabb
  1101. if (is_dynamic || _bound_findpoints_geom_instance(gi, object_pts, aabb)) {
  1102. // need to keep track of room bound
  1103. // NOTE the is_visible check MAY cause problems if conversion run on nodes that
  1104. // aren't properly in the tree. It can optionally be removed. Certainly calling is_visible_in_tree
  1105. // DID cause problems.
  1106. if (!is_dynamic && gi->get_include_in_bound() && gi->is_visible()) {
  1107. r_room_pts.append_array(object_pts);
  1108. }
  1109. if (p_add_to_portal_renderer) {
  1110. VisualServer::get_singleton()->room_add_instance(p_room->_room_rid, gi->get_instance(), gi->get_transformed_aabb(), object_pts);
  1111. }
  1112. } // if bound found points
  1113. }
  1114. } // if gi
  1115. VisibilityNotifier *vn = Object::cast_to<VisibilityNotifier>(p_node);
  1116. if (!done && vn && ((vn->get_portal_mode() == CullInstance::PORTAL_MODE_DYNAMIC) || (vn->get_portal_mode() == CullInstance::PORTAL_MODE_STATIC))) {
  1117. done = true;
  1118. if (p_add_to_portal_renderer) {
  1119. AABB world_aabb = vn->get_global_transform().xform(vn->get_aabb());
  1120. VisualServer::get_singleton()->room_add_ghost(p_room->_room_rid, vn->get_instance_id(), world_aabb);
  1121. convert_log("\t\t\tVIS \t" + vn->get_name());
  1122. }
  1123. }
  1124. } // if not ignore
  1125. }
  1126. void RoomManager::_find_statics_recursive(Room *p_room, Spatial *p_node, Vector<Vector3> &r_room_pts, bool p_add_to_portal_renderer) {
  1127. // don't process portal MeshInstances that are being deleted
  1128. // (and replaced by proper Portal nodes)
  1129. if (p_node->is_queued_for_deletion()) {
  1130. return;
  1131. }
  1132. _process_static(p_room, p_node, r_room_pts, p_add_to_portal_renderer);
  1133. for (int n = 0; n < p_node->get_child_count(); n++) {
  1134. Spatial *child = Object::cast_to<Spatial>(p_node->get_child(n));
  1135. if (child) {
  1136. _find_statics_recursive(p_room, child, r_room_pts, p_add_to_portal_renderer);
  1137. }
  1138. }
  1139. }
  1140. bool RoomManager::_convert_manual_bound(Room *p_room, Spatial *p_node, const LocalVector<Portal *> &p_portals) {
  1141. MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
  1142. if (!mi) {
  1143. return false;
  1144. }
  1145. Vector<Vector3> points;
  1146. AABB aabb;
  1147. if (!_bound_findpoints_mesh_instance(mi, points, aabb)) {
  1148. return false;
  1149. }
  1150. mi->set_portal_mode(CullInstance::PORTAL_MODE_IGNORE);
  1151. // hide bounds after conversion
  1152. // set to portal mode ignore?
  1153. mi->hide();
  1154. return _convert_room_hull_preliminary(p_room, points, p_portals);
  1155. }
  1156. bool RoomManager::_convert_room_hull_preliminary(Room *p_room, const Vector<Vector3> &p_room_pts, const LocalVector<Portal *> &p_portals) {
  1157. if (p_room_pts.size() <= 3) {
  1158. return false;
  1159. }
  1160. Geometry::MeshData md;
  1161. Error err = OK;
  1162. // if there are too many room points, quickhull will fail or freeze etc, so we will revert
  1163. // to a bounding rect and send an error message
  1164. if (p_room_pts.size() > 100000) {
  1165. WARN_PRINT(String(p_room->get_name()) + " contains too many vertices to find convex hull, use a manual bound instead.");
  1166. AABB aabb;
  1167. aabb.create_from_points(p_room_pts);
  1168. LocalVector<Vector3> pts;
  1169. Vector3 mins = aabb.position;
  1170. Vector3 maxs = mins + aabb.size;
  1171. pts.push_back(Vector3(mins.x, mins.y, mins.z));
  1172. pts.push_back(Vector3(mins.x, maxs.y, mins.z));
  1173. pts.push_back(Vector3(maxs.x, maxs.y, mins.z));
  1174. pts.push_back(Vector3(maxs.x, mins.y, mins.z));
  1175. pts.push_back(Vector3(mins.x, mins.y, maxs.z));
  1176. pts.push_back(Vector3(mins.x, maxs.y, maxs.z));
  1177. pts.push_back(Vector3(maxs.x, maxs.y, maxs.z));
  1178. pts.push_back(Vector3(maxs.x, mins.y, maxs.z));
  1179. err = _build_convex_hull(pts, md);
  1180. } else {
  1181. err = _build_room_convex_hull(p_room, p_room_pts, md);
  1182. }
  1183. if (err != OK) {
  1184. return false;
  1185. }
  1186. // add any existing portals planes first, as these will trump any other existing planes further out
  1187. for (int n = 0; n < p_room->_portals.size(); n++) {
  1188. int portal_id = p_room->_portals[n];
  1189. Portal *portal = p_portals[portal_id];
  1190. // don't add portals to the hull that are internal to this room!
  1191. if (portal->is_portal_internal(p_room->_room_ID)) {
  1192. continue;
  1193. }
  1194. Plane plane = portal->_plane;
  1195. // does it need to be reversed? (i.e. is the portal incoming rather than outgoing)
  1196. if (portal->_linkedroom_ID[1] == p_room->_room_ID) {
  1197. plane = -plane;
  1198. }
  1199. _add_plane_if_unique(p_room, p_room->_preliminary_planes, plane);
  1200. }
  1201. // add the planes from the geometry or manual bound
  1202. for (int n = 0; n < md.faces.size(); n++) {
  1203. const Plane &p = md.faces[n].plane;
  1204. _add_plane_if_unique(p_room, p_room->_preliminary_planes, p);
  1205. }
  1206. // temporary copy of mesh data for the boundary points
  1207. // to form a new hull in _convert_room_hull_final
  1208. p_room->_bound_mesh_data = md;
  1209. // aabb (should later include portals too, these are added in _convert_room_hull_final)
  1210. p_room->_aabb.create_from_points(md.vertices);
  1211. return true;
  1212. }
  1213. bool RoomManager::_convert_room_hull_final(Room *p_room, const LocalVector<Portal *> &p_portals) {
  1214. Vector<Vector3> vertices_including_portals = p_room->_bound_mesh_data.vertices;
  1215. // add the portals planes first, as these will trump any other existing planes further out
  1216. int num_portals_added = 0;
  1217. for (int n = 0; n < p_room->_portals.size(); n++) {
  1218. int portal_id = p_room->_portals[n];
  1219. Portal *portal = p_portals[portal_id];
  1220. // don't add portals to the world bound that are internal to this room!
  1221. if (portal->is_portal_internal(p_room->_room_ID)) {
  1222. continue;
  1223. }
  1224. Plane plane = portal->_plane;
  1225. // does it need to be reversed? (i.e. is the portal incoming rather than outgoing)
  1226. if (portal->_linkedroom_ID[1] == p_room->_room_ID) {
  1227. plane = -plane;
  1228. }
  1229. if (_add_plane_if_unique(p_room, p_room->_planes, plane)) {
  1230. num_portals_added++;
  1231. }
  1232. // add any new portals to the aabb of the room
  1233. for (int p = 0; p < portal->_pts_world.size(); p++) {
  1234. const Vector3 &pt = portal->_pts_world[p];
  1235. vertices_including_portals.push_back(pt);
  1236. p_room->_aabb.expand_to(pt);
  1237. }
  1238. }
  1239. // create new convex hull
  1240. Geometry::MeshData md;
  1241. Error err = _build_room_convex_hull(p_room, vertices_including_portals, md);
  1242. if (err != OK) {
  1243. return false;
  1244. }
  1245. // add the planes from the new hull
  1246. for (int n = 0; n < md.faces.size(); n++) {
  1247. const Plane &p = md.faces[n].plane;
  1248. _add_plane_if_unique(p_room, p_room->_planes, p);
  1249. }
  1250. // recreate the points within the new simplified bound, and then recreate the convex hull
  1251. // by running quickhull a second time... (this enables the gizmo to accurately show the simplified hull)
  1252. int num_planes_before_simplification = p_room->_planes.size();
  1253. Geometry::MeshData md_simplified;
  1254. _build_simplified_bound(p_room, md_simplified, p_room->_planes, num_portals_added);
  1255. if (num_planes_before_simplification != p_room->_planes.size()) {
  1256. convert_log("\t\t\tcontained " + itos(num_planes_before_simplification) + " planes before simplification, " + itos(p_room->_planes.size()) + " planes after.");
  1257. }
  1258. // make a copy of the mesh data for debugging
  1259. // note this could be avoided in release builds? NYI
  1260. p_room->_bound_mesh_data = md_simplified;
  1261. // send bound to visual server
  1262. VisualServer::get_singleton()->room_set_bound(p_room->_room_rid, p_room->get_instance_id(), p_room->_planes, p_room->_aabb, md_simplified.vertices);
  1263. return true;
  1264. }
  1265. #ifdef TOOLS_ENABLED
  1266. bool RoomManager::_room_regenerate_bound(Room *p_room) {
  1267. // for a preview, we allow the editor to change the bound
  1268. ERR_FAIL_COND_V(!p_room, false);
  1269. if (!p_room->_bound_pts.size()) {
  1270. return false;
  1271. }
  1272. // can't do yet if not in the tree
  1273. if (!p_room->is_inside_tree()) {
  1274. return false;
  1275. }
  1276. Transform tr = p_room->get_global_transform();
  1277. Vector<Vector3> pts;
  1278. pts.resize(p_room->_bound_pts.size());
  1279. for (int n = 0; n < pts.size(); n++) {
  1280. pts.set(n, tr.xform(p_room->_bound_pts[n]));
  1281. }
  1282. Geometry::MeshData md;
  1283. Error err = _build_room_convex_hull(p_room, pts, md);
  1284. if (err != OK) {
  1285. return false;
  1286. }
  1287. p_room->_bound_mesh_data = md;
  1288. p_room->update_gizmo();
  1289. return true;
  1290. }
  1291. #endif
  1292. void RoomManager::_build_simplified_bound(const Room *p_room, Geometry::MeshData &r_md, LocalVector<Plane, int32_t> &r_planes, int p_num_portal_planes) {
  1293. if (!r_planes.size()) {
  1294. return;
  1295. }
  1296. Vector<Vector3> pts = Geometry::compute_convex_mesh_points(&r_planes[0], r_planes.size(), 0.001);
  1297. Error err = _build_room_convex_hull(p_room, pts, r_md);
  1298. if (err != OK) {
  1299. WARN_PRINT("QuickHull failed building simplified bound");
  1300. return;
  1301. }
  1302. // if the number of faces is less than the number of planes, we can use this simplified version to reduce the number of planes
  1303. if (r_md.faces.size() < r_planes.size()) {
  1304. // always include the portal planes
  1305. r_planes.resize(p_num_portal_planes);
  1306. for (int n = 0; n < r_md.faces.size(); n++) {
  1307. _add_plane_if_unique(p_room, r_planes, r_md.faces[n].plane);
  1308. }
  1309. }
  1310. }
  1311. Error RoomManager::_build_room_convex_hull(const Room *p_room, const Vector<Vector3> &p_points, Geometry::MeshData &r_mesh) {
  1312. // calculate an epsilon based on the simplify value, and use this to build the hull
  1313. real_t s = 0.0;
  1314. DEV_ASSERT(p_room);
  1315. if (p_room->_use_default_simplify) {
  1316. s = _room_simplify_info._plane_simplify;
  1317. } else {
  1318. s = p_room->_simplify_info._plane_simplify;
  1319. }
  1320. // value between 0.3 (accurate) and 10.0 (very rough)
  1321. // * UNIT_EPSILON
  1322. s *= s;
  1323. s *= 40.0;
  1324. s += 0.3; // minimum
  1325. s *= UNIT_EPSILON;
  1326. return _build_convex_hull(p_points, r_mesh, s);
  1327. }
  1328. bool RoomManager::_add_plane_if_unique(const Room *p_room, LocalVector<Plane, int32_t> &r_planes, const Plane &p) {
  1329. DEV_ASSERT(p_room);
  1330. if (p_room->_use_default_simplify) {
  1331. return _room_simplify_info.add_plane_if_unique(r_planes, p);
  1332. }
  1333. return p_room->_simplify_info.add_plane_if_unique(r_planes, p);
  1334. }
  1335. void RoomManager::_convert_portal(Room *p_room, Spatial *p_node, LocalVector<Portal *> &portals) {
  1336. Portal *portal = Object::cast_to<Portal>(p_node);
  1337. bool importing = false;
  1338. // if not a gportal already, convert the node type
  1339. if (!portal) {
  1340. importing = true;
  1341. portal = _change_node_type<Portal>(p_node, "G", false);
  1342. portal->create_from_mesh_instance(Object::cast_to<MeshInstance>(p_node));
  1343. p_node->queue_delete();
  1344. } else {
  1345. // only allow converting once
  1346. if (portal->_conversion_tick == _conversion_tick) {
  1347. return;
  1348. }
  1349. }
  1350. // make sure to start with fresh internal data each time (for linked rooms etc)
  1351. portal->clear();
  1352. // mark the portal if we are importing, because we will need to use the naming
  1353. // prefix system to look for linked rooms in that case
  1354. portal->_importing_portal = importing;
  1355. // mark so as only to convert once
  1356. portal->_conversion_tick = _conversion_tick;
  1357. // link rooms
  1358. portal->portal_update();
  1359. // keep a list of portals for second pass
  1360. portals.push_back(portal);
  1361. // the portal is linking from this first room it is added to
  1362. portal->_linkedroom_ID[0] = p_room->_room_ID;
  1363. }
  1364. bool RoomManager::_bound_findpoints_geom_instance(GeometryInstance *p_gi, Vector<Vector3> &r_room_pts, AABB &r_aabb) {
  1365. // max opposite extents .. note AABB storing size is rubbish in this aspect
  1366. // it can fail once mesh min is larger than FLT_MAX / 2.
  1367. r_aabb.position = Vector3(FLT_MAX / 2, FLT_MAX / 2, FLT_MAX / 2);
  1368. r_aabb.size = Vector3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
  1369. #ifdef MODULE_CSG_ENABLED
  1370. CSGShape *shape = Object::cast_to<CSGShape>(p_gi);
  1371. if (shape) {
  1372. // Shapes will not be up to date on the first frame due to a quirk
  1373. // of CSG - it defers updates to the next frame. So we need to explicitly
  1374. // force an update to make sure the CSG is correct on level load.
  1375. shape->force_update_shape();
  1376. Array arr = shape->get_meshes();
  1377. if (!arr.size()) {
  1378. return false;
  1379. }
  1380. Ref<ArrayMesh> arr_mesh = arr[1];
  1381. if (!arr_mesh.is_valid()) {
  1382. return false;
  1383. }
  1384. if (arr_mesh->get_surface_count() == 0) {
  1385. return false;
  1386. }
  1387. // for converting meshes to world space
  1388. Transform trans = p_gi->get_global_transform();
  1389. for (int surf = 0; surf < arr_mesh->get_surface_count(); surf++) {
  1390. Array arrays = arr_mesh->surface_get_arrays(surf);
  1391. if (!arrays.size()) {
  1392. continue;
  1393. }
  1394. PoolVector<Vector3> vertices = arrays[VS::ARRAY_VERTEX];
  1395. // convert to world space
  1396. for (int n = 0; n < vertices.size(); n++) {
  1397. Vector3 pt_world = trans.xform(vertices[n]);
  1398. r_room_pts.push_back(pt_world);
  1399. // keep the bound up to date
  1400. r_aabb.expand_to(pt_world);
  1401. }
  1402. } // for through the surfaces
  1403. return true;
  1404. } // if csg shape
  1405. #endif
  1406. // multimesh
  1407. MultiMeshInstance *mmi = Object::cast_to<MultiMeshInstance>(p_gi);
  1408. if (mmi) {
  1409. Ref<MultiMesh> rmm = mmi->get_multimesh();
  1410. if (!rmm.is_valid()) {
  1411. return false;
  1412. }
  1413. // first get the mesh verts in local space
  1414. LocalVector<Vector3, int32_t> local_verts;
  1415. Ref<Mesh> rmesh = rmm->get_mesh();
  1416. if (rmesh->get_surface_count() == 0) {
  1417. String string;
  1418. string = "MultiMeshInstance '" + mmi->get_name() + "' has no surfaces, ignoring";
  1419. WARN_PRINT(string);
  1420. return false;
  1421. }
  1422. for (int surf = 0; surf < rmesh->get_surface_count(); surf++) {
  1423. Array arrays = rmesh->surface_get_arrays(surf);
  1424. if (!arrays.size()) {
  1425. WARN_PRINT_ONCE("MultiMesh mesh surface with no mesh, ignoring");
  1426. continue;
  1427. }
  1428. const PoolVector<Vector3> &vertices = arrays[VS::ARRAY_VERTEX];
  1429. int count = local_verts.size();
  1430. local_verts.resize(local_verts.size() + vertices.size());
  1431. for (int n = 0; n < vertices.size(); n++) {
  1432. local_verts[count++] = vertices[n];
  1433. }
  1434. }
  1435. if (!local_verts.size()) {
  1436. return false;
  1437. }
  1438. // now we have the local space verts, add a bunch for each instance, and find the AABB
  1439. for (int i = 0; i < rmm->get_instance_count(); i++) {
  1440. Transform trans = rmm->get_instance_transform(i);
  1441. trans = mmi->get_global_transform() * trans;
  1442. for (int n = 0; n < local_verts.size(); n++) {
  1443. Vector3 pt_world = trans.xform(local_verts[n]);
  1444. r_room_pts.push_back(pt_world);
  1445. // keep the bound up to date
  1446. r_aabb.expand_to(pt_world);
  1447. }
  1448. }
  1449. return true;
  1450. }
  1451. // Sprite3D
  1452. SpriteBase3D *sprite = Object::cast_to<SpriteBase3D>(p_gi);
  1453. if (sprite) {
  1454. Ref<TriangleMesh> tmesh = sprite->generate_triangle_mesh();
  1455. PoolVector<Vector3> vertices = tmesh->get_vertices();
  1456. // for converting meshes to world space
  1457. Transform trans = p_gi->get_global_transform();
  1458. // convert to world space
  1459. for (int n = 0; n < vertices.size(); n++) {
  1460. Vector3 pt_world = trans.xform(vertices[n]);
  1461. r_room_pts.push_back(pt_world);
  1462. // keep the bound up to date
  1463. r_aabb.expand_to(pt_world);
  1464. }
  1465. return true;
  1466. }
  1467. return false;
  1468. }
  1469. bool RoomManager::_bound_findpoints_mesh_instance(MeshInstance *p_mi, Vector<Vector3> &r_room_pts, AABB &r_aabb) {
  1470. // max opposite extents .. note AABB storing size is rubbish in this aspect
  1471. // it can fail once mesh min is larger than FLT_MAX / 2.
  1472. r_aabb.position = Vector3(FLT_MAX / 2, FLT_MAX / 2, FLT_MAX / 2);
  1473. r_aabb.size = Vector3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
  1474. // some godot jiggery pokery to get the mesh verts in local space
  1475. Ref<Mesh> rmesh = p_mi->get_mesh();
  1476. ERR_FAIL_COND_V(!rmesh.is_valid(), false);
  1477. if (rmesh->get_surface_count() == 0) {
  1478. String string;
  1479. string = "MeshInstance '" + p_mi->get_name() + "' has no surfaces, ignoring";
  1480. WARN_PRINT(string);
  1481. return false;
  1482. }
  1483. bool success = false;
  1484. // for converting meshes to world space
  1485. Transform trans = p_mi->get_global_transform();
  1486. for (int surf = 0; surf < rmesh->get_surface_count(); surf++) {
  1487. Array arrays = rmesh->surface_get_arrays(surf);
  1488. // possible to have a meshinstance with no geometry .. don't want to crash
  1489. if (!arrays.size()) {
  1490. WARN_PRINT_ONCE("MeshInstance surface with no mesh, ignoring");
  1491. continue;
  1492. }
  1493. success = true;
  1494. PoolVector<Vector3> vertices = arrays[VS::ARRAY_VERTEX];
  1495. // convert to world space
  1496. for (int n = 0; n < vertices.size(); n++) {
  1497. Vector3 ptWorld = trans.xform(vertices[n]);
  1498. r_room_pts.push_back(ptWorld);
  1499. // keep the bound up to date
  1500. r_aabb.expand_to(ptWorld);
  1501. }
  1502. } // for through the surfaces
  1503. return success;
  1504. }
  1505. void RoomManager::_cleanup_after_conversion() {
  1506. for (int n = 0; n < _rooms.size(); n++) {
  1507. Room *room = _rooms[n];
  1508. room->_portals.reset();
  1509. room->_preliminary_planes.reset();
  1510. // outside the editor, there's no need to keep the data for the convex hull
  1511. // drawing, as it is only used for gizmos.
  1512. if (!Engine::get_singleton()->is_editor_hint()) {
  1513. room->_bound_mesh_data = Geometry::MeshData();
  1514. }
  1515. }
  1516. }
  1517. bool RoomManager::resolve_preview_camera_path() {
  1518. Camera *camera = _resolve_path<Camera>(_settings_path_preview_camera);
  1519. if (camera) {
  1520. _godot_preview_camera_ID = camera->get_instance_id();
  1521. return true;
  1522. }
  1523. _godot_preview_camera_ID = -1;
  1524. return false;
  1525. }
  1526. template <class NODE_TYPE>
  1527. NODE_TYPE *RoomManager::_resolve_path(NodePath p_path) const {
  1528. if (has_node(p_path)) {
  1529. NODE_TYPE *node = Object::cast_to<NODE_TYPE>(get_node(p_path));
  1530. if (node) {
  1531. return node;
  1532. } else {
  1533. WARN_PRINT("node is incorrect type");
  1534. }
  1535. }
  1536. return nullptr;
  1537. }
  1538. template <class NODE_TYPE>
  1539. bool RoomManager::_node_is_type(Node *p_node) const {
  1540. NODE_TYPE *node = Object::cast_to<NODE_TYPE>(p_node);
  1541. return node != nullptr;
  1542. }
  1543. template <class T>
  1544. T *RoomManager::_change_node_type(Spatial *p_node, String p_prefix, bool p_delete) {
  1545. String string_full_name = p_node->get_name();
  1546. Node *parent = p_node->get_parent();
  1547. if (!parent) {
  1548. return nullptr;
  1549. }
  1550. // owner should normally be root
  1551. Node *owner = p_node->get_owner();
  1552. // change the name of the node to be deleted
  1553. p_node->set_name(p_prefix + string_full_name);
  1554. // create the new class T object
  1555. T *pNew = memnew(T);
  1556. pNew->set_name(string_full_name);
  1557. // add the child at the same position as the old node
  1558. // (this is more convenient for users)
  1559. parent->add_child_below_node(p_node, pNew);
  1560. // new lroom should have same transform
  1561. pNew->set_transform(p_node->get_transform());
  1562. // move each child
  1563. while (p_node->get_child_count()) {
  1564. Node *child = p_node->get_child(0);
  1565. p_node->remove_child(child);
  1566. // needs to set owner to appear in IDE
  1567. pNew->add_child(child);
  1568. }
  1569. // needs to set owner to appear in IDE
  1570. _set_owner_recursive(pNew, owner);
  1571. // delete old node
  1572. if (p_delete) {
  1573. p_node->queue_delete();
  1574. }
  1575. return pNew;
  1576. }
  1577. void RoomManager::_update_gizmos_recursive(Node *p_node) {
  1578. Portal *portal = Object::cast_to<Portal>(p_node);
  1579. if (portal) {
  1580. portal->update_gizmo();
  1581. }
  1582. for (int n = 0; n < p_node->get_child_count(); n++) {
  1583. _update_gizmos_recursive(p_node->get_child(n));
  1584. }
  1585. }
  1586. Error RoomManager::_build_convex_hull(const Vector<Vector3> &p_points, Geometry::MeshData &r_mesh, real_t p_epsilon) {
  1587. #ifdef GODOT_PORTALS_USE_BULLET_CONVEX_HULL
  1588. return ConvexHullComputer::convex_hull(p_points, r_mesh);
  1589. #if 0
  1590. // test comparison of methods
  1591. QuickHull::build(p_points, r_mesh, p_epsilon);
  1592. int qh_faces = r_mesh.faces.size();
  1593. int qh_verts = r_mesh.vertices.size();
  1594. r_mesh.vertices.clear();
  1595. r_mesh.faces.clear();
  1596. r_mesh.edges.clear();
  1597. Error err = ConvexHullComputer::convex_hull(p_points, r_mesh);
  1598. int bh_faces = r_mesh.faces.size();
  1599. int bh_verts = r_mesh.vertices.size();
  1600. if (qh_faces != bh_faces) {
  1601. print_line("qh_faces : " + itos(qh_faces) + ", bh_faces : " + itos(bh_faces));
  1602. }
  1603. if (qh_verts != bh_verts) {
  1604. print_line("qh_verts : " + itos(qh_verts) + ", bh_verts : " + itos(bh_verts));
  1605. }
  1606. return err;
  1607. #endif
  1608. #else
  1609. QuickHull::_flag_warnings = false;
  1610. Error err = QuickHull::build(p_points, r_mesh, p_epsilon);
  1611. QuickHull::_flag_warnings = true;
  1612. return err;
  1613. #endif
  1614. }
  1615. void RoomManager::_flip_portals_recursive(Spatial *p_node) {
  1616. Portal *portal = Object::cast_to<Portal>(p_node);
  1617. if (portal) {
  1618. portal->flip();
  1619. }
  1620. for (int n = 0; n < p_node->get_child_count(); n++) {
  1621. Spatial *child = Object::cast_to<Spatial>(p_node->get_child(n));
  1622. if (child) {
  1623. _flip_portals_recursive(child);
  1624. }
  1625. }
  1626. }
  1627. void RoomManager::_set_owner_recursive(Node *p_node, Node *p_owner) {
  1628. if (!p_node->get_owner() && (p_node != p_owner)) {
  1629. p_node->set_owner(p_owner);
  1630. }
  1631. for (int n = 0; n < p_node->get_child_count(); n++) {
  1632. _set_owner_recursive(p_node->get_child(n), p_owner);
  1633. }
  1634. }
  1635. bool RoomManager::_name_ends_with(const Node *p_node, String p_postfix) const {
  1636. ERR_FAIL_NULL_V(p_node, false);
  1637. String name = p_node->get_name();
  1638. int pf_l = p_postfix.length();
  1639. int l = name.length();
  1640. if (pf_l > l) {
  1641. return false;
  1642. }
  1643. // allow capitalization errors
  1644. if (name.substr(l - pf_l, pf_l).to_lower() == p_postfix) {
  1645. return true;
  1646. }
  1647. return false;
  1648. }
  1649. String RoomManager::_find_name_before(Node *p_node, String p_postfix, bool p_allow_no_postfix) {
  1650. ERR_FAIL_NULL_V(p_node, String());
  1651. String name = p_node->get_name();
  1652. int pf_l = p_postfix.length();
  1653. int l = name.length();
  1654. if (pf_l > l) {
  1655. if (!p_allow_no_postfix) {
  1656. return String();
  1657. }
  1658. } else {
  1659. if (name.substr(l - pf_l, pf_l) == p_postfix) {
  1660. name = name.substr(0, l - pf_l);
  1661. } else {
  1662. if (!p_allow_no_postfix) {
  1663. return String();
  1664. }
  1665. }
  1666. }
  1667. // because godot doesn't support multiple nodes with the same name, we will strip e.g. a number
  1668. // after an * on the end of the name...
  1669. // e.g. kitchen*2-portal
  1670. for (int c = 0; c < name.length(); c++) {
  1671. if (name[c] == GODOT_PORTAL_WILDCARD) {
  1672. // remove everything after and including this character
  1673. name = name.substr(0, c);
  1674. break;
  1675. }
  1676. }
  1677. return name;
  1678. }
  1679. void RoomManager::_merge_meshes_in_room(Room *p_room) {
  1680. // only do in running game so as not to lose data
  1681. if (Engine::get_singleton()->is_editor_hint()) {
  1682. return;
  1683. }
  1684. _merge_log("merging room " + p_room->get_name());
  1685. // list of meshes suitable
  1686. LocalVector<MeshInstance *, int32_t> source_meshes;
  1687. _list_mergeable_mesh_instances(p_room, source_meshes);
  1688. // none suitable
  1689. if (!source_meshes.size()) {
  1690. return;
  1691. }
  1692. _merge_log("\t" + itos(source_meshes.size()) + " source meshes");
  1693. BitFieldDynamic bf;
  1694. bf.create(source_meshes.size(), true);
  1695. for (int n = 0; n < source_meshes.size(); n++) {
  1696. LocalVector<MeshInstance *, int32_t> merge_list;
  1697. // find similar meshes
  1698. MeshInstance *a = source_meshes[n];
  1699. merge_list.push_back(a);
  1700. // may not be necessary
  1701. bf.set_bit(n, true);
  1702. for (int c = n + 1; c < source_meshes.size(); c++) {
  1703. // if not merged already
  1704. if (!bf.get_bit(c)) {
  1705. MeshInstance *b = source_meshes[c];
  1706. // if (_are_meshes_mergeable(a, b)) {
  1707. if (a->is_mergeable_with(*b)) {
  1708. merge_list.push_back(b);
  1709. bf.set_bit(c, true);
  1710. }
  1711. } // if not merged already
  1712. } // for c through secondary mesh
  1713. // only merge if more than 1
  1714. if (merge_list.size() > 1) {
  1715. // we can merge!
  1716. // create a new holder mesh
  1717. MeshInstance *merged = memnew(MeshInstance);
  1718. merged->set_name("MergedMesh");
  1719. _merge_log("\t\t" + merged->get_name());
  1720. if (merged->create_by_merging(merge_list)) {
  1721. // set all the source meshes to portal mode ignore so not shown
  1722. for (int i = 0; i < merge_list.size(); i++) {
  1723. merge_list[i]->set_portal_mode(CullInstance::PORTAL_MODE_IGNORE);
  1724. }
  1725. // and set the new merged mesh to static
  1726. merged->set_portal_mode(CullInstance::PORTAL_MODE_STATIC);
  1727. // attach to scene tree
  1728. p_room->add_child(merged);
  1729. merged->set_owner(p_room->get_owner());
  1730. // compensate for room transform, as the verts are now in world space
  1731. Transform tr = p_room->get_global_transform();
  1732. tr.affine_invert();
  1733. merged->set_transform(tr);
  1734. // delete originals?
  1735. // note this isn't perfect, it may still end up with dangling spatials, but they can be
  1736. // deleted later.
  1737. for (int i = 0; i < merge_list.size(); i++) {
  1738. MeshInstance *mi = merge_list[i];
  1739. if (!mi->get_child_count()) {
  1740. mi->queue_delete();
  1741. } else {
  1742. Node *parent = mi->get_parent();
  1743. if (parent) {
  1744. // if there are children, we don't want to delete it, but we do want to
  1745. // remove the mesh drawing, e.g. by replacing it with a spatial
  1746. String name = mi->get_name();
  1747. mi->set_name("DeleteMe"); // can be anything, just to avoid name conflict with replacement node
  1748. Spatial *replacement = memnew(Spatial);
  1749. replacement->set_name(name);
  1750. parent->add_child(replacement);
  1751. // make the transform and owner match
  1752. replacement->set_owner(mi->get_owner());
  1753. replacement->set_transform(mi->get_transform());
  1754. // move all children from the mesh instance to the replacement
  1755. while (mi->get_child_count()) {
  1756. Node *child = mi->get_child(0);
  1757. mi->remove_child(child);
  1758. replacement->add_child(child);
  1759. }
  1760. } // if the mesh instance has a parent (should hopefully be always the case?)
  1761. }
  1762. }
  1763. } else {
  1764. // no success
  1765. memdelete(merged);
  1766. }
  1767. }
  1768. } // for n through primary mesh
  1769. if (_settings_remove_danglers) {
  1770. _remove_redundant_dangling_nodes(p_room);
  1771. }
  1772. }
  1773. bool RoomManager::_remove_redundant_dangling_nodes(Spatial *p_node) {
  1774. int non_queue_delete_children = 0;
  1775. // do the children first
  1776. for (int n = 0; n < p_node->get_child_count(); n++) {
  1777. Node *node_child = p_node->get_child(n);
  1778. Spatial *child = Object::cast_to<Spatial>(node_child);
  1779. if (child) {
  1780. _remove_redundant_dangling_nodes(child);
  1781. }
  1782. if (node_child && !node_child->is_queued_for_deletion()) {
  1783. non_queue_delete_children++;
  1784. }
  1785. }
  1786. if (!non_queue_delete_children) {
  1787. // only remove true spatials, not derived classes
  1788. if (p_node->get_class_name() == "Spatial") {
  1789. p_node->queue_delete();
  1790. return true;
  1791. }
  1792. }
  1793. return false;
  1794. }
  1795. void RoomManager::_list_mergeable_mesh_instances(Spatial *p_node, LocalVector<MeshInstance *, int32_t> &r_list) {
  1796. MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
  1797. if (mi) {
  1798. // only interested in static portal mode meshes
  1799. VisualInstance *vi = Object::cast_to<VisualInstance>(mi);
  1800. // we are only interested in VIs with static or dynamic mode
  1801. if (vi && vi->get_portal_mode() == CullInstance::PORTAL_MODE_STATIC) {
  1802. // disallow for portals or bounds
  1803. // mesh instance portals should be queued for deletion by this point, we don't want to merge portals!
  1804. if (!_node_is_type<Portal>(mi) && !_name_ends_with(mi, "-bound") && !mi->is_queued_for_deletion()) {
  1805. // only merge if visible
  1806. if (mi->is_inside_tree() && mi->is_visible()) {
  1807. r_list.push_back(mi);
  1808. }
  1809. }
  1810. }
  1811. }
  1812. for (int n = 0; n < p_node->get_child_count(); n++) {
  1813. Spatial *child = Object::cast_to<Spatial>(p_node->get_child(n));
  1814. if (child) {
  1815. _list_mergeable_mesh_instances(child, r_list);
  1816. }
  1817. }
  1818. }