portal_renderer.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207
  1. /**************************************************************************/
  2. /* portal_renderer.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  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 "portal_renderer.h"
  31. #include "portal_pvs_builder.h"
  32. #include "servers/visual/visual_server_globals.h"
  33. #include "servers/visual/visual_server_scene.h"
  34. bool PortalRenderer::use_occlusion_culling = true;
  35. OcclusionHandle PortalRenderer::instance_moving_create(VSInstance *p_instance, RID p_instance_rid, bool p_global, AABB p_aabb) {
  36. uint32_t pool_id = 0;
  37. Moving *moving = _moving_pool.request(pool_id);
  38. moving->global = p_global;
  39. moving->pool_id = pool_id;
  40. moving->instance = p_instance;
  41. moving->room_id = -1;
  42. #ifdef PORTAL_RENDERER_STORE_MOVING_RIDS
  43. moving->instance_rid = p_instance_rid;
  44. #endif
  45. // add to the appropriate list
  46. if (p_global) {
  47. moving->list_id = _moving_list_global.size();
  48. _moving_list_global.push_back(pool_id);
  49. } else {
  50. // do we need a roaming master list? not sure yet
  51. moving->list_id = _moving_list_roaming.size();
  52. _moving_list_roaming.push_back(pool_id);
  53. }
  54. OcclusionHandle handle = pool_id + 1;
  55. instance_moving_update(handle, p_aabb, true);
  56. return handle;
  57. }
  58. void PortalRenderer::instance_moving_update(OcclusionHandle p_handle, const AABB &p_aabb, bool p_force_reinsert) {
  59. p_handle--;
  60. Moving &moving = _moving_pool[p_handle];
  61. moving.exact_aabb = p_aabb;
  62. // globals (e.g. interface elements) need their aabb updated irrespective of whether the system is loaded
  63. if (!_loaded || moving.global) {
  64. return;
  65. }
  66. // we can ignore these, they are statics / dynamics, and don't need updating
  67. // .. these should have been filtered out before calling the visual server...
  68. DEV_CHECK_ONCE(!_occlusion_handle_is_in_room(p_handle));
  69. // quick reject for most roaming cases
  70. if (!p_force_reinsert && moving.expanded_aabb.encloses(p_aabb)) {
  71. return;
  72. }
  73. // using an expanded aabb allows us to make 'no op' moves
  74. // where the new aabb is within the expanded
  75. moving.expanded_aabb = p_aabb.grow(_roaming_expansion_margin);
  76. // if we got to here, it is roaming (moving between rooms)
  77. // remove from current rooms
  78. _moving_remove_from_rooms(p_handle);
  79. // add to new rooms
  80. Vector3 center = p_aabb.position + (p_aabb.size * 0.5);
  81. int new_room = find_room_within(center, moving.room_id);
  82. moving.room_id = new_room;
  83. if (new_room != -1) {
  84. _bitfield_rooms.blank();
  85. sprawl_roaming(p_handle, moving, new_room, true);
  86. }
  87. }
  88. void PortalRenderer::_rghost_remove_from_rooms(uint32_t p_pool_id) {
  89. RGhost &moving = _rghost_pool[p_pool_id];
  90. // if we have unloaded the rooms and we try this, it will crash
  91. if (_loaded) {
  92. for (int n = 0; n < moving._rooms.size(); n++) {
  93. VSRoom &room = get_room(moving._rooms[n]);
  94. room.remove_rghost(p_pool_id);
  95. }
  96. }
  97. // moving is now in no rooms
  98. moving._rooms.clear();
  99. }
  100. void PortalRenderer::_occluder_remove_from_rooms(uint32_t p_pool_id) {
  101. VSOccluder_Instance &occ = _occluder_instance_pool[p_pool_id];
  102. if (_loaded && (occ.room_id != -1)) {
  103. VSRoom &room = get_room(occ.room_id);
  104. bool res = room.remove_occluder(p_pool_id);
  105. if (!res) {
  106. WARN_PRINT_ONCE("OccluderInstance was not present in Room");
  107. }
  108. }
  109. }
  110. void PortalRenderer::_moving_remove_from_rooms(uint32_t p_moving_pool_id) {
  111. Moving &moving = _moving_pool[p_moving_pool_id];
  112. // if we have unloaded the rooms and we try this, it will crash
  113. if (_loaded) {
  114. for (int n = 0; n < moving._rooms.size(); n++) {
  115. VSRoom &room = get_room(moving._rooms[n]);
  116. room.remove_roamer(p_moving_pool_id);
  117. }
  118. }
  119. // moving is now in no rooms
  120. moving._rooms.clear();
  121. }
  122. void PortalRenderer::_debug_print_global_list() {
  123. _log("globals:");
  124. for (int n = 0; n < _moving_list_global.size(); n++) {
  125. uint32_t id = _moving_list_global[n];
  126. const Moving &moving = _moving_pool[id];
  127. _log("\t" + _addr_to_string(&moving));
  128. }
  129. }
  130. void PortalRenderer::_log(String p_string, int p_priority) {
  131. if (_show_debug) {
  132. // change this for more debug output ..
  133. // not selectable at runtime yet.
  134. if (p_priority >= 1) {
  135. print_line(p_string);
  136. } else {
  137. print_verbose(p_string);
  138. }
  139. }
  140. }
  141. void PortalRenderer::instance_moving_destroy(OcclusionHandle p_handle) {
  142. // deleting an instance that is assigned to a room (STATIC or DYNAMIC)
  143. // is special, it must set the PortalRenderer into unloaded state, because
  144. // there will now be a dangling reference to the instance that was destroyed.
  145. // The alternative is to remove the reference, but this is not currently supported
  146. // (it would mean rejigging rooms etc)
  147. if (_occlusion_handle_is_in_room(p_handle)) {
  148. _ensure_unloaded("deleting STATIC or DYNAMIC");
  149. return;
  150. }
  151. p_handle--;
  152. Moving *moving = &_moving_pool[p_handle];
  153. // if a roamer, remove from any current rooms
  154. if (!moving->global) {
  155. _moving_remove_from_rooms(p_handle);
  156. }
  157. // remove from list (and keep in sync)
  158. uint32_t list_id = moving->list_id;
  159. if (moving->global) {
  160. _moving_list_global.remove_unordered(list_id);
  161. // keep the replacement moving in sync with the correct list Id
  162. if (list_id < (uint32_t)_moving_list_global.size()) {
  163. uint32_t replacement_id = _moving_list_global[list_id];
  164. Moving &replacement = _moving_pool[replacement_id];
  165. replacement.list_id = list_id;
  166. }
  167. } else {
  168. _moving_list_roaming.remove_unordered(list_id);
  169. // keep the replacement moving in sync with the correct list Id
  170. if (list_id < (uint32_t)_moving_list_roaming.size()) {
  171. uint32_t replacement_id = _moving_list_roaming[list_id];
  172. Moving &replacement = _moving_pool[replacement_id];
  173. replacement.list_id = list_id;
  174. }
  175. }
  176. moving->destroy();
  177. // can now free the moving
  178. _moving_pool.free(p_handle);
  179. }
  180. PortalHandle PortalRenderer::portal_create() {
  181. uint32_t pool_id = 0;
  182. VSPortal *portal = _portal_pool.request(pool_id);
  183. // explicit constructor
  184. portal->create();
  185. portal->_portal_id = _portal_pool_ids.size();
  186. _portal_pool_ids.push_back(pool_id);
  187. // plus one based handles, 0 is unset
  188. pool_id++;
  189. return pool_id;
  190. }
  191. void PortalRenderer::portal_destroy(PortalHandle p_portal) {
  192. ERR_FAIL_COND(!p_portal);
  193. _ensure_unloaded("deleting Portal");
  194. // plus one based
  195. p_portal--;
  196. // remove from list of valid portals
  197. VSPortal &portal = _portal_pool[p_portal];
  198. int portal_id = portal._portal_id;
  199. // we need to replace the last element in the list
  200. _portal_pool_ids.remove_unordered(portal_id);
  201. // and reset the id of the portal that was the replacement
  202. if (portal_id < _portal_pool_ids.size()) {
  203. int replacement_pool_id = _portal_pool_ids[portal_id];
  204. VSPortal &replacement = _portal_pool[replacement_pool_id];
  205. replacement._portal_id = portal_id;
  206. }
  207. // explicitly run destructor
  208. _portal_pool[p_portal].destroy();
  209. // return to the pool
  210. _portal_pool.free(p_portal);
  211. }
  212. void PortalRenderer::portal_set_geometry(PortalHandle p_portal, const Vector<Vector3> &p_points, real_t p_margin) {
  213. ERR_FAIL_COND(!p_portal);
  214. p_portal--; // plus 1 based
  215. VSPortal &portal = _portal_pool[p_portal];
  216. portal._pts_world = p_points;
  217. portal._margin = p_margin;
  218. if (portal._pts_world.size() < 3) {
  219. WARN_PRINT("Portal must have at least 3 vertices");
  220. return;
  221. }
  222. // create plane from points
  223. // Allow averaging in case of wonky portals.
  224. // first calculate average normal
  225. Vector3 average_normal = Vector3(0, 0, 0);
  226. for (int t = 2; t < (int)portal._pts_world.size(); t++) {
  227. Plane p = Plane(portal._pts_world[0], portal._pts_world[t - 1], portal._pts_world[t]);
  228. average_normal += p.normal;
  229. }
  230. // average normal
  231. average_normal /= portal._pts_world.size() - 2;
  232. // detect user error
  233. ERR_FAIL_COND_MSG(average_normal.length() < 0.1, "Nonsense portal detected, normals should be consistent");
  234. if (average_normal.length() < 0.7) {
  235. WARN_PRINT("Wonky portal detected, you may see culling errors");
  236. }
  237. // calc average point
  238. Vector3 average_pt = Vector3(0, 0, 0);
  239. for (unsigned int n = 0; n < portal._pts_world.size(); n++) {
  240. average_pt += portal._pts_world[n];
  241. }
  242. average_pt /= portal._pts_world.size();
  243. // record the center for use in PVS
  244. portal._pt_center = average_pt;
  245. // calculate bounding sphere radius
  246. portal._bounding_sphere_radius = 0.0;
  247. for (unsigned int n = 0; n < portal._pts_world.size(); n++) {
  248. real_t sl = (portal._pts_world[n] - average_pt).length_squared();
  249. if (sl > portal._bounding_sphere_radius) {
  250. portal._bounding_sphere_radius = sl;
  251. }
  252. }
  253. portal._bounding_sphere_radius = Math::sqrt(portal._bounding_sphere_radius);
  254. // use the average point and normal to derive the plane
  255. portal._plane = Plane(average_pt, average_normal);
  256. // aabb
  257. AABB &bb = portal._aabb;
  258. bb.position = p_points[0];
  259. bb.size = Vector3(0, 0, 0);
  260. for (int n = 1; n < p_points.size(); n++) {
  261. bb.expand_to(p_points[n]);
  262. }
  263. }
  264. void PortalRenderer::portal_link(PortalHandle p_portal, RoomHandle p_room_from, RoomHandle p_room_to, bool p_two_way) {
  265. ERR_FAIL_COND(!p_portal);
  266. p_portal--; // plus 1 based
  267. VSPortal &portal = _portal_pool[p_portal];
  268. ERR_FAIL_COND(!p_room_from);
  269. p_room_from--;
  270. VSRoom &room_from = _room_pool[p_room_from];
  271. ERR_FAIL_COND(!p_room_to);
  272. p_room_to--;
  273. VSRoom &room_to = _room_pool[p_room_to];
  274. portal._linkedroom_ID[0] = room_from._room_ID;
  275. portal._linkedroom_ID[1] = room_to._room_ID;
  276. // is the portal internal? internal portals are treated differently
  277. portal._internal = room_from._priority > room_to._priority;
  278. // if it is internal, mark the outer room as containing an internal room.
  279. // this is used for rooms lookup.
  280. if (portal._internal) {
  281. room_to._contains_internal_rooms = true;
  282. }
  283. // _log("portal_link from room " + itos(room_from._room_ID) + " to room " + itos(room_to._room_ID));
  284. room_from._portal_ids.push_back(portal._portal_id);
  285. // one way portals simply aren't added to the destination room, so they don't get seen through
  286. if (p_two_way) {
  287. room_to._portal_ids.push_back(portal._portal_id);
  288. }
  289. }
  290. void PortalRenderer::portal_set_active(PortalHandle p_portal, bool p_active) {
  291. ERR_FAIL_COND(!p_portal);
  292. p_portal--; // plus 1 based
  293. VSPortal &portal = _portal_pool[p_portal];
  294. portal._active = p_active;
  295. }
  296. RoomGroupHandle PortalRenderer::roomgroup_create() {
  297. uint32_t pool_id = 0;
  298. VSRoomGroup *rg = _roomgroup_pool.request(pool_id);
  299. // explicit constructor
  300. rg->create();
  301. // plus one based handles, 0 is unset
  302. pool_id++;
  303. return pool_id;
  304. }
  305. void PortalRenderer::roomgroup_prepare(RoomGroupHandle p_roomgroup, ObjectID p_roomgroup_object_id) {
  306. // plus one based
  307. p_roomgroup--;
  308. VSRoomGroup &rg = _roomgroup_pool[p_roomgroup];
  309. rg._godot_instance_ID = p_roomgroup_object_id;
  310. }
  311. void PortalRenderer::roomgroup_destroy(RoomGroupHandle p_roomgroup) {
  312. ERR_FAIL_COND(!p_roomgroup);
  313. _ensure_unloaded("deleting RoomGroup");
  314. // plus one based
  315. p_roomgroup--;
  316. VSRoomGroup &rg = _roomgroup_pool[p_roomgroup];
  317. // explicitly run destructor
  318. rg.destroy();
  319. // return to the pool
  320. _roomgroup_pool.free(p_roomgroup);
  321. }
  322. void PortalRenderer::roomgroup_add_room(RoomGroupHandle p_roomgroup, RoomHandle p_room) {
  323. // plus one based
  324. p_roomgroup--;
  325. VSRoomGroup &rg = _roomgroup_pool[p_roomgroup];
  326. p_room--;
  327. // add to room group
  328. rg._room_ids.push_back(p_room);
  329. // add the room group to the room
  330. VSRoom &room = _room_pool[p_room];
  331. room._roomgroup_ids.push_back(p_roomgroup);
  332. }
  333. // Cull Instances
  334. RGhostHandle PortalRenderer::rghost_create(ObjectID p_object_id, const AABB &p_aabb) {
  335. uint32_t pool_id = 0;
  336. RGhost *moving = _rghost_pool.request(pool_id);
  337. moving->pool_id = pool_id;
  338. moving->object_id = p_object_id;
  339. moving->room_id = -1;
  340. RGhostHandle handle = pool_id + 1;
  341. rghost_update(handle, p_aabb);
  342. return handle;
  343. }
  344. void PortalRenderer::rghost_update(RGhostHandle p_handle, const AABB &p_aabb, bool p_force_reinsert) {
  345. if (!_loaded) {
  346. return;
  347. }
  348. p_handle--;
  349. RGhost &moving = _rghost_pool[p_handle];
  350. moving.exact_aabb = p_aabb;
  351. // quick reject for most roaming cases
  352. if (!p_force_reinsert && moving.expanded_aabb.encloses(p_aabb)) {
  353. return;
  354. }
  355. // using an expanded aabb allows us to make 'no op' moves
  356. // where the new aabb is within the expanded
  357. moving.expanded_aabb = p_aabb.grow(_roaming_expansion_margin);
  358. // if we got to here, it is roaming (moving between rooms)
  359. // remove from current rooms
  360. _rghost_remove_from_rooms(p_handle);
  361. // add to new rooms
  362. Vector3 center = p_aabb.position + (p_aabb.size * 0.5);
  363. int new_room = find_room_within(center, moving.room_id);
  364. moving.room_id = new_room;
  365. if (new_room != -1) {
  366. _bitfield_rooms.blank();
  367. sprawl_roaming(p_handle, moving, new_room, false);
  368. }
  369. }
  370. void PortalRenderer::rghost_destroy(RGhostHandle p_handle) {
  371. p_handle--;
  372. RGhost *moving = &_rghost_pool[p_handle];
  373. // if a roamer, remove from any current rooms
  374. _rghost_remove_from_rooms(p_handle);
  375. moving->destroy();
  376. // can now free the moving
  377. _rghost_pool.free(p_handle);
  378. }
  379. OccluderInstanceHandle PortalRenderer::occluder_instance_create() {
  380. uint32_t pool_id = 0;
  381. VSOccluder_Instance *occ = _occluder_instance_pool.request(pool_id);
  382. occ->create();
  383. OccluderInstanceHandle handle = pool_id + 1;
  384. return handle;
  385. }
  386. void PortalRenderer::occluder_instance_link(OccluderInstanceHandle p_handle, OccluderResourceHandle p_resource_handle) {
  387. p_handle--;
  388. VSOccluder_Instance &occ = _occluder_instance_pool[p_handle];
  389. // Unlink with any already linked, and destroy world resources
  390. if (occ.resource_pool_id != UINT32_MAX) {
  391. // Watch for bugs in future with the room within, this is not changed here,
  392. // but could potentially be removed and re-added in future if we use sprawling.
  393. occluder_instance_destroy(p_handle + 1, false);
  394. occ.resource_pool_id = UINT32_MAX;
  395. }
  396. p_resource_handle--;
  397. VSOccluder_Resource &res = VSG::scene->get_portal_resources().get_pool_occluder_resource(p_resource_handle);
  398. occ.resource_pool_id = p_resource_handle;
  399. occ.type = res.type;
  400. occ.revision = 0;
  401. }
  402. void PortalRenderer::occluder_instance_set_active(OccluderInstanceHandle p_handle, bool p_active) {
  403. p_handle--;
  404. VSOccluder_Instance &occ = _occluder_instance_pool[p_handle];
  405. if (occ.active == p_active) {
  406. return;
  407. }
  408. occ.active = p_active;
  409. // this will take care of adding or removing from rooms
  410. occluder_refresh_room_within(p_handle);
  411. }
  412. void PortalRenderer::occluder_instance_set_transform(OccluderInstanceHandle p_handle, const Transform &p_xform) {
  413. p_handle--;
  414. VSOccluder_Instance &occ = _occluder_instance_pool[p_handle];
  415. occ.xform = p_xform;
  416. // mark as dirty as the world space spheres will be out of date
  417. occ.revision = 0;
  418. // The room within is based on the xform, rather than the AABB so this
  419. // should still work even though the world space transform is deferred.
  420. // N.B. Occluders are a single room based on the center of the Occluder transform,
  421. // this may need to be improved at a later date.
  422. occluder_refresh_room_within(p_handle);
  423. }
  424. void PortalRenderer::occluder_refresh_room_within(uint32_t p_occluder_pool_id) {
  425. VSOccluder_Instance &occ = _occluder_instance_pool[p_occluder_pool_id];
  426. // if we aren't loaded, the room within can't be valid
  427. if (!_loaded) {
  428. occ.room_id = -1;
  429. return;
  430. }
  431. // inactive?
  432. if (!occ.active) {
  433. // remove from any rooms present in
  434. if (occ.room_id != -1) {
  435. _occluder_remove_from_rooms(p_occluder_pool_id);
  436. occ.room_id = -1;
  437. }
  438. return;
  439. }
  440. // prevent checks with no significant changes
  441. Vector3 offset = occ.xform.origin - occ.pt_center;
  442. // could possibly make this epsilon editable?
  443. // is highly world size dependent.
  444. if ((offset.length_squared() < 0.01) && (occ.room_id != -1)) {
  445. return;
  446. }
  447. // standardize on the node origin for now
  448. occ.pt_center = occ.xform.origin;
  449. int new_room = find_room_within(occ.pt_center, occ.room_id);
  450. if (new_room != occ.room_id) {
  451. _occluder_remove_from_rooms(p_occluder_pool_id);
  452. occ.room_id = new_room;
  453. if (new_room != -1) {
  454. VSRoom &room = get_room(new_room);
  455. room.add_occluder(p_occluder_pool_id);
  456. }
  457. }
  458. }
  459. void PortalRenderer::occluder_instance_destroy(OccluderInstanceHandle p_handle, bool p_free) {
  460. p_handle--;
  461. if (p_free) {
  462. _occluder_remove_from_rooms(p_handle);
  463. }
  464. // depending on the occluder type, remove the spheres etc
  465. VSOccluder_Instance &occ = _occluder_instance_pool[p_handle];
  466. switch (occ.type) {
  467. case VSOccluder_Instance::OT_SPHERE: {
  468. // free any spheres owned by the occluder
  469. for (int n = 0; n < occ.list_ids.size(); n++) {
  470. uint32_t id = occ.list_ids[n];
  471. _occluder_world_sphere_pool.free(id);
  472. }
  473. occ.list_ids.clear();
  474. } break;
  475. case VSOccluder_Instance::OT_MESH: {
  476. // free any polys owned by the occluder
  477. for (int n = 0; n < occ.list_ids.size(); n++) {
  478. uint32_t id = occ.list_ids[n];
  479. VSOccluder_Poly &poly = _occluder_world_poly_pool[id];
  480. // free any holes owned by the poly
  481. for (int h = 0; h < poly.num_holes; h++) {
  482. _occluder_world_hole_pool.free(poly.hole_pool_ids[h]);
  483. }
  484. // blanks
  485. poly.create();
  486. _occluder_world_poly_pool.free(id);
  487. }
  488. occ.list_ids.clear();
  489. } break;
  490. default: {
  491. } break;
  492. }
  493. if (p_free) {
  494. _occluder_instance_pool.free(p_handle);
  495. }
  496. }
  497. // Rooms
  498. RoomHandle PortalRenderer::room_create() {
  499. uint32_t pool_id = 0;
  500. VSRoom *room = _room_pool.request(pool_id);
  501. // explicit constructor
  502. room->create();
  503. // keep our own internal list of rooms
  504. room->_room_ID = _room_pool_ids.size();
  505. _room_pool_ids.push_back(pool_id);
  506. // plus one based handles, 0 is unset
  507. pool_id++;
  508. return pool_id;
  509. }
  510. void PortalRenderer::room_destroy(RoomHandle p_room) {
  511. ERR_FAIL_COND(!p_room);
  512. _ensure_unloaded("deleting Room");
  513. // plus one based
  514. p_room--;
  515. // remove from list of valid rooms
  516. VSRoom &room = _room_pool[p_room];
  517. int room_id = room._room_ID;
  518. // we need to replace the last element in the list
  519. _room_pool_ids.remove_unordered(room_id);
  520. // and reset the id of the portal that was the replacement
  521. if (room_id < _room_pool_ids.size()) {
  522. int replacement_pool_id = _room_pool_ids[room_id];
  523. VSRoom &replacement = _room_pool[replacement_pool_id];
  524. replacement._room_ID = room_id;
  525. }
  526. // explicitly run destructor
  527. _room_pool[p_room].destroy();
  528. // return to the pool
  529. _room_pool.free(p_room);
  530. }
  531. OcclusionHandle PortalRenderer::room_add_ghost(RoomHandle p_room, ObjectID p_object_id, const AABB &p_aabb) {
  532. ERR_FAIL_COND_V(!p_room, 0);
  533. p_room--; // plus one based
  534. VSStaticGhost ghost;
  535. ghost.object_id = p_object_id;
  536. _static_ghosts.push_back(ghost);
  537. // sprawl immediately
  538. // precreate a useful bitfield of rooms for use in sprawling
  539. if ((int)_bitfield_rooms.get_num_bits() != get_num_rooms()) {
  540. _bitfield_rooms.create(get_num_rooms());
  541. }
  542. // only can do if rooms exist
  543. if (get_num_rooms()) {
  544. // the last one was just added
  545. int ghost_id = _static_ghosts.size() - 1;
  546. // create a bitfield to indicate which rooms have been
  547. // visited already, to prevent visiting rooms multiple times
  548. _bitfield_rooms.blank();
  549. if (sprawl_static_ghost(ghost_id, p_aabb, p_room)) {
  550. _log("\t\tSPRAWLED");
  551. }
  552. }
  553. return OCCLUSION_HANDLE_ROOM_BIT;
  554. }
  555. OcclusionHandle PortalRenderer::room_add_instance(RoomHandle p_room, RID p_instance, const AABB &p_aabb, bool p_dynamic, const Vector<Vector3> &p_object_pts) {
  556. ERR_FAIL_COND_V(!p_room, 0);
  557. p_room--; // plus one based
  558. VSRoom &room = _room_pool[p_room];
  559. VSStatic stat;
  560. stat.instance = p_instance;
  561. stat.source_room_id = room._room_ID;
  562. stat.dynamic = p_dynamic;
  563. stat.aabb = p_aabb;
  564. _statics.push_back(stat);
  565. // sprawl immediately
  566. // precreate a useful bitfield of rooms for use in sprawling
  567. if ((int)_bitfield_rooms.get_num_bits() != get_num_rooms()) {
  568. _bitfield_rooms.create(get_num_rooms());
  569. }
  570. // only can do if rooms exist
  571. if (get_num_rooms()) {
  572. // the last one was just added
  573. int static_id = _statics.size() - 1;
  574. // pop last static
  575. const VSStatic &st = _statics[static_id];
  576. // create a bitfield to indicate which rooms have been
  577. // visited already, to prevent visiting rooms multiple times
  578. _bitfield_rooms.blank();
  579. if (p_object_pts.size()) {
  580. if (sprawl_static_geometry(static_id, st, st.source_room_id, p_object_pts)) {
  581. _log("\t\tSPRAWLED");
  582. }
  583. } else {
  584. if (sprawl_static(static_id, st, st.source_room_id)) {
  585. _log("\t\tSPRAWLED");
  586. }
  587. }
  588. }
  589. return OCCLUSION_HANDLE_ROOM_BIT;
  590. }
  591. void PortalRenderer::room_prepare(RoomHandle p_room, int32_t p_priority) {
  592. ERR_FAIL_COND(!p_room);
  593. p_room--; // plus one based
  594. VSRoom &room = _room_pool[p_room];
  595. room._priority = p_priority;
  596. }
  597. void PortalRenderer::room_set_bound(RoomHandle p_room, ObjectID p_room_object_id, const Vector<Plane> &p_convex, const AABB &p_aabb, const Vector<Vector3> &p_verts) {
  598. ERR_FAIL_COND(!p_room);
  599. p_room--; // plus one based
  600. VSRoom &room = _room_pool[p_room];
  601. room._planes = p_convex;
  602. room._verts = p_verts;
  603. room._aabb = p_aabb;
  604. room._godot_instance_ID = p_room_object_id;
  605. }
  606. void PortalRenderer::_add_portal_to_convex_hull(LocalVector<Plane, int32_t> &p_planes, const Plane &p) {
  607. for (int n = 0; n < p_planes.size(); n++) {
  608. Plane &o = p_planes[n];
  609. // this is a fudge factor for how close the portal can be to an existing plane
  610. // to be to be considered the same ...
  611. // to prevent needless extra checks.
  612. // the epsilons should probably be more exact here than for the convex hull simplification, as it is
  613. // fairly crucial that the portal planes are reasonably accurate for determining the hull.
  614. // and because the portal plane is more important, we will REPLACE the existing similar plane
  615. // with the portal plane.
  616. const real_t d = 0.03; // 0.08f
  617. if (Math::abs(p.d - o.d) > d) {
  618. continue;
  619. }
  620. real_t dot = p.normal.dot(o.normal);
  621. if (dot < 0.99) // 0.98f
  622. {
  623. continue;
  624. }
  625. // match!
  626. // replace the existing plane
  627. o = p;
  628. return;
  629. }
  630. // there is no existing plane that is similar, create a new one especially for the portal
  631. p_planes.push_back(p);
  632. }
  633. void PortalRenderer::_rooms_add_portals_to_convex_hulls() {
  634. for (int n = 0; n < get_num_rooms(); n++) {
  635. VSRoom &room = get_room(n);
  636. for (int p = 0; p < room._portal_ids.size(); p++) {
  637. const VSPortal &portal = get_portal(room._portal_ids[p]);
  638. // everything depends on whether the portal is incoming or outgoing.
  639. // if incoming we reverse the logic.
  640. int outgoing = 1;
  641. int room_a_id = portal._linkedroom_ID[0];
  642. if (room_a_id != n) {
  643. outgoing = 0;
  644. DEV_ASSERT(portal._linkedroom_ID[1] == n);
  645. }
  646. // do not add internal portals to the convex hull of outer rooms!
  647. if (!outgoing && portal._internal) {
  648. continue;
  649. }
  650. // add the portal plane
  651. Plane portal_plane = portal._plane;
  652. if (!outgoing) {
  653. portal_plane = -portal_plane;
  654. }
  655. // add if sufficiently different from existing convex hull planes
  656. _add_portal_to_convex_hull(room._planes, portal_plane);
  657. }
  658. }
  659. }
  660. void PortalRenderer::rooms_finalize(bool p_generate_pvs, bool p_cull_using_pvs, bool p_use_secondary_pvs, bool p_use_signals, String p_pvs_filename, bool p_use_simple_pvs, bool p_log_pvs_generation) {
  661. _gameplay_monitor.set_params(p_use_secondary_pvs, p_use_signals);
  662. // portals should also bound the rooms, the room geometry may extend past the portal
  663. _rooms_add_portals_to_convex_hulls();
  664. // the trace results can never have more hits than the number of static objects
  665. _trace_results.create(_statics.size());
  666. // precreate a useful bitfield of rooms for use in sprawling, if not created already
  667. // (may not be necessary but just in case, rooms with no statics etc)
  668. _bitfield_rooms.create(_room_pool_ids.size());
  669. // the rooms looksup is a pre-calced grid structure for faster lookup of the nearest room
  670. // from position
  671. _rooms_lookup_bsp.create(*this);
  672. // calculate PVS
  673. if (p_generate_pvs) {
  674. PVSBuilder pvs;
  675. pvs.calculate_pvs(*this, p_pvs_filename, _tracer.get_depth_limit(), p_use_simple_pvs, p_log_pvs_generation);
  676. _cull_using_pvs = p_cull_using_pvs; // hard code to on for test
  677. } else {
  678. _cull_using_pvs = false;
  679. }
  680. _loaded = true;
  681. // all the roaming objects need to be sprawled into the rooms
  682. // (they may have been created before the rooms)
  683. _load_finalize_roaming();
  684. // allow deleting any intermediate data
  685. for (int n = 0; n < get_num_rooms(); n++) {
  686. get_room(n).cleanup_after_conversion();
  687. }
  688. // this should probably have some thread protection, but I doubt it matters
  689. // as this will worst case give wrong result for a frame
  690. Engine::get_singleton()->set_portals_active(true);
  691. _log("Room conversion complete. " + itos(_room_pool_ids.size()) + " rooms, " + itos(_portal_pool_ids.size()) + " portals.", 1);
  692. }
  693. bool PortalRenderer::sprawl_static_geometry(int p_static_id, const VSStatic &p_static, int p_room_id, const Vector<Vector3> &p_object_pts) {
  694. // set, and if room already done, ignore
  695. if (!_bitfield_rooms.check_and_set(p_room_id))
  696. return false;
  697. VSRoom &room = get_room(p_room_id);
  698. room._static_ids.push_back(p_static_id);
  699. bool sprawled = false;
  700. // go through portals
  701. for (int p = 0; p < room._portal_ids.size(); p++) {
  702. const VSPortal &portal = get_portal(room._portal_ids[p]);
  703. int room_to_id = portal.geometry_crosses_portal(p_room_id, p_static.aabb, p_object_pts);
  704. if (room_to_id != -1) {
  705. // _log(String(Variant(p_static.aabb)) + " crosses portal");
  706. sprawl_static_geometry(p_static_id, p_static, room_to_id, p_object_pts);
  707. sprawled = true;
  708. }
  709. }
  710. return sprawled;
  711. }
  712. bool PortalRenderer::sprawl_static_ghost(int p_ghost_id, const AABB &p_aabb, int p_room_id) {
  713. // set, and if room already done, ignore
  714. if (!_bitfield_rooms.check_and_set(p_room_id)) {
  715. return false;
  716. }
  717. VSRoom &room = get_room(p_room_id);
  718. room._static_ghost_ids.push_back(p_ghost_id);
  719. bool sprawled = false;
  720. // go through portals
  721. for (int p = 0; p < room._portal_ids.size(); p++) {
  722. const VSPortal &portal = get_portal(room._portal_ids[p]);
  723. int room_to_id = portal.crosses_portal(p_room_id, p_aabb, true);
  724. if (room_to_id != -1) {
  725. // _log(String(Variant(p_aabb)) + " crosses portal");
  726. sprawl_static_ghost(p_ghost_id, p_aabb, room_to_id);
  727. sprawled = true;
  728. }
  729. }
  730. return sprawled;
  731. }
  732. bool PortalRenderer::sprawl_static(int p_static_id, const VSStatic &p_static, int p_room_id) {
  733. // set, and if room already done, ignore
  734. if (!_bitfield_rooms.check_and_set(p_room_id)) {
  735. return false;
  736. }
  737. VSRoom &room = get_room(p_room_id);
  738. room._static_ids.push_back(p_static_id);
  739. bool sprawled = false;
  740. // go through portals
  741. for (int p = 0; p < room._portal_ids.size(); p++) {
  742. const VSPortal &portal = get_portal(room._portal_ids[p]);
  743. int room_to_id = portal.crosses_portal(p_room_id, p_static.aabb, true);
  744. if (room_to_id != -1) {
  745. // _log(String(Variant(p_static.aabb)) + " crosses portal");
  746. sprawl_static(p_static_id, p_static, room_to_id);
  747. sprawled = true;
  748. }
  749. }
  750. return sprawled;
  751. }
  752. void PortalRenderer::_load_finalize_roaming() {
  753. for (int n = 0; n < _moving_list_roaming.size(); n++) {
  754. uint32_t pool_id = _moving_list_roaming[n];
  755. Moving &moving = _moving_pool[pool_id];
  756. const AABB &aabb = moving.exact_aabb;
  757. OcclusionHandle handle = pool_id + 1;
  758. instance_moving_update(handle, aabb, true);
  759. }
  760. for (unsigned int n = 0; n < _rghost_pool.active_size(); n++) {
  761. RGhost &moving = _rghost_pool.get_active(n);
  762. const AABB &aabb = moving.exact_aabb;
  763. rghost_update(_rghost_pool.get_active_id(n) + 1, aabb, true);
  764. }
  765. for (unsigned int n = 0; n < _occluder_instance_pool.active_size(); n++) {
  766. VSOccluder_Instance &occ = _occluder_instance_pool.get_active(n);
  767. int occluder_id = _occluder_instance_pool.get_active_id(n);
  768. // make sure occluder is in the correct room
  769. occ.room_id = find_room_within(occ.pt_center, -1);
  770. if (occ.room_id != -1) {
  771. VSRoom &room = get_room(occ.room_id);
  772. room.add_occluder(occluder_id);
  773. }
  774. }
  775. }
  776. void PortalRenderer::sprawl_roaming(uint32_t p_mover_pool_id, MovingBase &r_moving, int p_room_id, bool p_moving_or_ghost) {
  777. // set, and if room already done, ignore
  778. if (!_bitfield_rooms.check_and_set(p_room_id)) {
  779. return;
  780. }
  781. // add to the room
  782. VSRoom &room = get_room(p_room_id);
  783. if (p_moving_or_ghost) {
  784. room.add_roamer(p_mover_pool_id);
  785. } else {
  786. room.add_rghost(p_mover_pool_id);
  787. }
  788. // add the room to the mover
  789. r_moving._rooms.push_back(p_room_id);
  790. // go through portals
  791. for (int p = 0; p < room._portal_ids.size(); p++) {
  792. const VSPortal &portal = get_portal(room._portal_ids[p]);
  793. int room_to_id = portal.crosses_portal(p_room_id, r_moving.expanded_aabb);
  794. if (room_to_id != -1) {
  795. // _log(String(Variant(p_static.aabb)) + " crosses portal");
  796. sprawl_roaming(p_mover_pool_id, r_moving, room_to_id, p_moving_or_ghost);
  797. }
  798. }
  799. }
  800. // This gets called when you delete an instance the the room system depends on
  801. void PortalRenderer::_ensure_unloaded(String p_reason) {
  802. if (_loaded) {
  803. _loaded = false;
  804. _gameplay_monitor.unload(*this);
  805. String str;
  806. if (p_reason != String()) {
  807. str = "Portal system unloaded ( " + p_reason + " ).";
  808. } else {
  809. str = "Portal system unloaded.";
  810. }
  811. _log(str, 1);
  812. // this should probably have some thread protection, but I doubt it matters
  813. // as this will worst case give wrong result for a frame
  814. Engine::get_singleton()->set_portals_active(false);
  815. }
  816. }
  817. void PortalRenderer::rooms_and_portals_clear() {
  818. _loaded = false;
  819. // N.B. We want to make sure all the tick counters on movings rooms etc to zero,
  820. // so that on loading the next level gameplay entered signals etc will be
  821. // correctly sent and everything is fresh.
  822. // This is mostly done by the gameplay_monitor, but rooms_and_portals_clear()
  823. // will also clear tick counters where possible
  824. // (there is no TrackedList for the RoomGroup pool for example).
  825. // This could be made neater by moving everything to TrackedPooledLists, but this
  826. // may be overkill.
  827. _gameplay_monitor.unload(*this);
  828. _statics.clear();
  829. _static_ghosts.clear();
  830. // the rooms and portals should remove their id when they delete themselves
  831. // from the scene tree by calling room_destroy and portal_destroy ...
  832. // therefore there should be no need to clear these here
  833. // _room_pool_ids.clear();
  834. // _portal_pool_ids.clear();
  835. _rooms_lookup_bsp.clear();
  836. // clear the portals out of each existing room
  837. for (int n = 0; n < get_num_rooms(); n++) {
  838. VSRoom &room = get_room(n);
  839. room.rooms_and_portals_clear();
  840. }
  841. for (int n = 0; n < get_num_portals(); n++) {
  842. VSPortal &portal = get_portal(n);
  843. portal.rooms_and_portals_clear();
  844. }
  845. // when the rooms_and_portals_clear message is sent,
  846. // we want to remove all references to old rooms in the moving
  847. // objects, to prevent dangling references.
  848. for (int n = 0; n < get_num_moving_globals(); n++) {
  849. Moving &moving = get_pool_moving(_moving_list_global[n]);
  850. moving.rooms_and_portals_clear();
  851. }
  852. for (int n = 0; n < _moving_list_roaming.size(); n++) {
  853. Moving &moving = get_pool_moving(_moving_list_roaming[n]);
  854. moving.rooms_and_portals_clear();
  855. }
  856. for (unsigned int n = 0; n < _rghost_pool.active_size(); n++) {
  857. RGhost &moving = _rghost_pool.get_active(n);
  858. moving.rooms_and_portals_clear();
  859. }
  860. _pvs.clear();
  861. }
  862. void PortalRenderer::rooms_override_camera(bool p_override, const Vector3 &p_point, const Vector<Plane> *p_convex) {
  863. _override_camera = p_override;
  864. _override_camera_pos = p_point;
  865. if (p_convex) {
  866. _override_camera_planes = *p_convex;
  867. }
  868. }
  869. void PortalRenderer::rooms_update_gameplay_monitor(const Vector<Vector3> &p_camera_positions) {
  870. // is the pvs loaded?
  871. if (!_loaded || !_pvs.is_loaded()) {
  872. if (!_pvs.is_loaded()) {
  873. WARN_PRINT_ONCE("RoomManager PVS is required for this functionality");
  874. }
  875. return;
  876. }
  877. int *source_rooms = (int *)alloca(sizeof(int) * p_camera_positions.size());
  878. int num_source_rooms = 0;
  879. for (int n = 0; n < p_camera_positions.size(); n++) {
  880. int source_room_id = find_room_within(p_camera_positions[n]);
  881. if (source_room_id == -1) {
  882. continue;
  883. }
  884. source_rooms[num_source_rooms++] = source_room_id;
  885. }
  886. _gameplay_monitor.update_gameplay(*this, source_rooms, num_source_rooms);
  887. }
  888. int PortalRenderer::cull_convex_implementation(const Vector3 &p_point, const Vector3 &p_cam_dir, const CameraMatrix &p_cam_matrix, const Vector<Plane> &p_convex, VSInstance **p_result_array, int p_result_max, uint32_t p_mask, int32_t &r_previous_room_id_hint) {
  889. // start room
  890. int start_room_id = find_room_within(p_point, r_previous_room_id_hint);
  891. // return the previous room hint
  892. r_previous_room_id_hint = start_room_id;
  893. if (start_room_id == -1) {
  894. return -1;
  895. }
  896. // set up the occlusion culler once off .. this is a prepare before the prepare is done PER room
  897. _tracer.get_occlusion_culler().prepare_camera(p_cam_matrix, p_cam_dir);
  898. // planes must be in CameraMatrix order
  899. DEV_ASSERT(p_convex.size() == 6);
  900. LocalVector<Plane> planes;
  901. planes = p_convex;
  902. _trace_results.clear();
  903. if (!_debug_sprawl) {
  904. _tracer.trace(*this, p_point, planes, start_room_id, _trace_results); //, near_and_far_planes);
  905. } else {
  906. _tracer.trace_debug_sprawl(*this, p_point, start_room_id, _trace_results);
  907. }
  908. int num_results = _trace_results.visible_static_ids.size();
  909. int out_count = 0;
  910. for (int n = 0; n < num_results; n++) {
  911. uint32_t static_id = _trace_results.visible_static_ids[n];
  912. RID static_rid = _statics[static_id].instance;
  913. VSInstance *instance = VSG::scene->_instance_get_from_rid(static_rid);
  914. if (VSG::scene->_instance_cull_check(instance, p_mask)) {
  915. p_result_array[out_count++] = instance;
  916. if (out_count >= p_result_max) {
  917. break;
  918. }
  919. }
  920. }
  921. // results could be full up already
  922. if (out_count >= p_result_max) {
  923. return out_count;
  924. }
  925. // add the roaming results
  926. // cap to the maximum results
  927. int num_roam_hits = _trace_results.visible_roamer_pool_ids.size();
  928. // translate
  929. for (int n = 0; n < num_roam_hits; n++) {
  930. const Moving &moving = get_pool_moving(_trace_results.visible_roamer_pool_ids[n]);
  931. if (VSG::scene->_instance_cull_check(moving.instance, p_mask)) {
  932. p_result_array[out_count++] = moving.instance;
  933. if (out_count >= p_result_max) {
  934. break;
  935. }
  936. }
  937. }
  938. // results could be full up already
  939. if (out_count >= p_result_max) {
  940. return out_count;
  941. }
  942. out_count = _tracer.trace_globals(planes, p_result_array, out_count, p_result_max, p_mask, _override_camera);
  943. return out_count;
  944. }
  945. String PortalRenderer::_rid_to_string(RID p_rid) {
  946. return itos(p_rid.get_id());
  947. }
  948. String PortalRenderer::_addr_to_string(const void *p_addr) {
  949. return String::num_uint64((uint64_t)p_addr, 16);
  950. }
  951. PortalRenderer::PortalRenderer() {
  952. _show_debug = GLOBAL_GET("rendering/portals/debug/logging");
  953. }