|
@@ -557,9 +557,7 @@ void RoomManager::rooms_convert() {
|
|
|
|
|
|
// first check that the roomlist is valid, and the user hasn't made
|
|
|
// a silly scene tree
|
|
|
- Node *invalid_node = _check_roomlist_validity_recursive(_roomlist);
|
|
|
- if (invalid_node) {
|
|
|
- show_warning("RoomList contains invalid node", "RoomList should only contain Rooms, RoomGroups and Spatials.\nInvalid node : " + invalid_node->get_name());
|
|
|
+ if (!_check_roomlist_validity(_roomlist)) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -585,7 +583,7 @@ void RoomManager::rooms_convert() {
|
|
|
|
|
|
// autolink portals that are not already manually linked
|
|
|
// and finalize the portals
|
|
|
- _third_pass_portals(_roomlist, portals);
|
|
|
+ _autolink_portals(_roomlist, portals);
|
|
|
|
|
|
// Find the statics AGAIN and only this time add them to the PortalRenderer.
|
|
|
// We need to do this twice because the room points determine the room bound...
|
|
@@ -595,6 +593,11 @@ void RoomManager::rooms_convert() {
|
|
|
// Also finalize the room hulls.
|
|
|
_third_pass_rooms(portals);
|
|
|
|
|
|
+ // now we run autoplace to place any statics that have not been explicitly placed in rooms.
|
|
|
+ // These will by definition not affect the room bounds, but is convenient for users to edit
|
|
|
+ // levels in a more freeform manner
|
|
|
+ _autoplace_recursive(_roomlist);
|
|
|
+
|
|
|
bool generate_pvs = false;
|
|
|
bool pvs_cull = false;
|
|
|
switch (_pvs_mode) {
|
|
@@ -866,8 +869,8 @@ void RoomManager::_second_pass_portals(Spatial *p_roomlist, LocalVector<Portal *
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void RoomManager::_third_pass_portals(Spatial *p_roomlist, LocalVector<Portal *> &r_portals) {
|
|
|
- convert_log("_third_pass_portals");
|
|
|
+void RoomManager::_autolink_portals(Spatial *p_roomlist, LocalVector<Portal *> &r_portals) {
|
|
|
+ convert_log("_autolink_portals");
|
|
|
|
|
|
for (unsigned int n = 0; n < r_portals.size(); n++) {
|
|
|
Portal *portal = r_portals[n];
|
|
@@ -965,44 +968,13 @@ void RoomManager::_third_pass_portals(Spatial *p_roomlist, LocalVector<Portal *>
|
|
|
|
|
|
// to prevent users creating mistakes for themselves, we limit what can be put into the room list branch.
|
|
|
// returns invalid node, or NULL
|
|
|
-Node *RoomManager::_check_roomlist_validity_recursive(Node *p_node) {
|
|
|
- bool ok = false;
|
|
|
-
|
|
|
- // is this a room?
|
|
|
- if (_name_starts_with(p_node, "Room") || _node_is_type<Room>(p_node)) {
|
|
|
- // end the recursion here
|
|
|
- return nullptr;
|
|
|
- }
|
|
|
-
|
|
|
- // is this a roomgroup?
|
|
|
- if (_name_starts_with(p_node, "RoomGroup") || _node_is_type<RoomGroup>(p_node)) {
|
|
|
- // end the recursion here
|
|
|
- return nullptr;
|
|
|
- }
|
|
|
-
|
|
|
- // now we are getting dodgy.
|
|
|
- // is it a Spatial? (and not a derived)
|
|
|
- if (p_node->get_class_name() == "Spatial") {
|
|
|
- ok = true;
|
|
|
- }
|
|
|
-
|
|
|
- if (!ok) {
|
|
|
- // return the invalid node
|
|
|
- return p_node;
|
|
|
- }
|
|
|
-
|
|
|
- // recurse
|
|
|
- for (int n = 0; n < p_node->get_child_count(); n++) {
|
|
|
- Node *child = p_node->get_child(n);
|
|
|
- if (child) {
|
|
|
- Node *invalid_node = _check_roomlist_validity_recursive(child);
|
|
|
- if (invalid_node) {
|
|
|
- return invalid_node;
|
|
|
- }
|
|
|
- }
|
|
|
+bool RoomManager::_check_roomlist_validity(Node *p_node) {
|
|
|
+ if (Room::detect_nodes_of_type<RoomManager>(p_node, false)) {
|
|
|
+ show_warning("RoomList should not be the RoomManager,\nor contain a RoomManager as child or grandchild.");
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- return nullptr;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
void RoomManager::_convert_rooms_recursive(Spatial *p_node, LocalVector<Portal *> &r_portals, LocalVector<RoomGroup *> &r_roomgroups, int p_roomgroup) {
|
|
@@ -1159,13 +1131,69 @@ void RoomManager::_check_portal_for_warnings(Portal *p_portal, const AABB &p_roo
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-void RoomManager::_find_statics_recursive(Room *p_room, Spatial *p_node, Vector<Vector3> &r_room_pts, bool p_add_to_portal_renderer) {
|
|
|
- // don't process portal MeshInstances that are being deleted
|
|
|
- // (and replaced by proper Portal nodes)
|
|
|
+bool RoomManager::_autoplace_object(VisualInstance *p_vi) {
|
|
|
+ // note we could alternatively use the portal_renderer to do this more efficiently
|
|
|
+ // (as it has a BSP) but at a cost of returning result from the visual server
|
|
|
+ AABB bb = p_vi->get_transformed_aabb();
|
|
|
+ Vector3 centre = bb.get_center();
|
|
|
+
|
|
|
+ // in order to deal with internal rooms, we can't just stop at the first
|
|
|
+ // room the point is within, as there could be later rooms with a higher priority
|
|
|
+ int best_priority = -INT32_MAX;
|
|
|
+ Room *best_room = nullptr;
|
|
|
+
|
|
|
+ for (int n = 0; n < _rooms.size(); n++) {
|
|
|
+ Room *room = _rooms[n];
|
|
|
+
|
|
|
+ if (room->contains_point(centre)) {
|
|
|
+ if (room->_room_priority > best_priority) {
|
|
|
+ best_priority = room->_room_priority;
|
|
|
+ best_room = room;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (best_room) {
|
|
|
+ // just dummies, we won't use these this time
|
|
|
+ Vector<Vector3> room_pts;
|
|
|
+
|
|
|
+ // we can reuse this function
|
|
|
+ _process_static(best_room, p_vi, room_pts, true);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void RoomManager::_autoplace_recursive(Spatial *p_node) {
|
|
|
if (p_node->is_queued_for_deletion()) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ VisualInstance *vi = Object::cast_to<VisualInstance>(p_node);
|
|
|
+
|
|
|
+ // we are only interested in VIs with static or dynamic mode
|
|
|
+ if (vi) {
|
|
|
+ switch (vi->get_portal_mode()) {
|
|
|
+ default: {
|
|
|
+ } break;
|
|
|
+ case CullInstance::PORTAL_MODE_DYNAMIC:
|
|
|
+ case CullInstance::PORTAL_MODE_STATIC: {
|
|
|
+ _autoplace_object(vi);
|
|
|
+ } break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int n = 0; n < p_node->get_child_count(); n++) {
|
|
|
+ Spatial *child = Object::cast_to<Spatial>(p_node->get_child(n));
|
|
|
+
|
|
|
+ if (child) {
|
|
|
+ _autoplace_recursive(child);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void RoomManager::_process_static(Room *p_room, Spatial *p_node, Vector<Vector3> &r_room_pts, bool p_add_to_portal_renderer) {
|
|
|
bool ignore = false;
|
|
|
VisualInstance *vi = Object::cast_to<VisualInstance>(p_node);
|
|
|
|
|
@@ -1269,6 +1297,16 @@ void RoomManager::_find_statics_recursive(Room *p_room, Spatial *p_node, Vector<
|
|
|
}
|
|
|
|
|
|
} // if not ignore
|
|
|
+}
|
|
|
+
|
|
|
+void RoomManager::_find_statics_recursive(Room *p_room, Spatial *p_node, Vector<Vector3> &r_room_pts, bool p_add_to_portal_renderer) {
|
|
|
+ // don't process portal MeshInstances that are being deleted
|
|
|
+ // (and replaced by proper Portal nodes)
|
|
|
+ if (p_node->is_queued_for_deletion()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ _process_static(p_room, p_node, r_room_pts, p_add_to_portal_renderer);
|
|
|
|
|
|
for (int n = 0; n < p_node->get_child_count(); n++) {
|
|
|
Spatial *child = Object::cast_to<Spatial>(p_node->get_child(n));
|