From fdb2a1098b5f7e1e44259c5c05ae70a011f057f8 Mon Sep 17 00:00:00 2001 From: MatthewBeshay <92357869+MatthewBeshay@users.noreply.github.com> Date: Tue, 24 Mar 2026 08:21:19 +1100 Subject: [PATCH] fix: restore block lightmap sampling --- Minecraft.Client/Platform/Linux/LinuxGL.cpp | 44 +++++++++++++++++++ Minecraft.Client/Platform/stubs.cpp | 16 ++++++- Minecraft.Client/Platform/stubs.h | 2 + .../EntityRenderers/ItemInHandRenderer.cpp | 9 ++++ Minecraft.Client/Rendering/GameRenderer.cpp | 26 +++++++++++ Minecraft.Client/Rendering/Tesselator.cpp | 40 +++++++++++++++-- 6 files changed, 131 insertions(+), 6 deletions(-) diff --git a/Minecraft.Client/Platform/Linux/LinuxGL.cpp b/Minecraft.Client/Platform/Linux/LinuxGL.cpp index fd4919b0b..351bb5d24 100644 --- a/Minecraft.Client/Platform/Linux/LinuxGL.cpp +++ b/Minecraft.Client/Platform/Linux/LinuxGL.cpp @@ -1,5 +1,7 @@ #ifdef __linux__ +#include "../stdafx.h" + #include #include #include @@ -9,6 +11,48 @@ #include "../../Minecraft.World/IO/Streams/FloatBuffer.h" #include "../../Minecraft.World/IO/Streams/ByteBuffer.h" +void LinuxGLLogLightmapState(const char* stage, int textureId, bool scaleLight) { + static int logCount = 0; + if (logCount >= 16) return; + + ++logCount; + + static bool loggedSymbols = false; + if (!loggedSymbols) { + loggedSymbols = true; + app.DebugPrintf( + "[linux-lightmap] linuxgl symbols glActiveTexture=%p " + "glClientActiveTexture=%p glMultiTexCoord2f=%p\n", + reinterpret_cast(::glActiveTexture), + reinterpret_cast(::glClientActiveTexture), + reinterpret_cast(::glMultiTexCoord2f)); + } + + GLint activeTexture = 0; + GLint matrixMode = 0; + ::glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture); + ::glGetIntegerv(GL_MATRIX_MODE, &matrixMode); + + const GLint restoreTexture = activeTexture; + ::glActiveTexture(GL_TEXTURE1); + + GLint unit1Binding = 0; + ::glGetIntegerv(GL_TEXTURE_BINDING_2D, &unit1Binding); + const bool unit1Enabled = (::glIsEnabled(GL_TEXTURE_2D) == GL_TRUE); + + GLfloat textureMatrix[16]; + ::glGetFloatv(GL_TEXTURE_MATRIX, textureMatrix); + + ::glActiveTexture(restoreTexture); + + app.DebugPrintf( + "[linux-lightmap] %s tex=%d scale=%d active=%#x matrixMode=%#x " + "unit1Bound=%d unit1Enabled=%d texMatrix=[%.4f %.4f %.4f %.4f]\n", + stage, textureId, scaleLight ? 1 : 0, activeTexture, matrixMode, + unit1Binding, unit1Enabled ? 1 : 0, textureMatrix[0], textureMatrix[5], + textureMatrix[12], textureMatrix[13]); +} + int glGenTextures() { GLuint id = 0; ::glGenTextures(1, &id); diff --git a/Minecraft.Client/Platform/stubs.cpp b/Minecraft.Client/Platform/stubs.cpp index ad16cc431..97620df18 100644 --- a/Minecraft.Client/Platform/stubs.cpp +++ b/Minecraft.Client/Platform/stubs.cpp @@ -1,6 +1,18 @@ #include "stdafx.h" -#ifndef __linux__ +#ifdef __linux__ + +void LinuxLogStubLightmapProbe() { + static bool logged = false; + if (logged) return; + + logged = true; + app.DebugPrintf( + "[linux-lightmap] stubs.cpp: Linux excludes the no-op multitexture " + "stubs in this file; the runtime uses libGL/4jlibs symbols.\n"); +} + +#else void glReadPixels(int,int, int, int, int, int, ByteBuffer *) { @@ -120,4 +132,4 @@ DWORD XCamSetView( XCAMDEVICESTATE XCamGetStatus() { return XCAMDEVICESTATE_DISCONNECTED; } #endif -#endif \ No newline at end of file +#endif diff --git a/Minecraft.Client/Platform/stubs.h b/Minecraft.Client/Platform/stubs.h index a868ea6fc..91464c6a8 100644 --- a/Minecraft.Client/Platform/stubs.h +++ b/Minecraft.Client/Platform/stubs.h @@ -34,6 +34,8 @@ void glBeginQueryARB(int, int); void glEndQueryARB(int); void glGetQueryObjectuARB(int, int, IntBuffer *); void glReadPixels(int, int, int, int, int, int, ByteBuffer *); +void LinuxGLLogLightmapState(const char* stage, int textureId, bool scaleLight); +void LinuxLogStubLightmapProbe(); #else diff --git a/Minecraft.Client/Rendering/EntityRenderers/ItemInHandRenderer.cpp b/Minecraft.Client/Rendering/EntityRenderers/ItemInHandRenderer.cpp index 69d49339b..7503821aa 100644 --- a/Minecraft.Client/Rendering/EntityRenderers/ItemInHandRenderer.cpp +++ b/Minecraft.Client/Rendering/EntityRenderers/ItemInHandRenderer.cpp @@ -441,6 +441,15 @@ void ItemInHandRenderer::render(float a) { Mth::floor(player->z), 0); int u = col % 65536; int v = col / 65536; +#ifdef __linux__ + static int lightmapLogCount = 0; + if (lightmapLogCount < 8) { + ++lightmapLogCount; + app.DebugPrintf( + "[linux-lightmap] item-hand raw=0x%08x uv=(%d,%d)\n", col, u, + v); + } +#endif glMultiTexCoord2f(GL_TEXTURE1, u / 1.0f, v / 1.0f); glColor4f(1, 1, 1, 1); } diff --git a/Minecraft.Client/Rendering/GameRenderer.cpp b/Minecraft.Client/Rendering/GameRenderer.cpp index e8f728b73..dc7ae6a28 100644 --- a/Minecraft.Client/Rendering/GameRenderer.cpp +++ b/Minecraft.Client/Rendering/GameRenderer.cpp @@ -767,6 +767,13 @@ void GameRenderer::renderItemInHand(float a, int eye) { // 4J - change brought forward from 1.8.2 void GameRenderer::turnOffLightLayer(double alpha) { // 4J - TODO +#ifdef __linux__ + if (SharedConstants::TEXTURE_LIGHTING) { + LinuxLogStubLightmapProbe(); + RenderManager.TextureBindVertex(-1); + LinuxGLLogLightmapState("turnOffLightLayer", -1, false); + } +#else // 4jcraft: manually handle this in order to ensure that the light layer is // turned off correctly #if 1 @@ -784,12 +791,30 @@ void GameRenderer::turnOffLightLayer(double alpha) { // 4J - TODO #else RenderManager.TextureBindVertex(-1); #endif +#endif } // 4J - change brought forward from 1.8.2 void GameRenderer::turnOnLightLayer( double alpha, bool scaleLight) { // 4jcraft: added scaleLight for entity lighting +#ifdef __linux__ + if (!SharedConstants::TEXTURE_LIGHTING) return; + + LinuxLogStubLightmapProbe(); + const int textureId = getLightTexture(mc->player->GetXboxPad(), mc->level); + + static int logCount = 0; + if (logCount < 16) { + ++logCount; + app.DebugPrintf( + "[linux-lightmap] turnOnLightLayer tex=%d scale=%d\n", textureId, + scaleLight ? 1 : 0); + } + + RenderManager.TextureBindVertex(textureId, scaleLight); + LinuxGLLogLightmapState("turnOnLightLayer", textureId, scaleLight); +#else #if 0 if (SharedConstants::TEXTURE_LIGHTING) { @@ -827,6 +852,7 @@ void GameRenderer::turnOnLightLayer( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); #endif +#endif } // 4J - change brought forward from 1.8.2 diff --git a/Minecraft.Client/Rendering/Tesselator.cpp b/Minecraft.Client/Rendering/Tesselator.cpp index acc2ce854..35e472a45 100644 --- a/Minecraft.Client/Rendering/Tesselator.cpp +++ b/Minecraft.Client/Rendering/Tesselator.cpp @@ -741,6 +741,31 @@ typedef unsigned short hfloat; extern hfloat convertFloatToHFloat(float f); extern float convertHFloatToFloat(hfloat hf); +#ifdef __linux__ +namespace { +void packLinuxLightmapCoords(int tex2, std::int16_t& u, std::int16_t& v) { + u = static_cast(tex2 & 0xffff); + v = static_cast((tex2 >> 16) & 0xffff); + + // Linux 4jlibs consumes packed UV2 values by dividing them by 256 directly + // for chunk and other non-scaleLight draws, so offset to texel centers here. + u += 8; + v += 8; +} + +void logLinuxPackedLightmapCoords(const char* path, int tex2, std::int16_t u, + std::int16_t v) { + static int logCount = 0; + if (logCount >= 16) return; + + ++logCount; + app.DebugPrintf( + "[linux-lightmap] %s raw=0x%08x packed=(%d,%d) sampled=(%.4f,%.4f)\n", + path, tex2, (int)u, (int)v, u / 256.0f, v / 256.0f); +} +} // namespace +#endif + void Tesselator::vertex(float x, float y, float z) { bounds.addVert(x + xo, y + yo, z + zo); // 4J MGH - added count++; @@ -828,8 +853,13 @@ void Tesselator::vertex(float x, float y, float z) { pShortData[3] = ipackedcol; pShortData[4] = (((int)(uu * 8192.0f)) & 0xffff); pShortData[5] = (((int)(v * 8192.0f)) & 0xffff); - std::int16_t u2 = ((std::int16_t*)&_tex2)[0]; - std::int16_t v2 = ((std::int16_t*)&_tex2)[1]; + std::int16_t u2 = static_cast(_tex2 & 0xffff); + std::int16_t v2 = + static_cast((_tex2 >> 16) & 0xffff); +#ifdef __linux__ + packLinuxLightmapCoords(_tex2, u2, v2); + logLinuxPackedLightmapCoords("compact", _tex2, u2, v2); +#endif #if defined _XBOX_ONE || defined __ORBIS__ // Optimisation - pack the second UVs into a single short (they could // actually go in a byte), which frees up a short to store the x offset @@ -943,8 +973,10 @@ void Tesselator::vertex(float x, float y, float z) { std::int16_t tex2U = ((std::int16_t*)&_tex2)[1] + 8; std::int16_t tex2V = ((std::int16_t*)&_tex2)[0] + 8; #else - std::int16_t tex2U = ((std::int16_t*)&_tex2)[0] + 8; - std::int16_t tex2V = ((std::int16_t*)&_tex2)[1] + 8; + std::int16_t tex2U; + std::int16_t tex2V; + packLinuxLightmapCoords(_tex2, tex2U, tex2V); + logLinuxPackedLightmapCoords("standard", _tex2, tex2U, tex2V); #endif std::int16_t* pShortArray = (std::int16_t*)&_array->data[p + 7]; pShortArray[0] = tex2U;