diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 7a6d1c20a..0c5365c8d 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -88,6 +88,8 @@ #include "utils/translation.hpp" #include "utils/vs.hpp" +#include +#include #include #if !defined(SERVER_ONLY) && defined(ANDROID) @@ -322,38 +324,43 @@ void IrrDriver::updateConfigIfRelevant() } #endif // !SERVER_ONLY } // updateConfigIfRelevant -core::recti IrrDriver::getSplitscreenWindow(int WindowNum) + +// ---------------------------------------------------------------------------- +core::recti IrrDriver::getSplitscreenWindow(int window_num) { - const int playernum = RaceManager::get()->getNumLocalPlayers(); - const float playernum_sqrt = sqrtf((float)playernum); - - int rows = int( UserConfigParams::split_screen_horizontally - ? ceil(playernum_sqrt) - : round(playernum_sqrt) ); - int cols = int( UserConfigParams::split_screen_horizontally - ? round(playernum_sqrt) - : ceil(playernum_sqrt) ); - - if (rows == 0){rows = 1;} - if (cols == 0) {cols = 1;} - //This could add a bit of overhang - const int width_of_space = - int(ceil( (float)irr_driver->getActualScreenSize().Width - / (float)cols) ); - const int height_of_space = - int (ceil( (float)irr_driver->getActualScreenSize().Height - / (float)rows) ); + // Determine the number of columns and rows needed + int total_players = RaceManager::get()->getNumLocalPlayers(); + if (total_players < 1) + total_players = 1; + int columns = (int)(std::ceil(std::sqrt(total_players))); + int rows = (int)(std::ceil((double)(total_players) / columns)); + if (UserConfigParams::split_screen_horizontally) + std::swap(columns, rows); - const int x_grid_Position = WindowNum % cols; - const int y_grid_Position = int(floor((WindowNum) / cols)); + // Calculate the base dimensions of each viewport + int base_viewport_width = irr_driver->getActualScreenSize().Width / columns; + int base_viewport_height = irr_driver->getActualScreenSize().Height / rows; + + // Calculate remaining pixels to distribute + int extra_width = irr_driver->getActualScreenSize().Width % columns; + int extra_height = irr_driver->getActualScreenSize().Height % rows; + + // Determine the row and column for the given player index + int row = window_num / columns; + int col = window_num % columns; + + // Calculate the top-left corner of the viewport + int viewport_x = col * base_viewport_width + std::min(col, extra_width); + int viewport_y = row * base_viewport_height + std::min(row, extra_height); + + // Adjust width and height to fully occupy the remaining pixels + int viewport_width = base_viewport_width + (col < extra_width ? 1 : 0); + int viewport_height = base_viewport_height + (row < extra_height ? 1 : 0); + + return core::recti(core::position2di(viewport_x, viewport_y), + core::dimension2du(viewport_width, viewport_height)); +} // getSplitscreenWindow -//To prevent the viewport going over the right side, we use std::min to ensure the right corners are never larger than the total width - return core::recti( - x_grid_Position * width_of_space, - y_grid_Position * height_of_space, - (x_grid_Position * width_of_space) + width_of_space, - (y_grid_Position * height_of_space) + height_of_space); -} // ---------------------------------------------------------------------------- /** Gets a list of supported video modes from the irrlicht device. This data * is stored in m_modes. diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index 6a183d012..0382430fa 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -214,7 +214,7 @@ public: void increaseObjectCount(); core::array &getMainSetup(); void updateConfigIfRelevant(); - core::recti getSplitscreenWindow(int WindowNum); + core::recti getSplitscreenWindow(int window_num); void setAllMaterialFlags(scene::IMesh *mesh) const; scene::IAnimatedMesh *getAnimatedMesh(const std::string &name); scene::IMesh *getMesh(const std::string &name);