diff --git a/data/gui/options_ui.stkgui b/data/gui/options_ui.stkgui index 2c654be7b..737104b0d 100644 --- a/data/gui/options_ui.stkgui +++ b/data/gui/options_ui.stkgui @@ -72,8 +72,12 @@ - - + +
+ + +
diff --git a/data/skins/Forest.stkskin b/data/skins/Forest.stkskin index cd7514f44..ac6a071d0 100644 --- a/data/skins/Forest.stkskin +++ b/data/skins/Forest.stkskin @@ -129,6 +129,9 @@ when the border that intersect at this corner are enabled. hborder_out_portion="0.2" /> + diff --git a/data/skins/Ocean.stkskin b/data/skins/Ocean.stkskin index b251e5b37..72b93bfda 100644 --- a/data/skins/Ocean.stkskin +++ b/data/skins/Ocean.stkskin @@ -128,6 +128,9 @@ when the border that intersect at this corner are enabled. hborder_out_portion="0.2" /> + diff --git a/data/skins/Peach.stkskin b/data/skins/Peach.stkskin index 4b67f0f5b..2f2ab97d4 100644 --- a/data/skins/Peach.stkskin +++ b/data/skins/Peach.stkskin @@ -129,6 +129,9 @@ when the border that intersect at this corner are enabled. + diff --git a/data/skins/Ruby.stkskin b/data/skins/Ruby.stkskin index 76407f632..844fcc2d9 100644 --- a/data/skins/Ruby.stkskin +++ b/data/skins/Ruby.stkskin @@ -130,6 +130,9 @@ when the border that intersect at this corner are enabled. + diff --git a/data/skins/forest/glass_square_focused_bw.png b/data/skins/forest/glass_square_focused_bw.png new file mode 100644 index 000000000..300633757 Binary files /dev/null and b/data/skins/forest/glass_square_focused_bw.png differ diff --git a/data/skins/ocean/glass_square_focused_bw.png b/data/skins/ocean/glass_square_focused_bw.png new file mode 100644 index 000000000..8319920d5 Binary files /dev/null and b/data/skins/ocean/glass_square_focused_bw.png differ diff --git a/data/skins/peach/glass_square_focused_bw.png b/data/skins/peach/glass_square_focused_bw.png new file mode 100644 index 000000000..113c08a6f Binary files /dev/null and b/data/skins/peach/glass_square_focused_bw.png differ diff --git a/data/skins/ruby/glass_square_focused_bw.png b/data/skins/ruby/glass_square_focused_bw.png new file mode 100644 index 000000000..5ca9e5454 Binary files /dev/null and b/data/skins/ruby/glass_square_focused_bw.png differ diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index 8be5181e6..acf29279c 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -269,10 +269,14 @@ void STKConfig::getAllData(const XMLNode * root) if (const XMLNode *camera = root->getNode("camera")) { - camera->get("fov-1", &m_camera_fov[0]); - camera->get("fov-2", &m_camera_fov[1]); - camera->get("fov-3", &m_camera_fov[2]); - camera->get("fov-4", &m_camera_fov[3]); + for (int i = 0; i < 4; i++) + { + camera->get("fov-" + std::to_string(i + 1), &m_camera_fov[i]); + } + for (int i = 4; i < MAX_PLAYER_COUNT; i++) + { + camera->get("fov-" + std::to_string(4), &m_camera_fov[i]); + } camera->get("cutscene-fov", &m_cutscene_fov); } diff --git a/src/config/stk_config.hpp b/src/config/stk_config.hpp index f58853848..a04879b35 100644 --- a/src/config/stk_config.hpp +++ b/src/config/stk_config.hpp @@ -29,6 +29,7 @@ #include "network/remote_kart_info.hpp" #include "utils/no_copy.hpp" +#include "utils/constants.hpp" #include #include #include @@ -148,7 +149,7 @@ public: float m_replay_delta_angle; /** The field of view for 1, 2, 3, 4 player split screen. */ - float m_camera_fov[4]; + float m_camera_fov[MAX_PLAYER_COUNT]; float m_cutscene_fov; diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index ae414a515..ead7a1a73 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -561,7 +561,10 @@ namespace UserConfigParams PARAM_PREFIX BoolUserConfigParam m_force_legacy_device PARAM_DEFAULT(BoolUserConfigParam(false, "force_legacy_device", &m_video_group, "Force OpenGL 2 context, even if OpenGL 3 is available.")); - + PARAM_PREFIX BoolUserConfigParam split_screen_horizontally + PARAM_DEFAULT(BoolUserConfigParam(true, "split_screen_horizontally", + &m_video_group, "When playing a non-square amount of players (e.g. 2)," + " should it split horizontally (top/bottom)")); PARAM_PREFIX BoolUserConfigParam m_texture_compression PARAM_DEFAULT(BoolUserConfigParam(true, "enable_texture_compression", &m_video_group, "Enable Texture Compression")); @@ -614,7 +617,6 @@ namespace UserConfigParams PARAM_DEFAULT(BoolUserConfigParam(true, "limit_game_fps", &m_recording_group, "Limit game framerate not beyond the fps of" " recording video.")); - PARAM_PREFIX IntUserConfigParam m_video_format PARAM_DEFAULT(IntUserConfigParam(0, "video_format", &m_recording_group, "Specify the video for record, which is the enum" @@ -743,7 +745,7 @@ namespace UserConfigParams "stun.voxgratia.org", "stun.xten.com") ); - // ---- Gamemode setup + // ---- Gamemode setup PARAM_PREFIX IntToIntUserConfigParam m_num_karts_per_gamemode PARAM_DEFAULT(IntToIntUserConfigParam("num_karts_per_gamemode", "The Number of karts per gamemode.", @@ -845,7 +847,7 @@ namespace UserConfigParams PARAM_PREFIX BoolUserConfigParam m_log_errors_to_console PARAM_DEFAULT( BoolUserConfigParam( CONSOLE_DEFAULT, "log_errors", "Enable logging to console.") ); - + // ---- Camera PARAM_PREFIX GroupUserConfigParam m_camera PARAM_DEFAULT( GroupUserConfigParam("camera", diff --git a/src/graphics/camera.cpp b/src/graphics/camera.cpp index e908f46b4..083b28e1d 100644 --- a/src/graphics/camera.cpp +++ b/src/graphics/camera.cpp @@ -163,71 +163,15 @@ void Camera::setKart(AbstractKart *new_kart) */ void Camera::setupCamera() { - m_aspect = (float)(irr_driver->getActualScreenSize().Width) - / irr_driver->getActualScreenSize().Height; - switch(race_manager->getNumLocalPlayers()) - { - case 1: m_viewport = core::recti(0, 0, - irr_driver->getActualScreenSize().Width, - irr_driver->getActualScreenSize().Height); - m_scaling = core::vector2df(1.0f, 1.0f); - m_fov = DEGREE_TO_RAD*stk_config->m_camera_fov[0]; - break; - case 2: m_viewport = core::recti(0, - m_index==0 ? 0 - : irr_driver->getActualScreenSize().Height>>1, - irr_driver->getActualScreenSize().Width, - m_index==0 ? irr_driver->getActualScreenSize().Height>>1 - : irr_driver->getActualScreenSize().Height); - m_scaling = core::vector2df(1.0f, 0.5f); - m_aspect *= 2.0f; - m_fov = DEGREE_TO_RAD*stk_config->m_camera_fov[1]; - break; - case 3: - /* - if(m_index<2) - { - m_viewport = core::recti(m_index==0 ? 0 - : irr_driver->getActualScreenSize().Width>>1, - 0, - m_index==0 ? irr_driver->getActualScreenSize().Width>>1 - : irr_driver->getActualScreenSize().Width, - irr_driver->getActualScreenSize().Height>>1); - m_scaling = core::vector2df(0.5f, 0.5f); - m_fov = DEGREE_TO_RAD*50.0f; - } - else - { - m_viewport = core::recti(0, irr_driver->getActualScreenSize().Height>>1, - irr_driver->getActualScreenSize().Width, - irr_driver->getActualScreenSize().Height); - m_scaling = core::vector2df(1.0f, 0.5f); - m_fov = DEGREE_TO_RAD*65.0f; - m_aspect *= 2.0f; - } - break;*/ - case 4: - { // g++ 4.3 whines about the variables in switch/case if not {}-wrapped (???) - const int x1 = (m_index%2==0 ? 0 : irr_driver->getActualScreenSize().Width>>1); - const int y1 = (m_index<2 ? 0 : irr_driver->getActualScreenSize().Height>>1); - const int x2 = (m_index%2==0 ? irr_driver->getActualScreenSize().Width>>1 : irr_driver->getActualScreenSize().Width); - const int y2 = (m_index<2 ? irr_driver->getActualScreenSize().Height>>1 : irr_driver->getActualScreenSize().Height); - m_viewport = core::recti(x1, y1, x2, y2); - m_scaling = core::vector2df(0.5f, 0.5f); - m_fov = DEGREE_TO_RAD*stk_config->m_camera_fov[3]; - } - break; - default: - if(UserConfigParams::logMisc()) - Log::warn("Camera", "Incorrect number of players: '%d' - assuming 1.", - race_manager->getNumLocalPlayers()); - m_viewport = core::recti(0, 0, - irr_driver->getActualScreenSize().Width, - irr_driver->getActualScreenSize().Height); - m_scaling = core::vector2df(1.0f, 1.0f); - m_fov = DEGREE_TO_RAD*75.0f; - break; - } // switch + m_viewport = irr_driver->GetSplitscreenWindow(m_index); + m_aspect = (float)((float)(m_viewport.getWidth()) / (float)(m_viewport.getHeight())); + + m_scaling = core::vector2df( + irr_driver->getActualScreenSize().Width / m_viewport.getWidth() , + irr_driver->getActualScreenSize().Height / m_viewport.getHeight()); + + m_fov = DEGREE_TO_RAD * stk_config->m_camera_fov[race_manager->getNumLocalPlayers() - 1]; + m_camera->setFOV(m_fov); m_camera->setAspectRatio(m_aspect); m_camera->setFarValue(Track::getCurrentTrack()->getCameraFar()); diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index dc9ac0447..9e1600aa3 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -230,7 +230,31 @@ void IrrDriver::updateConfigIfRelevant() } #endif // !SERVER_ONLY } // updateConfigIfRelevant +core::recti IrrDriver::GetSplitscreenWindow(int WindowNum) +{ + const int playernum = race_manager->getNumLocalPlayers(); + const float playernum_sqrt = sqrt(playernum); + + int rows = UserConfigParams::split_screen_horizontally ? ceil(playernum_sqrt) : round(playernum_sqrt); + int cols = 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 = ceil((float)irr_driver->getActualScreenSize().Width / (float)cols); + const int height_of_space = ceil((float)irr_driver->getActualScreenSize().Height / (float)rows); + const int x_grid_Position = WindowNum % cols; + const int y_grid_Position = floor((WindowNum) / cols); + int wid = (int)irr_driver->getActualScreenSize().Width; + +//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 55ed173f9..706738e6a 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -203,6 +203,7 @@ public: void increaseObjectCount(); core::array &getMainSetup(); void updateConfigIfRelevant(); + core::recti GetSplitscreenWindow(int WindowNum); void setAllMaterialFlags(scene::IMesh *mesh) const; scene::IAnimatedMesh *getAnimatedMesh(const std::string &name); scene::IMesh *getMesh(const std::string &name); diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index 012d3778b..e49043c7d 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -912,6 +912,19 @@ void Skin::drawRibbon(const core::recti &rect, Widget* widget, { } // drawRibbon +SColorf GetPlayerColor(int player_id) +{ + + SColorHSL col = { 0,100,50 }; + col.Hue += (360 / 4) * (player_id % 4); + int color_id = player_id % 4; + SColorf color_rgb = { 0,0,0,1 }; + + + col.Saturation = col.Saturation * (1.0F / (floor(player_id / 4) + 1) ); + col.toRGB(color_rgb); + return color_rgb; +} // ---------------------------------------------------------------------------- /** * @param focused whether this element is focus by the master player (whether @@ -1069,8 +1082,8 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget, } } - // if multiple player selected the same ribbon item, we need to know - // to make it visible + + //Handle drawing for the first player int nPlayersOnThisItem = 0; if (mark_focused) @@ -1086,36 +1099,36 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget, const float dt = GUIEngine::getLatestDt(); - glow_effect += dt*3; + glow_effect += dt * 3; if (glow_effect > 6.2832f /* 2*PI */) glow_effect -= 6.2832f; - grow = (int)(45 + 10*sin(glow_effect)); + grow = (int)(45 + 10 * sin(glow_effect)); const int glow_center_x = rect.UpperLeftCorner.X - + rect.getWidth()/2; + + rect.getWidth() / 2; const int glow_center_y = rect.UpperLeftCorner.Y - + rect.getHeight() - 5; + + rect.getHeight() - 5; ITexture* tex_ficonhighlight = SkinConfig::m_render_params["focusHalo::neutral"] - .getImage(); + .getImage(); const int texture_w = tex_ficonhighlight->getSize().Width; const int texture_h = tex_ficonhighlight->getSize().Height; - core::recti source_area(0, 0, texture_w,texture_h); + core::recti source_area(0, 0, texture_w, texture_h); const core::recti rect2(glow_center_x - 45 - grow, - glow_center_y - 25 - grow/2, - glow_center_x + 45 + grow, - glow_center_y + 25 + grow/2); + glow_center_y - 25 - grow / 2, + glow_center_x + 45 + grow, + glow_center_y + 25 + grow / 2); draw2DImage(tex_ficonhighlight, rect2, - source_area, - /*clipping*/ 0, - /*color*/ 0, - /*alpha*/true ); + source_area, + /*clipping*/ 0, + /*color*/ 0, + /*alpha*/true); } // if we're not using glow, draw square focus instead else @@ -1129,80 +1142,51 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget, return; drawBoxFromStretchableTexture(parentRibbonWidget, rect, - SkinConfig::m_render_params["squareFocusHalo::neutral"]); + SkinConfig::m_render_params["squareFocusHalo::neutral"]); nPlayersOnThisItem++; } } // end if mark_focused - // ---- Draw selection for other players than player 1 - if (parentRibbon->isFocusedForPlayer(1) && - parentRibbon->getSelectionIDString(1) == - widget->m_properties[PROP_ID]) + //Handle drawing for everyone else + for (int i = 1; i < MAX_PLAYER_COUNT; i++) { - if (nPlayersOnThisItem > 0) + // ---- Draw selection for other players than player 1 + if (parentRibbon->isFocusedForPlayer(i) && + parentRibbon->getSelectionIDString(i) == + widget->m_properties[PROP_ID]) { - core::recti rect2 = rect; - const int enlarge = nPlayersOnThisItem*6; - rect2.UpperLeftCorner.X -= enlarge; - rect2.UpperLeftCorner.Y -= enlarge; - rect2.LowerRightCorner.X += enlarge; - rect2.LowerRightCorner.Y += enlarge; - drawBoxFromStretchableTexture(parentRibbonWidget, rect2, - SkinConfig::m_render_params["squareFocusHalo2::neutral"]); - } - else - { - drawBoxFromStretchableTexture(parentRibbonWidget, rect, - SkinConfig::m_render_params["squareFocusHalo2::neutral"]); - } + short red_previous = parentRibbonWidget->m_skin_r; + short green_previous = parentRibbonWidget->m_skin_g; + short blue_previous = parentRibbonWidget->m_skin_b; - nPlayersOnThisItem++; - } + SColorf color_rgb = GetPlayerColor(i); + + parentRibbonWidget->m_skin_r = color_rgb.r * 255.0F; + parentRibbonWidget->m_skin_g = color_rgb.g * 255.0F; + parentRibbonWidget->m_skin_b = color_rgb.b * 255.0F; - if (parentRibbon->isFocusedForPlayer(2) && - parentRibbon->getSelectionIDString(2) == - widget->m_properties[PROP_ID]) - { - if (nPlayersOnThisItem > 0) - { - core::recti rect2 = rect; - const int enlarge = nPlayersOnThisItem*6; - rect2.UpperLeftCorner.X -= enlarge; - rect2.UpperLeftCorner.Y -= enlarge; - rect2.LowerRightCorner.X += enlarge; - rect2.LowerRightCorner.Y += enlarge; - drawBoxFromStretchableTexture(parentRibbonWidget, rect2, - SkinConfig::m_render_params["squareFocusHalo3::neutral"]); - } - else - { - drawBoxFromStretchableTexture(parentRibbonWidget, rect, - SkinConfig::m_render_params["squareFocusHalo3::neutral"]); - } - nPlayersOnThisItem++; - } + if (nPlayersOnThisItem > 0) + { + core::recti rect2 = rect; + const int enlarge = nPlayersOnThisItem * 6; + rect2.UpperLeftCorner.X -= enlarge; + rect2.UpperLeftCorner.Y -= enlarge; + rect2.LowerRightCorner.X += enlarge; + rect2.LowerRightCorner.Y += enlarge; - if (parentRibbon->isFocusedForPlayer(3) && - parentRibbon->getSelectionIDString(3) == - widget->m_properties[PROP_ID]) - { - if (nPlayersOnThisItem > 0) - { - core::recti rect2 = rect; - const int enlarge = nPlayersOnThisItem*6; - rect2.UpperLeftCorner.X -= enlarge; - rect2.UpperLeftCorner.Y -= enlarge; - rect2.LowerRightCorner.X += enlarge; - rect2.LowerRightCorner.Y += enlarge; - drawBoxFromStretchableTexture(parentRibbonWidget, rect2, - SkinConfig::m_render_params["squareFocusHalo4::neutral"]); + drawBoxFromStretchableTexture(parentRibbonWidget, rect2, + SkinConfig::m_render_params["squareFocusHaloBW::neutral"]); + } + else + { + drawBoxFromStretchableTexture(parentRibbonWidget, rect, + SkinConfig::m_render_params["squareFocusHaloBW::neutral"]); + } + parentRibbonWidget->m_skin_r = red_previous; + parentRibbonWidget->m_skin_g = green_previous; + parentRibbonWidget->m_skin_b = blue_previous; + nPlayersOnThisItem++; } - else - { - drawBoxFromStretchableTexture(parentRibbonWidget, rect, - SkinConfig::m_render_params["squareFocusHalo4::neutral"]); - } - nPlayersOnThisItem++; } drawIconButton(rect, widget, pressed, focused); @@ -1224,6 +1208,7 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget, #endif } // drawRibbonChild + // ---------------------------------------------------------------------------- /** * @param focused whether this element is focus by the master player (whether @@ -1256,25 +1241,28 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget, } } + + BoxRenderParams* params; SpinnerWidget* q = dynamic_cast(widget); if(q->getUseBackgroundColor()) { int player_id=q->getSpinnerWidgetPlayerID(); - if(player_id==0) - params=&SkinConfig::m_render_params["spinner1::neutral"]; - else if(player_id==1) - params=&SkinConfig::m_render_params["spinner2::neutral"]; - else if(player_id==2) - params=&SkinConfig::m_render_params["spinner3::neutral"]; - else if(player_id==3) - params=&SkinConfig::m_render_params["spinner4::neutral"]; - else + + params = &SkinConfig::m_render_params[ + "spinner::deactivated"]; + + SColorf color_rgb = GetPlayerColor(player_id); + + widget->m_skin_r = color_rgb.r * 255.0F; + widget->m_skin_g = color_rgb.g * 255.0F; + widget->m_skin_b = color_rgb.b * 255.0F; + + if (player_id == 0) { - Log::fatal("Skin::drawSpinnerBody", "Unknown playerID (more than 4 players?)"); - // Silence compiler warning - params = NULL; + color_rgb = { 1,1,1,1 }; } + } else if (widget->m_deactivated) { @@ -1288,48 +1276,23 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget, { params=&SkinConfig::m_render_params["spinner::neutral"]; } - if (widget->isFocusedForPlayer(0)) + for (int i = 1; i < MAX_PLAYER_COUNT + 1; i++) { - core::recti rect2 = rect; - rect2.UpperLeftCorner.X += 2; - rect2.UpperLeftCorner.Y -= 3; - rect2.LowerRightCorner.X -= 2; - rect2.LowerRightCorner.Y += 5; - drawBoxFromStretchableTexture(widget, rect2, - SkinConfig::m_render_params["squareFocusHalo::neutral"]); - + if (widget->isFocusedForPlayer(i - 1)) { + core::recti rect2 = rect; + rect2.UpperLeftCorner.X += 2; + rect2.UpperLeftCorner.Y -= 3; + rect2.LowerRightCorner.X -= 2; + rect2.LowerRightCorner.Y += 5; + + + drawBoxFromStretchableTexture(widget, rect2, + SkinConfig::m_render_params["squareFocusHaloBW::neutral"]); + //TODO add squarefocushalo0 + } } - else if (widget->isFocusedForPlayer(1)) - { - core::recti rect2 = rect; - rect2.UpperLeftCorner.X += 2; - rect2.UpperLeftCorner.Y -= 3; - rect2.LowerRightCorner.X -= 2; - rect2.LowerRightCorner.Y += 5; - drawBoxFromStretchableTexture(widget, rect2, - SkinConfig::m_render_params["squareFocusHalo2::neutral"]); - } - else if (widget->isFocusedForPlayer(2)) - { - core::recti rect2 = rect; - rect2.UpperLeftCorner.X += 2; - rect2.UpperLeftCorner.Y -= 3; - rect2.LowerRightCorner.X -= 2; - rect2.LowerRightCorner.Y += 5; - drawBoxFromStretchableTexture(widget, rect2, - SkinConfig::m_render_params["squareFocusHalo3::neutral"]); - } - else if (widget->isFocusedForPlayer(3)) - { - core::recti rect2 = rect; - rect2.UpperLeftCorner.X += 2; - rect2.UpperLeftCorner.Y -= 3; - rect2.LowerRightCorner.X -= 2; - rect2.LowerRightCorner.Y += 5; - drawBoxFromStretchableTexture(widget, rect2, - SkinConfig::m_render_params["squareFocusHalo4::neutral"]); - } + core::recti sized_rect = rect; if (m_dialog && m_dialog_size < 1.0f && widget->m_parent != NULL && @@ -2538,4 +2501,4 @@ void Skin::setSize (EGUI_DEFAULT_SIZE which, s32 texture_size) void Skin::setSpriteBank (IGUISpriteBank *bank) { m_fallback_skin->setSpriteBank(bank); -} // setSpriteBank +} // setSpriteBank \ No newline at end of file diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 7de4d8eda..875321b25 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -489,7 +489,17 @@ public: { return m_num_local_players; } // getNumLocalPlayers + // ------------------------------------------------------------------------ + bool getIfEmptyScreenSpaceExists() const + { + const float Sqrt = sqrt(getNumLocalPlayers()); + const int rows = ceil(Sqrt); + const int cols = round(Sqrt); + const int total_spaces = rows * cols; + return (total_spaces - getNumLocalPlayers() > 0); + } // getNumLocalPlayers + // ------------------------------------------------------------------------ /** Returns the selected number of karts (selected number of players and * AI karts. */ unsigned int getNumberOfKarts() const {return m_num_karts; } diff --git a/src/states_screens/options_screen_ui.cpp b/src/states_screens/options_screen_ui.cpp index ee47e2629..eb2479396 100644 --- a/src/states_screens/options_screen_ui.cpp +++ b/src/states_screens/options_screen_ui.cpp @@ -128,6 +128,13 @@ void OptionsScreenUI::init() assert( skinSelector != NULL ); // ---- video modes + CheckBoxWidget* splitscreen_method = getWidget("split_screen_horizontally"); + assert(splitscreen_method != NULL); + splitscreen_method->setState(UserConfigParams::split_screen_horizontally); + + //Forbid changing this setting in game + bool in_game = StateManager::get()->getGameState() == GUIEngine::INGAME_MENU; + splitscreen_method->setActive(!in_game); CheckBoxWidget* fps = getWidget("showfps"); assert( fps != NULL ); @@ -220,6 +227,7 @@ void OptionsScreenUI::init() // Forbid changing language while in-game, since this crashes (changing the language involves // tearing down and rebuilding the menu stack. not good when in-game) list_widget->setActive(StateManager::get()->getGameState() != GUIEngine::INGAME_MENU); + } // init @@ -258,6 +266,13 @@ void OptionsScreenUI::eventCallback(Widget* widget, const std::string& name, con UserConfigParams::m_skin_file = core::stringc(selectedSkin.c_str()).c_str() + std::string(".stkskin"); GUIEngine::reloadSkin(); } + else if (name == "split_screen_horizontally") + { + CheckBoxWidget* split_screen_horizontally = getWidget("split_screen_horizontally"); + assert(split_screen_horizontally != NULL); + UserConfigParams::split_screen_horizontally = split_screen_horizontally->getState(); + + } else if (name == "showfps") { CheckBoxWidget* fps = getWidget("showfps"); diff --git a/src/states_screens/race_gui.cpp b/src/states_screens/race_gui.cpp index 49c6488b5..4334052f7 100644 --- a/src/states_screens/race_gui.cpp +++ b/src/states_screens/race_gui.cpp @@ -121,7 +121,7 @@ RaceGUI::RaceGUI() // special case : when 3 players play, use available 4th space for such things - if (race_manager->getNumLocalPlayers() == 3) + if (race_manager->getIfEmptyScreenSpaceExists()) { m_map_left = irr_driver->getActualScreenSize().Width - m_map_width; } @@ -190,15 +190,13 @@ void RaceGUI::renderGlobal(float dt) // Special case : when 3 players play, use 4th window to display such // stuff (but we must clear it) - if (race_manager->getNumLocalPlayers() == 3 && + if (race_manager->getIfEmptyScreenSpaceExists() && !GUIEngine::ModalDialog::isADialogActive()) { static video::SColor black = video::SColor(255,0,0,0); - GL32_draw2DRectangle(black, - core::rect(irr_driver->getActualScreenSize().Width/2, - irr_driver->getActualScreenSize().Height/2, - irr_driver->getActualScreenSize().Width, - irr_driver->getActualScreenSize().Height)); + + GL32_draw2DRectangle(black, irr_driver->GetSplitscreenWindow( + race_manager->getNumLocalPlayers())); } World *world = World::getWorld(); @@ -255,7 +253,7 @@ void RaceGUI::renderPlayerView(const Camera *camera, float dt) drawPlungerInFace(camera, dt); - scaling *= viewport.getWidth()/800.0f; // scale race GUI along screen size + scaling *= float(viewport.getWidth()) / float(irr_driver->getActualScreenSize().Width); // scale race GUI along screen size drawAllMessages(kart, viewport, scaling); if(!World::getWorld()->isRacePhase()) return; @@ -368,9 +366,10 @@ void RaceGUI::drawGlobalTimer() irr_driver->getActualScreenSize().Width , 50); // special case : when 3 players play, use available 4th space for such things - if (race_manager->getNumLocalPlayers() == 3) + if (race_manager->getIfEmptyScreenSpaceExists()) { - pos += core::vector2d(0, irr_driver->getActualScreenSize().Height/2); + pos -= core::vector2d(0, pos.LowerRightCorner.Y / 2); + pos += core::vector2d(0, irr_driver->getActualScreenSize().Height - irr_driver->GetSplitscreenWindow(0).getHeight()); } gui::ScalableFont* font = (use_digit_font ? GUIEngine::getHighresDigitFont() : GUIEngine::getFont()); @@ -888,14 +887,20 @@ void RaceGUI::drawLap(const AbstractKart* kart, if (lap < 0 ) return; core::recti pos; - pos.UpperLeftCorner.Y = viewport.UpperLeftCorner.Y + m_font_height; + // If the time display in the top right is in this viewport, // move the lap/rank display down a little bit so that it is // displayed under the time. - if (viewport.UpperLeftCorner.Y==0 && - viewport.LowerRightCorner.X==(int)(irr_driver->getActualScreenSize().Width) && - race_manager->getNumPlayers()!=3) - pos.UpperLeftCorner.Y += m_font_height; + if (viewport.UpperLeftCorner.Y == 0 && + viewport.LowerRightCorner.X == (int)(irr_driver->getActualScreenSize().Width) && + !race_manager->getIfEmptyScreenSpaceExists()) + { + pos.UpperLeftCorner.Y += m_font_height; + } + else + { + pos.UpperLeftCorner.Y = viewport.UpperLeftCorner.Y + m_font_height; + } pos.LowerRightCorner.Y = viewport.LowerRightCorner.Y+20; pos.UpperLeftCorner.X = viewport.LowerRightCorner.X - m_lap_width - 10; diff --git a/src/states_screens/race_gui_base.cpp b/src/states_screens/race_gui_base.cpp index 4dd278a89..e9ae58f80 100644 --- a/src/states_screens/race_gui_base.cpp +++ b/src/states_screens/race_gui_base.cpp @@ -206,9 +206,9 @@ void RaceGUIBase::drawAllMessages(const AbstractKart* kart, const core::vector2df &scaling) { int y = viewport.LowerRightCorner.Y - m_small_font_max_height - 10; - - const int x = (viewport.LowerRightCorner.X + viewport.UpperLeftCorner.X)/2; - const int w = (viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X); + + const int x = viewport.getCenter().X; + const int w = viewport.getWidth(); // Draw less important messages first, at the very bottom of the screen // unimportant messages are skipped in multiplayer, they take too much screen space @@ -244,7 +244,7 @@ void RaceGUIBase::drawAllMessages(const AbstractKart* kart, } // First line of text somewhat under the top of the viewport. - y = (int)(viewport.UpperLeftCorner.Y + 164*scaling.Y); + y = (int)(viewport.UpperLeftCorner.Y + 20); gui::ScalableFont* font = GUIEngine::getFont(); gui::ScalableFont* big_font = GUIEngine::getTitleFont(); @@ -665,10 +665,11 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin) int y_base = 20; unsigned int y_space = irr_driver->getActualScreenSize().Height - bottom_margin - y_base; // Special case : when 3 players play, use 4th window to display such stuff - if (race_manager->getNumLocalPlayers() == 3) + if (race_manager->getIfEmptyScreenSpaceExists()) { - x_base = irr_driver->getActualScreenSize().Width/2 + x_base; - y_base = irr_driver->getActualScreenSize().Height/2 + y_base; + irr::core::recti Last_Space = irr_driver->GetSplitscreenWindow(race_manager->getNumLocalPlayers()); + x_base = Last_Space.UpperLeftCorner.X; + y_base = Last_Space.UpperLeftCorner.Y; y_space = irr_driver->getActualScreenSize().Height - y_base; } @@ -729,7 +730,7 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin) //where is the limit to hide last icons int y_icons_limit = irr_driver->getActualScreenSize().Height - bottom_margin - ICON_PLAYER_WIDTH; - if (race_manager->getNumLocalPlayers() == 3) + if (race_manager->getIfEmptyScreenSpaceExists()) { y_icons_limit = irr_driver->getActualScreenSize().Height - ICON_WIDTH; } diff --git a/src/states_screens/race_gui_overworld.cpp b/src/states_screens/race_gui_overworld.cpp index 625a3eec7..1c236802e 100644 --- a/src/states_screens/race_gui_overworld.cpp +++ b/src/states_screens/race_gui_overworld.cpp @@ -122,7 +122,7 @@ RaceGUIOverworld::RaceGUIOverworld() // special case : when 3 players play, use available 4th space for such things - if (race_manager->getNumLocalPlayers() == 3) + if (race_manager->getIfEmptyScreenSpaceExists()) { m_map_left = irr_driver->getActualScreenSize().Width - m_map_width; } @@ -179,15 +179,15 @@ void RaceGUIOverworld::renderGlobal(float dt) // Special case : when 3 players play, use 4th window to display such // stuff (but we must clear it) - if (race_manager->getNumLocalPlayers() == 3 && + if (race_manager->getIfEmptyScreenSpaceExists() && !GUIEngine::ModalDialog::isADialogActive()) { + const float Sqrt = sqrt(race_manager->getNumLocalPlayers()); + const int rows = ceil(Sqrt); + const int cols = round(Sqrt); static video::SColor black = video::SColor(255,0,0,0); - GL32_draw2DRectangle(black, - core::rect(irr_driver->getActualScreenSize().Width/2, - irr_driver->getActualScreenSize().Height/2, - irr_driver->getActualScreenSize().Width, - irr_driver->getActualScreenSize().Height)); + GL32_draw2DRectangle(black, irr_driver->GetSplitscreenWindow( + race_manager->getNumLocalPlayers())); } World *world = World::getWorld(); diff --git a/src/utils/constants.hpp b/src/utils/constants.hpp index 58d58a961..e433430c6 100644 --- a/src/utils/constants.hpp +++ b/src/utils/constants.hpp @@ -47,7 +47,7 @@ #define DEGREE_TO_RAD (M_PI/180.0f) #define RAD_TO_DEGREE (180.0f/M_PI) -const unsigned int MAX_PLAYER_COUNT = 4; +const unsigned int MAX_PLAYER_COUNT = 8; extern const bool IS_LITTLE_ENDIAN;