diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cd039ec..dc695e06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,7 +87,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp include/services/ac.hpp include/services/am.hpp include/services/boss.hpp include/services/frd.hpp include/services/nim.hpp include/fs/archive_ext_save_data.hpp include/services/shared_font.hpp include/fs/archive_ncch.hpp - include/renderer_gl/textures.hpp + include/renderer_gl/textures.hpp include/colour.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/colour.hpp b/include/colour.hpp new file mode 100644 index 00000000..67ee15b2 --- /dev/null +++ b/include/colour.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "helpers.hpp" + +// Helpers functions for converting colour channels between bit depths +namespace Colour { + inline static u8 convert4To8Bit(u8 c) { + return (c << 4) | c; + } + + inline static u8 convert5To8Bit(u8 c) { + return (c << 3) | (c >> 2); + } +} \ No newline at end of file diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index 0082db4b..a5452b9d 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -45,6 +45,7 @@ class Renderer { const std::array& regs; OpenGL::Framebuffer getColourFBO(); + OpenGL::Texture getTexture(Texture& tex); MAKE_LOG_FUNCTION(log, rendererLogger) diff --git a/include/renderer_gl/surface_cache.hpp b/include/renderer_gl/surface_cache.hpp index 07dcc7dd..4980c1a4 100644 --- a/include/renderer_gl/surface_cache.hpp +++ b/include/renderer_gl/surface_cache.hpp @@ -41,7 +41,7 @@ public: } // Adds a surface object to the cache and returns it - SurfaceType add(SurfaceType& surface) { + SurfaceType add(const SurfaceType& surface) { if (size >= capacity) { Helpers::panic("Surface cache full! Add emptying!"); } diff --git a/include/renderer_gl/textures.hpp b/include/renderer_gl/textures.hpp index 72e72b67..e6ebaecf 100644 --- a/include/renderer_gl/textures.hpp +++ b/include/renderer_gl/textures.hpp @@ -55,9 +55,12 @@ struct Texture { } void allocate(); + void decodeTexture(void* data); void free(); u64 sizeInBytes(); + u32 decodeTexel(u32 u, u32 v, Formats fmt, void* data); + // Get the morton interleave offset of a texel based on its U and V values static u32 mortonInterleave(u32 u, u32 v); // Get the byte offset of texel (u, v) in the texture diff --git a/src/core/renderer_gl/textures.cpp b/src/core/renderer_gl/textures.cpp index 8e80cf0a..30dd71b8 100644 --- a/src/core/renderer_gl/textures.cpp +++ b/src/core/renderer_gl/textures.cpp @@ -1,4 +1,5 @@ #include "renderer_gl/textures.hpp" +#include "colour.hpp" void Texture::allocate() { Helpers::panic("Tried to allocate texture"); @@ -70,4 +71,37 @@ u32 Texture::getSwizzledOffset(u32 u, u32 v, u32 width, u32 bytesPerPixel) { offset += mortonInterleave(u, v); // Add the in-tile offset of the texel return offset * bytesPerPixel; +} + +u32 Texture::decodeTexel(u32 u, u32 v, Texture::Formats fmt, void* data) { + switch (fmt) { + case Formats::RGBA4: { + u32 offset = getSwizzledOffset(u, v, size.u(), 2); + u8* ptr = static_cast(data); + u16 texel = u16(ptr[offset]) | (u16(ptr[offset + 1]) << 8); + + u8 alpha = Colour::convert4To8Bit(texel & 0xf); + u8 b = Colour::convert4To8Bit((texel >> 4) & 0xf); + u8 g = Colour::convert4To8Bit((texel >> 8) & 0xf); + u8 r = Colour::convert4To8Bit((texel >> 12) & 0xf); + + return (r << 24) | (g << 16) | (b << 8) | alpha; + } + + default: + Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast(fmt)); + } +} + +void Texture::decodeTexture(void* data) { + std::vector decoded; + decoded.reserve(size.u() * size.v()); + + // Decode texels line by line + for (u32 v = 0; v < size.v(); v++) { + for (u32 u = 0; u < size.u(); u++) { + u32 colour = decodeTexel(u, v, format, data); + decoded.push_back(colour); + } + } } \ No newline at end of file