mirror of
https://github.com/godotengine/godot.git
synced 2026-01-06 10:11:57 +03:00
Portals - Add the ability to autoplace static objects
In order to make level building easier, the system can now support STATIC and DYNAMIC objects in the roomlist that are not placed in rooms. The system will automatically place them in the appropriate room.
This commit is contained in:
@@ -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;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
Reference in New Issue
Block a user