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/GameRenderer.cpp b/Minecraft.Client/GameRenderer.cpp index 73b39529c..9cbc0c818 100644 --- a/Minecraft.Client/GameRenderer.cpp +++ b/Minecraft.Client/GameRenderer.cpp @@ -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();