From b62a14d3ffb5c16962d3a931cf9cee298939c38d Mon Sep 17 00:00:00 2001
From: Samuliak <samuliak77@gmail.com>
Date: Tue, 2 Jul 2024 13:40:29 +0200
Subject: [PATCH] implement textures

---
 include/renderer_mtl/renderer_mtl.hpp  |  3 ++
 src/core/renderer_mtl/renderer_mtl.cpp | 50 ++++++++++++++++++++++++++
 src/core/renderer_mtl/texture.cpp      | 13 +++++--
 3 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/include/renderer_mtl/renderer_mtl.hpp b/include/renderer_mtl/renderer_mtl.hpp
index 892eedc1..5d30c644 100644
--- a/include/renderer_mtl/renderer_mtl.hpp
+++ b/include/renderer_mtl/renderer_mtl.hpp
@@ -54,4 +54,7 @@ class RendererMTL final : public Renderer {
 			commandBuffer = commandQueue->commandBuffer();
 		}
 	}
+
+	MTL::Texture* getTexture(Metal::Texture& tex);
+	void bindTexturesToSlots();
 };
diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp
index dbf34881..d1b734e3 100644
--- a/src/core/renderer_mtl/renderer_mtl.cpp
+++ b/src/core/renderer_mtl/renderer_mtl.cpp
@@ -1,3 +1,4 @@
+#include "PICA/gpu.hpp"
 #include "renderer_mtl/renderer_mtl.hpp"
 
 #include <cmrc/cmrc.hpp>
@@ -209,6 +210,9 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::span<const PICA::Ve
 	renderCommandEncoder->setRenderPipelineState(drawPipeline);
 	renderCommandEncoder->setVertexBytes(vertices.data(), vertices.size_bytes(), VERTEX_BUFFER_BINDING_INDEX);
 
+	// Bind resources
+	bindTexturesToSlots();
+
 	// TODO: respect primitive type
 	renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangle, NS::UInteger(0), NS::UInteger(vertices.size()));
 
@@ -226,3 +230,49 @@ void RendererMTL::deinitGraphicsContext() {
 	// TODO: implement
 	Helpers::warn("RendererMTL::deinitGraphicsContext not implemented");
 }
+
+MTL::Texture* RendererMTL::getTexture(Metal::Texture& tex) {
+	auto buffer = textureCache.find(tex);
+
+	if (buffer.has_value()) {
+		return buffer.value().get().texture;
+	} else {
+		const auto textureData = std::span{gpu.getPointerPhys<u8>(tex.location), tex.sizeInBytes()};  // Get pointer to the texture data in 3DS memory
+		Metal::Texture& newTex = textureCache.add(tex);
+		newTex.decodeTexture(textureData);
+
+		return newTex.texture;
+	}
+}
+
+void RendererMTL::bindTexturesToSlots() {
+	static constexpr std::array<u32, 3> ioBases = {
+		PICA::InternalRegs::Tex0BorderColor,
+		PICA::InternalRegs::Tex1BorderColor,
+		PICA::InternalRegs::Tex2BorderColor,
+	};
+
+	for (int i = 0; i < 3; i++) {
+		if ((regs[PICA::InternalRegs::TexUnitCfg] & (1 << i)) == 0) {
+			continue;
+		}
+
+		const size_t ioBase = ioBases[i];
+
+		const u32 dim = regs[ioBase + 1];
+		const u32 config = regs[ioBase + 2];
+		const u32 height = dim & 0x7ff;
+		const u32 width = Helpers::getBits<16, 11>(dim);
+		const u32 addr = (regs[ioBase + 4] & 0x0FFFFFFF) << 3;
+		u32 format = regs[ioBase + (i == 0 ? 13 : 5)] & 0xF;
+
+		if (addr != 0) [[likely]] {
+			Metal::Texture targetTex(device, addr, static_cast<PICA::TextureFmt>(format), width, height, config);
+			MTL::Texture* tex = getTexture(targetTex);
+			// TODO: bind the texture
+			Helpers::warn("Wanted to bind texture %p at index %i", tex, i);
+		} else {
+			// TODO: bind a dummy texture?
+		}
+	}
+}
diff --git a/src/core/renderer_mtl/texture.cpp b/src/core/renderer_mtl/texture.cpp
index a556263c..a4c1dd4d 100644
--- a/src/core/renderer_mtl/texture.cpp
+++ b/src/core/renderer_mtl/texture.cpp
@@ -228,8 +228,14 @@ u32 Texture::decodeTexel(u32 u, u32 v, PICA::TextureFmt fmt, std::span<const u8>
             return (alpha << 24) | (intensity << 16) | (intensity << 8) | intensity;
         }
 
-        case PICA::TextureFmt::ETC1: return getTexelETC(false, u, v, size.u(), data);
-        case PICA::TextureFmt::ETC1A4: return getTexelETC(true, u, v, size.u(), data);
+        case PICA::TextureFmt::ETC1: {
+            //return getTexelETC(false, u, v, size.u(), data);
+            Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast<int>(fmt));
+        }
+        case PICA::TextureFmt::ETC1A4: {
+            //return getTexelETC(true, u, v, size.u(), data);
+            Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast<int>(fmt));
+        }
 
         default:
             Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast<int>(fmt));
@@ -248,7 +254,8 @@ void Texture::decodeTexture(std::span<const u8> data) {
         }
     }
 
-    u32 bytesPerRow = sizeInBytes() / size.v();
+    // TODO: is this correct?
+    u32 bytesPerRow = 4 * size.u();//sizeInBytes() / size.v();
     texture->replaceRegion(MTL::Region(0, 0, size.u(), size.v()), 0, 0, decoded.data(), bytesPerRow, 0);
 }