portal_renderer.cpp 34 KB

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