From 65a9c99215b3a6afcde7e9b9ce704d3a44b1cf94 Mon Sep 17 00:00:00 2001 From: JuiceyDev Date: Fri, 6 Mar 2026 00:01:26 +0100 Subject: [PATCH] YES PLEASE --- 4J.Input/4J_Input.cpp | 15 ++++++++-- 4J.Render/4J_Render.cpp | 31 +++++++++++++++------ Minecraft.Client/Rendering/GameRenderer.cpp | 5 ++++ Minecraft.Client/Textures/Textures.cpp | 7 ++++- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/4J.Input/4J_Input.cpp b/4J.Input/4J_Input.cpp index 6dc9de349..1c86d72e6 100644 --- a/4J.Input/4J_Input.cpp +++ b/4J.Input/4J_Input.cpp @@ -140,9 +140,9 @@ void C_4JInput::Initialise(int /*iInputStateC*/, unsigned char /*ucMapC*/, if (w) { glfwSetCursorPosCallback(w, onCursorPos); glfwSetScrollCallback(w, onScroll); - if (glfwRawMouseMotionSupported()) { - glfwSetInputMode(w, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); - } + // NOTE: GLFW_RAW_MOUSE_MOTION must only be set when cursor mode is + // GLFW_CURSOR_DISABLED (Wayland zwp_relative_pointer_v1 requirement). + // It is activated at the cursor-lock call sites below in Tick(). } printf("[4J_Input] GLFW input initialised\n"); @@ -181,6 +181,8 @@ void C_4JInput::Tick(void) { if (menuNow && s_mouseLocked) { // Re-entered a menu → release mouse cursor s_mouseLocked = false; + if (glfwRawMouseMotionSupported()) + glfwSetInputMode(w, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE); glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_NORMAL); // Discard stale delta so the view doesn't jerk on re-lock s_mouseAccumX = s_mouseAccumY = 0.0f; @@ -190,6 +192,11 @@ void C_4JInput::Tick(void) { // Left the menu → lock mouse for look control s_mouseLocked = true; glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + // Enable raw (un-accelerated) relative motion now that cursor is disabled. + // On Wayland this activates zwp_relative_pointer_v1 for sub-pixel precise + // mouse deltas; on X11 it bypasses the compositor acceleration curve. + if (glfwRawMouseMotionSupported()) + glfwSetInputMode(w, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); s_mouseAccumX = s_mouseAccumY = 0.0f; s_cursorInitialized = false; } @@ -210,6 +217,8 @@ void C_4JInput::Tick(void) { if (!menuNow && lclick) { s_mouseLocked = true; glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + if (glfwRawMouseMotionSupported()) + glfwSetInputMode(w, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); s_mouseAccumX = s_mouseAccumY = 0.0f; s_cursorInitialized = false; } diff --git a/4J.Render/4J_Render.cpp b/4J.Render/4J_Render.cpp index 02dfa7df2..879a27695 100644 --- a/4J.Render/4J_Render.cpp +++ b/4J.Render/4J_Render.cpp @@ -1,5 +1,6 @@ #include "4J_Render.h" #include +#include // getenv #define GL_GLEXT_PROTOTYPES #include @@ -37,6 +38,17 @@ static bool s_mainThreadSet = false; void C4JRender::Initialise() { +#if defined(__linux__) && (GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 4)) + // If the session is a native Wayland session, tell GLFW to use the Wayland + // backend instead of falling back to XWayland. This enables proper cursor + // confine-and-hide (zwp_confined_pointer_v1 + zwp_relative_pointer_v1) which + // is required for correct first-person mouse input on Wayland compositors. + if (getenv("WAYLAND_DISPLAY")) { + glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND); + fprintf(stderr, "[4J_Render] Wayland session detected — requesting native Wayland backend\n"); + } +#endif + if (!glfwInit()) { fprintf(stderr, "[4J_Render] Failed to initialise GLFW\n"); return; @@ -408,16 +420,17 @@ void C4JRender::TextureData(int width, int height, void *data, int level, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - // Do NOT set filter params here — the game calls glTexParameteri with the correct - // filter settings (GL_NEAREST_MIPMAP_LINEAR etc.) BEFORE calling TextureData. - // Setting params here would override those mipmap settings. - // Only guarantee the texture is always complete by generating mipmaps as a safety net. + // For the base level (0), force the texture to be non-mipmapped and pixel-crisp. + // glGenerateMipmap() was previously called here as a "safety net", but on Mesa/Nvidia + // drivers it silently resets GL_TEXTURE_MIN_FILTER to the OpenGL spec default + // (GL_NEAREST_MIPMAP_LINEAR), overriding the GL_NEAREST set before this call. + // Fix: set GL_TEXTURE_MAX_LEVEL=0 (only sample level 0) and re-enforce GL_NEAREST. + // The game manually uploads explicit mip levels 1..N-1 after this call anyway, + // so we don't need glGenerateMipmap() as a completeness safety net. if (level == 0) { - GLint maxLevel = 0; - ::glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, &maxLevel); - if (maxLevel > 0) { - ::glGenerateMipmap(GL_TEXTURE_2D); - } + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } } diff --git a/Minecraft.Client/Rendering/GameRenderer.cpp b/Minecraft.Client/Rendering/GameRenderer.cpp index 19076b729..def5b31d6 100644 --- a/Minecraft.Client/Rendering/GameRenderer.cpp +++ b/Minecraft.Client/Rendering/GameRenderer.cpp @@ -838,11 +838,16 @@ void GameRenderer::turnOnLightLayer(double alpha) glActiveTexture(GL_TEXTURE0); } #endif + // Linux/PC: TextureBindVertex is a no-op (no vertex texture unit on desktop GL2.1). + // The glTexParameteri calls below MUST NOT execute — they would corrupt the currently + // bound terrain atlas on GL_TEXTURE0, replacing GL_NEAREST with GL_LINEAR every frame. RenderManager.TextureBindVertex(getLightTexture(mc->player->GetXboxPad(), mc->level)); +#if 0 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); +#endif } // 4J - change brought forward from 1.8.2 diff --git a/Minecraft.Client/Textures/Textures.cpp b/Minecraft.Client/Textures/Textures.cpp index c08b0de03..07af71b56 100644 --- a/Minecraft.Client/Textures/Textures.cpp +++ b/Minecraft.Client/Textures/Textures.cpp @@ -17,7 +17,12 @@ #include "../../Minecraft.World/Headers/net.minecraft.world.level.h" #include "../../Minecraft.World/Util/StringHelpers.h" -bool Textures::MIPMAP = true; +// Linux/PC port: disable mipmapping globally so textures are always sampled from +// the full-resolution level 0 with GL_NEAREST, giving pixel-crisp Minecraft blocks +// at all distances. Mipmapping causes glGenerateMipmap() to fire (which resets the +// min-filter to GL_NEAREST_MIPMAP_LINEAR on many Mesa/Nvidia drivers) and the +// per-level crispBlend loop is both wasteful and still causes visible blurring. +bool Textures::MIPMAP = false; C4JRender::eTextureFormat Textures::TEXTURE_FORMAT = C4JRender::TEXTURE_FORMAT_RxGyBzAw; int Textures::preLoadedIdx[TN_COUNT];