From 781c39a2cf78c8dd5e79e9640570c6bb4a409fc9 Mon Sep 17 00:00:00 2001 From: RDW Date: Mon, 18 Mar 2024 17:56:12 +0100 Subject: [PATCH] GND: Implement error correction for lightmap textures The blending stage interpolates colors linearly when multiplying with the higher-precision inputs (same as for diffuse textures). --- Core/FileFormats/RagnarokGND.lua | 18 +++++++++++------- Tests/FileFormats/RagnarokGND.spec.lua | 2 +- Tests/Tools/RagnarokTools.spec.lua | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Core/FileFormats/RagnarokGND.lua b/Core/FileFormats/RagnarokGND.lua index a66765b1..bfb42712 100644 --- a/Core/FileFormats/RagnarokGND.lua +++ b/Core/FileFormats/RagnarokGND.lua @@ -10,7 +10,7 @@ local ffi = require("ffi") local uv = require("uv") local assert = assert -local math_floor = math.floor +local floor = math.floor local format = string.format local table_insert = table.insert local tonumber = tonumber @@ -800,9 +800,9 @@ function RagnarokGND:GenerateLightmapTextureImage(posterizationLevel) local rgbaImageBytes = buffer.new(width * height * 4) local bufferStartPointer, reservedlength = rgbaImageBytes:reserve(width * height * 4) for pixelV = 0, height - 1, 1 do - local sliceV = math_floor(pixelV / 8) + local sliceV = floor(pixelV / 8) for pixelU = 0, width - 1, 1 do - local sliceU = math_floor(pixelU / 8) + local sliceU = floor(pixelU / 8) local sliceID = sliceV * numSlicesPerRow + sliceU local offsetU = pixelU % 8 local offsetV = pixelV % 8 @@ -827,10 +827,14 @@ function RagnarokGND:GenerateLightmapTextureImage(posterizationLevel) posterizedBlue = bit.lshift(posterizedBlue, posterizationLevel) posterizedAlpha = bit.lshift(posterizedAlpha, posterizationLevel) - bufferStartPointer[writableAreaStartIndex + 0] = posterizedRed - bufferStartPointer[writableAreaStartIndex + 1] = posterizedGreen - bufferStartPointer[writableAreaStartIndex + 2] = posterizedBlue - bufferStartPointer[writableAreaStartIndex + 3] = posterizedAlpha + local remainingColorDepthInBitsPerPixel = math.max(1, 8 - posterizationLevel) + local numAvailableColorValues = math.pow(2, remainingColorDepthInBitsPerPixel) -- 256, 128, 64, 32, 16, 8 + local errorCorrection = 1 / numAvailableColorValues + + bufferStartPointer[writableAreaStartIndex + 0] = posterizedRed + floor(errorCorrection * red) + bufferStartPointer[writableAreaStartIndex + 1] = posterizedGreen + floor(errorCorrection * green) + bufferStartPointer[writableAreaStartIndex + 2] = posterizedBlue + floor(errorCorrection * blue) + bufferStartPointer[writableAreaStartIndex + 3] = posterizedAlpha + floor(errorCorrection * alpha) else -- Slightly wasteful, but the determinism enables testing (and it's barely noticeable anyway) bufferStartPointer[writableAreaStartIndex + 0] = 255 bufferStartPointer[writableAreaStartIndex + 1] = 0 diff --git a/Tests/FileFormats/RagnarokGND.spec.lua b/Tests/FileFormats/RagnarokGND.spec.lua index 20ccbc7e..f475e4e0 100644 --- a/Tests/FileFormats/RagnarokGND.spec.lua +++ b/Tests/FileFormats/RagnarokGND.spec.lua @@ -599,7 +599,7 @@ describe("RagnarokGND", function() assertEquals(lightmapTextureImage.height, 8) local rawImageBytes = tostring(lightmapTextureImage.rgbaImageBytes) - local expectedTextureChecksum = 288753058 + local expectedTextureChecksum = 3839217290 local generatedTextureChecksum = miniz.crc32(rawImageBytes) assertEquals(generatedTextureChecksum, expectedTextureChecksum) end) diff --git a/Tests/Tools/RagnarokTools.spec.lua b/Tests/Tools/RagnarokTools.spec.lua index 716ba11d..1554f0db 100644 --- a/Tests/Tools/RagnarokTools.spec.lua +++ b/Tests/Tools/RagnarokTools.spec.lua @@ -49,7 +49,7 @@ describe("RagnarokTools", function() it("should export the GND lightmap data in a human-readable format if a valid GND buffer is passed", function() local expectedLightmapChecksum = "be735bab85771a54892d4129d7aba3126e0f7f41f2c9891a28aa8dcfc897d2fa" local expectedShadowmapChecksum = "4a7a36bedbb8e73797b91b2f568b59b8d4600dc3975e2265114339a5142e9175" - local expectedTextureChecksum = "dfbff3a58a516c0990147567388431dee2d05dae12a01bd5fb4d30230bb79573" + local expectedTextureChecksum = "b8323aa6889476237edea7d1ce894c889e3bb7dbd464bbe1068568994999c659" local gndFileContents = C_FileSystem.ReadFile(path.join("Tests", "Fixtures", "no-water-plane.gnd")) RagnarokTools:ExportLightmapsFromGND(gndFileContents)