diff --git a/Core/FileFormats/RagnarokMap.lua b/Core/FileFormats/RagnarokMap.lua index dbaddbc8..9658869c 100644 --- a/Core/FileFormats/RagnarokMap.lua +++ b/Core/FileFormats/RagnarokMap.lua @@ -4,6 +4,7 @@ local RagnarokGRF = require("Core.FileFormats.RagnarokGRF") local RagnarokRSW = require("Core.FileFormats.RagnarokRSW") local C_Resources = require("Core.NativeClient.C_Resources") +local Texture = require("Core.NativeClient.WebGPU.Texture") local NormalsVisualization = require("Core.NativeClient.DebugDraw.NormalsVisualization") @@ -100,6 +101,8 @@ function RagnarokMap:LoadTerrainGeometry(mapID) local textureImageBytes = self:FetchResourceByID(normalizedTextureImagePath) local rgbaImageBytes, width, height = C_ImageProcessing.DecodeFileContents(textureImageBytes) + rgbaImageBytes, width, height = Texture:CreateReducedColorImage(rgbaImageBytes, width, height) + printf( "[RagnarokMap] Loading GND ground mesh section %d with diffuse texture %s (%d x %d)", sectionID, diff --git a/Core/NativeClient/WebGPU/Texture.lua b/Core/NativeClient/WebGPU/Texture.lua index 875bda8d..3a8963b2 100644 --- a/Core/NativeClient/WebGPU/Texture.lua +++ b/Core/NativeClient/WebGPU/Texture.lua @@ -209,6 +209,45 @@ function Texture:CreateTextureView(wgpuTexture, wgpuTextureViewDescriptor) return webgpu.bindings.wgpu_texture_create_view(wgpuTexture, wgpuTextureViewDescriptor) end +-- Should probably be replaced with an optimized version (via the ImageProcessing API)? +function Texture:CreateReducedColorImage(inputImageBytes, width, height, posterizationLevel) + posterizationLevel = posterizationLevel or 3 + + local numBytesWritten = 0 + local rgbaImageBytes = buffer.new(width * height * 4) + local bufferStartPointer = rgbaImageBytes:reserve(width * height * 4) + local inputPixels = buffer.new():put(inputImageBytes):ref() + for pixelV = 0, height - 1, 1 do + for pixelU = 0, width - 1, 1 do + local writableAreaStartIndex = (pixelV * width + pixelU) * 4 + local red = inputPixels[writableAreaStartIndex + 0] + local green = inputPixels[writableAreaStartIndex + 1] + local blue = inputPixels[writableAreaStartIndex + 2] + local alpha = inputPixels[writableAreaStartIndex + 3] + + local posterizedRed = bit.rshift(red, posterizationLevel) + local posterizedGreen = bit.rshift(green, posterizationLevel) + local posterizedBlue = bit.rshift(blue, posterizationLevel) + local posterizedAlpha = bit.rshift(alpha, posterizationLevel) + posterizedRed = bit.lshift(posterizedRed, posterizationLevel) + posterizedGreen = bit.lshift(posterizedGreen, 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 + + numBytesWritten = numBytesWritten + 4 + end + end + + rgbaImageBytes:commit(numBytesWritten) + + return rgbaImageBytes, width, height +end + Texture.__call = Texture.Construct Texture.__index = Texture setmetatable(Texture, Texture) diff --git a/Tests/FileFormats/RagnarokMap.spec.lua b/Tests/FileFormats/RagnarokMap.spec.lua index eb9dff9f..4c547a1b 100644 --- a/Tests/FileFormats/RagnarokMap.spec.lua +++ b/Tests/FileFormats/RagnarokMap.spec.lua @@ -5,6 +5,16 @@ local RagnarokRSW = require("Core.FileFormats.RagnarokRSW") local Texture = require("Core.NativeClient.WebGPU.Texture") +local openssl = require("openssl") +local digest = openssl.digest.digest + +local function assertImageChecksumMatches(actualImageBytes, expectedImageBytes) + local checksum = digest("sha256", tostring(actualImageBytes)) + expectedImageBytes = Texture:CreateReducedColorImage(expectedImageBytes, 256, 256) + local expectedChecksum = digest("sha256", tostring(expectedImageBytes)) + assertEquals(checksum, expectedChecksum) +end + local function makeFileSystem(name) local testFileSystem = { ROOT_DIR = path.join("Tests", "Fixtures", "Borftopia"), @@ -80,7 +90,7 @@ describe("RagnarokMap", function() assertEquals(#map.meshes, 2 + 1) assertEquals(#map.meshes, #groundMeshSections + #waterPlanes) - assertEquals(map.meshes[1].diffuseTextureImage.rgbaImageBytes, gradientTexture) + assertImageChecksumMatches(map.meshes[1].diffuseTextureImage.rgbaImageBytes, gradientTexture) assertEquals(map.meshes[1].diffuseTextureImage.width, 256) assertEquals(map.meshes[1].diffuseTextureImage.height, 256) assertEquals(map.meshes[1].vertexPositions, groundMeshSections[1].vertexPositions) @@ -88,7 +98,7 @@ describe("RagnarokMap", function() assertEquals(map.meshes[1].triangleConnections, groundMeshSections[1].triangleConnections) assertEquals(map.meshes[1].diffuseTextureCoords, groundMeshSections[1].diffuseTextureCoords) - assertEquals(map.meshes[2].diffuseTextureImage.rgbaImageBytes, gridTexture) + assertImageChecksumMatches(map.meshes[2].diffuseTextureImage.rgbaImageBytes, gridTexture) assertEquals(map.meshes[2].diffuseTextureImage.width, 256) assertEquals(map.meshes[2].diffuseTextureImage.height, 256) assertEquals(map.meshes[2].vertexPositions, groundMeshSections[2].vertexPositions) diff --git a/Tests/NativeClient/WebGPU/Texture.spec.lua b/Tests/NativeClient/WebGPU/Texture.spec.lua index 983ac23a..27612ef9 100644 --- a/Tests/NativeClient/WebGPU/Texture.spec.lua +++ b/Tests/NativeClient/WebGPU/Texture.spec.lua @@ -204,4 +204,15 @@ describe("Texture", function() end, Texture.ERROR_DIMENSIONS_EXCEEDING_LIMIT) end) end) + + describe("CreateReducedColorImage", function() + it("should reduce the color depth of the texture image", function() + local testImage = "\255\192\128\000" .. "\007\007\007\007" + local reducedColorImage, width, height = Texture:CreateReducedColorImage(testImage, 2, 1) + local expectedimageBytes = "\248\192\128\000\000\000\000\000" + assertEquals(width, 2) + assertEquals(height, 1) + assertEquals(tostring(reducedColorImage), expectedimageBytes) + end) + end) end)