diff --git a/Minecraft.Client/Common/App_enums.h b/Minecraft.Client/Common/App_enums.h index 15a179787..18dff99d3 100644 --- a/Minecraft.Client/Common/App_enums.h +++ b/Minecraft.Client/Common/App_enums.h @@ -133,6 +133,8 @@ enum eGameSetting { eGameSetting_MusicVolume=0, eGameSetting_SoundFXVolume, + eGameSetting_FpsCap, + eGameSetting_VSync, eGameSetting_RenderDistance, eGameSetting_Gamma, eGameSetting_FOV, @@ -157,32 +159,24 @@ enum eGameSetting eGameSetting_InviteOnly, eGameSetting_FriendsOfFriends, eGameSetting_DisplayUpdateMessage, - // TU6 eGameSetting_BedrockFog, eGameSetting_DisplayHUD, eGameSetting_DisplayHand, - // TU7 eGameSetting_CustomSkinAnim, - // TU9 eGameSetting_DeathMessages, eGameSetting_UISize, eGameSetting_UISizeSplitscreen, eGameSetting_AnimatedCharacter, - // PS3 eGameSetting_PS3_EULA_Read, - // PSVita eGameSetting_PSVita_NetworkModeAdhoc, - - }; - enum eGameMode { eMode_Singleplayer, diff --git a/Minecraft.Client/Common/App_structs.h b/Minecraft.Client/Common/App_structs.h index 6a6e03546..62c6c9987 100644 --- a/Minecraft.Client/Common/App_structs.h +++ b/Minecraft.Client/Common/App_structs.h @@ -67,6 +67,8 @@ typedef struct unsigned char ucInterfaceOpacity; unsigned char ucPad02; // 1 byte padding unsigned char ucFov; + unsigned char ucFpsCap; + unsigned char ucVSync; // Adding another bitmask flag for more settings for 1.8.2 unsigned int uiBitmaskValues; // 0x00000001 - eGameSetting_Clouds - on diff --git a/Minecraft.Client/Common/Consoles_App.cpp b/Minecraft.Client/Common/Consoles_App.cpp index c3a623d5f..2abf4a8b7 100644 --- a/Minecraft.Client/Common/Consoles_App.cpp +++ b/Minecraft.Client/Common/Consoles_App.cpp @@ -771,6 +771,7 @@ static void Win64_GetSettingsPath(char *outPath, DWORD size) static void Win64_SaveSettings(GAME_SETTINGS *gs) { if (!gs) return; + printf("[DEBUG] Win64_SaveSettings: VSync=%d before save\n", gs->ucVSync); char filePath[MAX_PATH] = {}; Win64_GetSettingsPath(filePath, MAX_PATH); FILE *f = nullptr; @@ -778,6 +779,11 @@ static void Win64_SaveSettings(GAME_SETTINGS *gs) { fwrite(gs, sizeof(GAME_SETTINGS), 1, f); fclose(f); + printf("[DEBUG] Win64_SaveSettings: Settings saved to %s\n", filePath); + } + else + { + printf("[DEBUG] Win64_SaveSettings: Failed to open file %s\n", filePath); } } static void Win64_LoadSettings(GAME_SETTINGS *gs) @@ -790,8 +796,16 @@ static void Win64_LoadSettings(GAME_SETTINGS *gs) { GAME_SETTINGS temp = {}; if (fread(&temp, sizeof(GAME_SETTINGS), 1, f) == 1) + { memcpy(gs, &temp, sizeof(GAME_SETTINGS)); + printf("[DEBUG] Win64_LoadSettings: VSync=%d after load\n", gs->ucVSync); + } fclose(f); + printf("[DEBUG] Win64_LoadSettings: Settings loaded from %s\n", filePath); + } + else + { + printf("[DEBUG] Win64_LoadSettings: Failed to open file %s, using defaults\n", filePath); } } #endif @@ -838,6 +852,9 @@ int CMinecraftApp::SetDefaultOptions(C_4JProfile::PROFILESETTINGS *pSettings,con SetGameSettings(iPad,eGameSetting_RenderDistance,16); SetGameSettings(iPad,eGameSetting_Gamma,50); SetGameSettings(iPad,eGameSetting_FOV,0); + SetGameSettings(iPad,eGameSetting_FpsCap,1); + SetGameSettings(iPad,eGameSetting_VSync,0); + printf("[DEBUG] VSync initialized to OFF (0) for pad %d\n", iPad); // 4J-PB - Don't reset the difficult level if we're in-game if(Minecraft::GetInstance()->level==nullptr) @@ -1411,6 +1428,10 @@ void CMinecraftApp::ActionGameSettings(int iPad,eGameSetting eVal) pMinecraft->options->set(Options::Option::FOV, (float)GameSettingsA[iPad]->ucFov / 100.0f); } break; + case eGameSetting_FpsCap: + break; + case eGameSetting_VSync: + break; case eGameSetting_Difficulty: if(iPad==ProfileManager.GetPrimaryPad()) { @@ -1890,6 +1911,22 @@ void CMinecraftApp::SetGameSettings(int iPad,eGameSetting eVal,unsigned char ucV GameSettingsA[iPad]->bSettingsChanged=true; } break; + case eGameSetting_FpsCap: + if(GameSettingsA[iPad]->ucFpsCap!=ucVal) + { + GameSettingsA[iPad]->ucFpsCap=ucVal; + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_VSync: + printf("[DEBUG] SetGameSettings VSync: pad=%d, old=%d, new=%d\n", iPad, GameSettingsA[iPad]->ucVSync, ucVal); + if(GameSettingsA[iPad]->ucVSync!=ucVal) + { + GameSettingsA[iPad]->ucVSync=ucVal; + GameSettingsA[iPad]->bSettingsChanged=true; + printf("[DEBUG] VSync setting updated to: %d\n", ucVal); + } + break; case eGameSetting_Difficulty: if((GameSettingsA[iPad]->usBitmaskValues&0x03)!=(ucVal&0x03)) { @@ -2442,6 +2479,13 @@ unsigned char CMinecraftApp::GetGameSettings(int iPad,eGameSetting eVal) case eGameSetting_PSVita_NetworkModeAdhoc: return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_PSVITANETWORKMODEADHOC)>>17; + case eGameSetting_FpsCap: + return GameSettingsA[iPad]->ucFpsCap; + + case eGameSetting_VSync: + printf("[DEBUG] GetGameSettings VSync: pad=%d, value=%d\n", iPad, GameSettingsA[iPad]->ucVSync); + return GameSettingsA[iPad]->ucVSync; + } return 0; } diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp index b258d8c31..f70c7113b 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp @@ -7,21 +7,22 @@ namespace { - constexpr int FOV_MIN = 70; - constexpr int FOV_MAX = 110; - constexpr int FOV_SLIDER_MAX = 100; + const int FOV_MIN = 70; + const int FOV_MAX = 110; + const int FOV_SLIDER_MAX = 100; - int ClampFov(int value) + const int fpsCaps[] = {30, 60, 120, 0}; + + int clampFov(int value) { if (value < FOV_MIN) return FOV_MIN; if (value > FOV_MAX) return FOV_MAX; return value; } - [[maybe_unused]] - int FovToSliderValue(float fov) + int fovToSliderValue(float fov) { - const int clampedFov = ClampFov(static_cast(fov + 0.5f)); + int clampedFov = clampFov((int)(fov + 0.5f)); return ((clampedFov - FOV_MIN) * FOV_SLIDER_MAX) / (FOV_MAX - FOV_MIN); } @@ -31,6 +32,14 @@ namespace if (sliderValue > FOV_SLIDER_MAX) sliderValue = FOV_SLIDER_MAX; return FOV_MIN + ((sliderValue * (FOV_MAX - FOV_MIN)) / FOV_SLIDER_MAX); } + + void formatFpsCapLabel(WCHAR* buf, int idx) + { + if (fpsCaps[idx] == 0) + swprintf(buf, 256, L"Max Framerate: Unlimited"); + else + swprintf(buf, 256, L"Max Framerate: %d", fpsCaps[idx]); + } } int UIScene_SettingsGraphicsMenu::LevelToDistance(int level) @@ -43,73 +52,71 @@ int UIScene_SettingsGraphicsMenu::LevelToDistance(int level) int UIScene_SettingsGraphicsMenu::DistanceToLevel(int dist) { - static const int table[6] = {2,4,8,16,32,64}; - for(int i = 0; i < 6; i++){ - if(table[i] == dist) - return i; - } - return 3; + static const int table[6] = {2,4,8,16,32,64}; + for(int i = 0; i < 6; i++){ + if(table[i] == dist) + return i; + } + return 3; } UIScene_SettingsGraphicsMenu::UIScene_SettingsGraphicsMenu(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer) { - // Setup all the Iggy references we need for this scene initialiseMovie(); Minecraft* pMinecraft = Minecraft::GetInstance(); - m_bNotInGame=(Minecraft::GetInstance()->level==nullptr); + m_bNotInGame = (Minecraft::GetInstance()->level == NULL); - m_checkboxClouds.init(app.GetString(IDS_CHECKBOX_RENDER_CLOUDS),eControl_Clouds,(app.GetGameSettings(m_iPad,eGameSetting_Clouds)!=0)); - m_checkboxBedrockFog.init(app.GetString(IDS_CHECKBOX_RENDER_BEDROCKFOG),eControl_BedrockFog,(app.GetGameSettings(m_iPad,eGameSetting_BedrockFog)!=0)); - m_checkboxCustomSkinAnim.init(app.GetString(IDS_CHECKBOX_CUSTOM_SKIN_ANIM),eControl_CustomSkinAnim,(app.GetGameSettings(m_iPad,eGameSetting_CustomSkinAnim)!=0)); + m_checkboxClouds.init(app.GetString(IDS_CHECKBOX_RENDER_CLOUDS), eControl_Clouds, (app.GetGameSettings(m_iPad, eGameSetting_Clouds) != 0)); + m_checkboxBedrockFog.init(app.GetString(IDS_CHECKBOX_RENDER_BEDROCKFOG), eControl_BedrockFog, (app.GetGameSettings(m_iPad, eGameSetting_BedrockFog) != 0)); + m_checkboxCustomSkinAnim.init(app.GetString(IDS_CHECKBOX_CUSTOM_SKIN_ANIM), eControl_CustomSkinAnim, (app.GetGameSettings(m_iPad, eGameSetting_CustomSkinAnim) != 0)); + m_checkboxVSync.init(L"VSync", eControl_VSync, (app.GetGameSettings(m_iPad, eGameSetting_VSync) != 0)); - WCHAR TempString[256]; - swprintf(TempString, 256, L"Render Distance: %d",app.GetGameSettings(m_iPad,eGameSetting_RenderDistance)); - m_sliderRenderDistance.init(TempString,eControl_RenderDistance,0,5,DistanceToLevel(app.GetGameSettings(m_iPad,eGameSetting_RenderDistance))); - - swprintf( TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_GAMMA ),app.GetGameSettings(m_iPad,eGameSetting_Gamma)); - m_sliderGamma.init(TempString,eControl_Gamma,0,100,app.GetGameSettings(m_iPad,eGameSetting_Gamma)); + swprintf(TempString, 256, L"Render Distance: %d", (int)app.GetGameSettings(m_iPad, eGameSetting_RenderDistance)); + m_sliderRenderDistance.init(TempString, eControl_RenderDistance, 0, 5, DistanceToLevel((int)app.GetGameSettings(m_iPad, eGameSetting_RenderDistance))); - const int initialFovSlider = app.GetGameSettings(m_iPad, eGameSetting_FOV); - const int initialFovDeg = sliderValueToFov(initialFovSlider); - swprintf(TempString, 256, L"FOV: %d", initialFovDeg); + swprintf(TempString, 256, L"%ls: %d%%", app.GetString(IDS_SLIDER_GAMMA), (int)app.GetGameSettings(m_iPad, eGameSetting_Gamma)); + m_sliderGamma.init(TempString, eControl_Gamma, 0, 100, (int)app.GetGameSettings(m_iPad, eGameSetting_Gamma)); + + int initialFovSlider = (int)app.GetGameSettings(m_iPad, eGameSetting_FOV); + swprintf(TempString, 256, L"FOV: %d", sliderValueToFov(initialFovSlider)); m_sliderFOV.init(TempString, eControl_FOV, 0, FOV_SLIDER_MAX, initialFovSlider); - - swprintf( TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_INTERFACEOPACITY ),app.GetGameSettings(m_iPad,eGameSetting_InterfaceOpacity)); - m_sliderInterfaceOpacity.init(TempString,eControl_InterfaceOpacity,0,100,app.GetGameSettings(m_iPad,eGameSetting_InterfaceOpacity)); + + swprintf(TempString, 256, L"%ls: %d%%", app.GetString(IDS_SLIDER_INTERFACEOPACITY), (int)app.GetGameSettings(m_iPad, eGameSetting_InterfaceOpacity)); + m_sliderInterfaceOpacity.init(TempString, eControl_InterfaceOpacity, 0, 100, (int)app.GetGameSettings(m_iPad, eGameSetting_InterfaceOpacity)); + + int fpsCapIndex = (int)app.GetGameSettings(m_iPad, eGameSetting_FpsCap); + if (fpsCapIndex < 0 || fpsCapIndex > 3) fpsCapIndex = 1; + formatFpsCapLabel(TempString, fpsCapIndex); + m_sliderFpsCap.init(TempString, eControl_FpsCap, 0, 3, fpsCapIndex); doHorizontalResizeCheck(); + + bool bInGame = (Minecraft::GetInstance()->level != NULL); + bool bIsPrimaryPad = (ProfileManager.GetPrimaryPad() == m_iPad); - const bool bInGame=(Minecraft::GetInstance()->level!=nullptr); - const bool bIsPrimaryPad=(ProfileManager.GetPrimaryPad()==m_iPad); - // if we're not in the game, we need to use basescene 0 if(bInGame) { - // If the game has started, then you need to be the host to change the in-game gamertags if(bIsPrimaryPad) { - // we are the primary player on this machine, but not the game host - // are we the game host? If not, we need to remove the bedrockfog setting if(!g_NetworkManager.IsHost()) { - // hide the in-game bedrock fog setting removeControl(&m_checkboxBedrockFog, true); } } else { - // We shouldn't have the bedrock fog option, or the m_CustomSkinAnim option removeControl(&m_checkboxBedrockFog, true); removeControl(&m_checkboxCustomSkinAnim, true); } } - if(app.GetLocalPlayerCount()>1) + if(app.GetLocalPlayerCount() > 1) { #if TO_BE_IMPLEMENTED - app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + app.AdjustSplitscreenScene(m_hObj, &m_OriginalPosition, m_iPad); #endif } } @@ -132,24 +139,23 @@ wstring UIScene_SettingsGraphicsMenu::getMoviePath() void UIScene_SettingsGraphicsMenu::updateTooltips() { - ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + ui.SetTooltips(m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK); } void UIScene_SettingsGraphicsMenu::updateComponents() { - const bool bNotInGame=(Minecraft::GetInstance()->level==nullptr); + bool bNotInGame = (Minecraft::GetInstance()->level == NULL); if(bNotInGame) { - m_parentLayer->showComponent(m_iPad,eUIComponent_Panorama,true); - m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,true); + m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, true); + m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, true); } else { - m_parentLayer->showComponent(m_iPad,eUIComponent_Panorama,false); + m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, false); - if( app.GetLocalPlayerCount() == 1 ) m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,true); - else m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,false); - + if(app.GetLocalPlayerCount() == 1) m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, true); + else m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, false); } } @@ -161,10 +167,10 @@ void UIScene_SettingsGraphicsMenu::handleInput(int iPad, int key, bool repeat, b case ACTION_MENU_CANCEL: if(pressed) { - // check the checkboxes - app.SetGameSettings(m_iPad,eGameSetting_Clouds,m_checkboxClouds.IsChecked()?1:0); - app.SetGameSettings(m_iPad,eGameSetting_BedrockFog,m_checkboxBedrockFog.IsChecked()?1:0); - app.SetGameSettings(m_iPad,eGameSetting_CustomSkinAnim,m_checkboxCustomSkinAnim.IsChecked()?1:0); + app.SetGameSettings(m_iPad, eGameSetting_Clouds, m_checkboxClouds.IsChecked() ? 1 : 0); + app.SetGameSettings(m_iPad, eGameSetting_BedrockFog, m_checkboxBedrockFog.IsChecked() ? 1 : 0); + app.SetGameSettings(m_iPad, eGameSetting_CustomSkinAnim, m_checkboxCustomSkinAnim.IsChecked() ? 1 : 0); + app.SetGameSettings(m_iPad, eGameSetting_VSync, m_checkboxVSync.IsChecked() ? 1 : 0); navigateBack(); handled = true; @@ -188,53 +194,59 @@ void UIScene_SettingsGraphicsMenu::handleInput(int iPad, int key, bool repeat, b void UIScene_SettingsGraphicsMenu::handleSliderMove(F64 sliderId, F64 currentValue) { WCHAR TempString[256]; - const int value = static_cast(currentValue); - switch(static_cast(sliderId)) + int value = (int)currentValue; + switch((int)sliderId) { case eControl_RenderDistance: { m_sliderRenderDistance.handleSliderMove(value); - const int dist = LevelToDistance(value); + int dist = LevelToDistance(value); + app.SetGameSettings(m_iPad, eGameSetting_RenderDistance, dist); - app.SetGameSettings(m_iPad,eGameSetting_RenderDistance,dist); - - const Minecraft* mc = Minecraft::GetInstance(); + Minecraft* mc = Minecraft::GetInstance(); mc->options->viewDistance = 3 - value; - swprintf(TempString,256,L"Render Distance: %d",dist); + swprintf(TempString, 256, L"Render Distance: %d", dist); m_sliderRenderDistance.setLabel(TempString); } break; case eControl_Gamma: m_sliderGamma.handleSliderMove(value); - - app.SetGameSettings(m_iPad,eGameSetting_Gamma,value); - swprintf( TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_GAMMA ),value); + app.SetGameSettings(m_iPad, eGameSetting_Gamma, value); + swprintf(TempString, 256, L"%ls: %d%%", app.GetString(IDS_SLIDER_GAMMA), value); m_sliderGamma.setLabel(TempString); - break; case eControl_FOV: { m_sliderFOV.handleSliderMove(value); - const Minecraft* pMinecraft = Minecraft::GetInstance(); - const int fovValue = sliderValueToFov(value); - pMinecraft->gameRenderer->SetFovVal(static_cast(fovValue)); + Minecraft* pMinecraft = Minecraft::GetInstance(); + int fovValue = sliderValueToFov(value); + pMinecraft->gameRenderer->SetFovVal((float)fovValue); app.SetGameSettings(m_iPad, eGameSetting_FOV, value); - WCHAR tempString[256]; - swprintf(tempString, 256, L"FOV: %d", fovValue); - m_sliderFOV.setLabel(tempString); + swprintf(TempString, 256, L"FOV: %d", fovValue); + m_sliderFOV.setLabel(TempString); } break; case eControl_InterfaceOpacity: m_sliderInterfaceOpacity.handleSliderMove(value); - - app.SetGameSettings(m_iPad,eGameSetting_InterfaceOpacity,value); - swprintf( TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_INTERFACEOPACITY ),value); + app.SetGameSettings(m_iPad, eGameSetting_InterfaceOpacity, value); + swprintf(TempString, 256, L"%ls: %d%%", app.GetString(IDS_SLIDER_INTERFACEOPACITY), value); m_sliderInterfaceOpacity.setLabel(TempString); + break; + case eControl_FpsCap: + { + int idx = value; + if (idx < 0) idx = 0; + if (idx > 3) idx = 3; + m_sliderFpsCap.handleSliderMove(idx); + app.SetGameSettings(m_iPad, eGameSetting_FpsCap, idx); + formatFpsCapLabel(TempString, idx); + m_sliderFpsCap.setLabel(TempString); + } break; } } diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.h b/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.h index 99022c83f..22b1ef0ce 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.h @@ -15,19 +15,23 @@ private: eControl_RenderDistance, eControl_Gamma, eControl_FOV, - eControl_InterfaceOpacity + eControl_InterfaceOpacity, + eControl_FpsCap, + eControl_VSync }; - UIControl_CheckBox m_checkboxClouds, m_checkboxBedrockFog, m_checkboxCustomSkinAnim; // Checkboxes - UIControl_Slider m_sliderRenderDistance, m_sliderGamma, m_sliderFOV, m_sliderInterfaceOpacity; // Sliders + UIControl_CheckBox m_checkboxClouds, m_checkboxBedrockFog, m_checkboxCustomSkinAnim, m_checkboxVSync; + UIControl_Slider m_sliderRenderDistance, m_sliderGamma, m_sliderFOV, m_sliderInterfaceOpacity, m_sliderFpsCap; UI_BEGIN_MAP_ELEMENTS_AND_NAMES(UIScene) UI_MAP_ELEMENT( m_checkboxClouds, "Clouds") UI_MAP_ELEMENT( m_checkboxBedrockFog, "BedrockFog") UI_MAP_ELEMENT( m_checkboxCustomSkinAnim, "CustomSkinAnim") + UI_MAP_ELEMENT( m_checkboxVSync, "VSync") UI_MAP_ELEMENT( m_sliderRenderDistance, "RenderDistance") UI_MAP_ELEMENT( m_sliderGamma, "Gamma") UI_MAP_ELEMENT(m_sliderFOV, "FOV") UI_MAP_ELEMENT( m_sliderInterfaceOpacity, "InterfaceOpacity") + UI_MAP_ELEMENT( m_sliderFpsCap, "FpsCap") UI_END_MAP_ELEMENTS_AND_NAMES() bool m_bNotInGame; diff --git a/Minecraft.Client/GameRenderer.cpp b/Minecraft.Client/GameRenderer.cpp index 73b39529c..e8dc2767d 100644 --- a/Minecraft.Client/GameRenderer.cpp +++ b/Minecraft.Client/GameRenderer.cpp @@ -30,7 +30,7 @@ #include "..\Minecraft.World\System.h" #include "..\Minecraft.World\FloatBuffer.h" #include "..\Minecraft.World\ThreadName.h" -#include "..\Minecraft.World\SparseLightStorage.h" +#include "..\Minecraft.World\SparseLightStorage.h"i #include "..\Minecraft.World\CompressedTileStorage.h" #include "..\Minecraft.World\SparseDataStorage.h" #include "..\Minecraft.World\JavaMath.h" @@ -954,70 +954,91 @@ float GameRenderer::ComputeGammaFromSlider(float slider0to100) void GameRenderer::CachePlayerGammas() { - const float slider = app.GetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_Gamma); - const float gamma = ComputeGammaFromSlider(slider); - for (int j = 0; j < XUSER_MAX_COUNT && j < NUM_LIGHT_TEXTURES; ++j) - m_cachedGammaPerPlayer[j] = gamma; + { + std::shared_ptr player = Minecraft::GetInstance()->localplayers[j]; + if (!player) + { + m_cachedGammaPerPlayer[j] = 1.0f; + continue; + } + + const float slider = app.GetGameSettings(j, eGameSetting_Gamma); // 0..100 + m_cachedGammaPerPlayer[j] = ComputeGammaFromSlider(slider); + } } bool GameRenderer::ComputeViewportForPlayer(int j, D3D11_VIEWPORT &outViewport) const { + // Use the actual backbuffer dimensions so viewports adapt to window resize. extern int g_rScreenWidth; extern int g_rScreenHeight; - std::shared_ptr player = Minecraft::GetInstance()->localplayers[j]; - if (!player) + int active = 0; + int indexMap[NUM_LIGHT_TEXTURES] = {-1, -1, -1, -1}; + for (int i = 0; i < XUSER_MAX_COUNT && i < NUM_LIGHT_TEXTURES; ++i) + { + if (Minecraft::GetInstance()->localplayers[i]) + indexMap[active++] = i; + } + + if (active <= 1) + { + outViewport.TopLeftX = 0.0f; + outViewport.TopLeftY = 0.0f; + outViewport.Width = static_cast(g_rScreenWidth); + outViewport.Height = static_cast(g_rScreenHeight); + outViewport.MinDepth = 0.0f; + outViewport.MaxDepth = 1.0f; + return true; + } + + int k = -1; + for (int ord = 0; ord < active; ++ord) + if (indexMap[ord] == j) + { + k = ord; + break; + } + if (k < 0) return false; - const float w = static_cast(g_rScreenWidth); - const float h = static_cast(g_rScreenHeight); - const float halfW = w * 0.5f; - const float halfH = h * 0.5f; + const float width = static_cast(g_rScreenWidth); + const float height = static_cast(g_rScreenHeight); - outViewport.MinDepth = 0.0f; - outViewport.MaxDepth = 1.0f; - - switch (static_cast(player->m_iScreenSection)) + if (active == 2) { - case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: - outViewport.TopLeftX = 0; outViewport.TopLeftY = 0; - outViewport.Width = w; outViewport.Height = halfH; - break; - case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: - outViewport.TopLeftX = 0; outViewport.TopLeftY = halfH; - outViewport.Width = w; outViewport.Height = halfH; - break; - case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: - outViewport.TopLeftX = 0; outViewport.TopLeftY = 0; - outViewport.Width = halfW; outViewport.Height = h; - break; - case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT: - outViewport.TopLeftX = halfW; outViewport.TopLeftY = 0; - outViewport.Width = halfW; outViewport.Height = h; - break; - case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: - outViewport.TopLeftX = 0; outViewport.TopLeftY = 0; - outViewport.Width = halfW; outViewport.Height = halfH; - break; - case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: - outViewport.TopLeftX = halfW; outViewport.TopLeftY = 0; - outViewport.Width = halfW; outViewport.Height = halfH; - break; - case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: - outViewport.TopLeftX = 0; outViewport.TopLeftY = halfH; - outViewport.Width = halfW; outViewport.Height = halfH; - break; - case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: - outViewport.TopLeftX = halfW; outViewport.TopLeftY = halfH; - outViewport.Width = halfW; outViewport.Height = halfH; - break; - default: - outViewport.TopLeftX = 0; outViewport.TopLeftY = 0; - outViewport.Width = w; outViewport.Height = h; - break; + const float halfH = height * 0.5f; + outViewport.TopLeftX = 0.0f; + outViewport.Width = width; + outViewport.MinDepth = 0.0f; + outViewport.MaxDepth = 1.0f; + if (k == 0) + { + outViewport.TopLeftY = 0.0f; + outViewport.Height = halfH; + } + else + { + outViewport.TopLeftY = halfH; + outViewport.Height = halfH; + } + return true; + } + else + { + const float halfW = width * 0.5f; + const float halfH = height * 0.5f; + const int row = (k >= 2) ? 1 : 0; + const int col = (k % 2); + outViewport.TopLeftX = col ? halfW : 0.0f; + outViewport.TopLeftY = row ? halfH : 0.0f; + outViewport.Width = halfW; + outViewport.Height = halfH; + outViewport.MinDepth = 0.0f; + outViewport.MaxDepth = 1.0f; + return true; } - return true; } uint32_t GameRenderer::BuildPlayerViewports(D3D11_VIEWPORT *outViewports, float *outGammas, UINT maxCount) const @@ -1169,19 +1190,11 @@ void GameRenderer::render(float a, bool bFirst) const int xMouse = Mouse::getX() * screenWidth / mc->width; const int yMouse = screenHeight - Mouse::getY() * screenHeight / mc->height - 1; - const int maxFps = getFpsCap(mc->options->framerateLimit); + const int maxFps = getFpsCap(app.GetGameSettings(0, eGameSetting_FpsCap)); if (mc->level != nullptr) { - if (mc->options->framerateLimit == 0) - { - renderLevel(a, 0); - } - else - { - renderLevel(a, lastNsTime + 1000000000 / maxFps); - } - + renderLevel(a, 0); lastNsTime = System::nanoTime(); if (!mc->options->hideGui || mc->screen != nullptr) @@ -2240,10 +2253,9 @@ FloatBuffer *GameRenderer::getBuffer(float a, float b, float c, float d) int GameRenderer::getFpsCap(int option) { - int maxFps = 200; - if (option == 1) maxFps = 120; - if (option == 2) maxFps = 35; - return maxFps; + static const int fpsCaps[] = {30, 60, 120, 0}; + if (option < 0 || option > 3) return 0; + return fpsCaps[option]; } void GameRenderer::updateAllChunks() diff --git a/Minecraft.Client/GameRenderer.h b/Minecraft.Client/GameRenderer.h index c379106e0..a2856e1f3 100644 --- a/Minecraft.Client/GameRenderer.h +++ b/Minecraft.Client/GameRenderer.h @@ -163,8 +163,8 @@ private: void setupFog(int i, float alpha); FloatBuffer *getBuffer(float a, float b, float c, float d); - static int getFpsCap(int option); public: + static int getFpsCap(int option); void updateAllChunks(); #ifdef MULTITHREAD_ENABLE diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp index 70aeb22bf..a6de636a9 100644 --- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp +++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp @@ -1959,8 +1959,29 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, RenderManager.Set_matrixDirty(); #endif + { + int maxFps = GameRenderer::getFpsCap(app.GetGameSettings(0, eGameSetting_FpsCap)); + if (maxFps > 0) + { + static LONGLONG lastTime = 0; + LARGE_INTEGER freq, now; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&now); + LONGLONG targetInterval = freq.QuadPart / maxFps; + LONGLONG elapsed = now.QuadPart - lastTime; + if (elapsed < targetInterval) + { + DWORD sleepMs = (DWORD)((targetInterval - elapsed) * 1000 / freq.QuadPart); + if (sleepMs > 0) Sleep(sleepMs); + } + QueryPerformanceCounter(&now); + lastTime = now.QuadPart; + } + } // Present the frame. - RenderManager.Present(); + int vsyncSetting = app.GetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_VSync); + printf("[DEBUG] VSync setting: %d (0=OFF, 1=ON)\n", vsyncSetting); + g_pSwapChain->Present(vsyncSetting ? 1 : 0, 0); ui.CheckMenuDisplayed();