From 0fba1d48a6ab7a9fa19ce65ec864da212ceb501a Mon Sep 17 00:00:00 2001
From: Tony Wasserka <NeoBrainX@gmail.com>
Date: Thu, 4 Dec 2014 17:37:59 +0100
Subject: [PATCH] Pica: Implement texture wrapping.

---
 src/video_core/pica.h         | 12 +++++++++++-
 src/video_core/rasterizer.cpp | 21 ++++++++++++++++++++-
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 7ed49caedd..ec20114fe3 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -104,6 +104,11 @@ struct Regs {
     INSERT_PADDING_WORDS(0x17);
 
     struct TextureConfig {
+        enum WrapMode : u32 {
+            ClampToEdge = 0,
+            Repeat      = 2,
+        };
+
         INSERT_PADDING_WORDS(0x1);
 
         union {
@@ -111,7 +116,12 @@ struct Regs {
             BitField<16, 16, u32> width;
         };
 
-        INSERT_PADDING_WORDS(0x2);
+        union {
+            BitField< 8, 2, WrapMode> wrap_s;
+            BitField<11, 2, WrapMode> wrap_t;
+        };
+
+        INSERT_PADDING_WORDS(0x1);
 
         u32 address;
 
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 2ff6d19a66..e12f68a7f1 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -181,7 +181,7 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
                 if (!texture.enabled)
                     continue;
 
-                _dbg_assert_(GPU, 0 != texture.config.address);
+                _dbg_assert_(HW_GPU, 0 != texture.config.address);
 
                 // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each
                 // of which is composed of four 2x2 subtiles each of which is composed of four texels.
@@ -206,6 +206,25 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
                 // somewhat inefficient code around for now.
                 int s = (int)(uv[i].u() * float24::FromFloat32(static_cast<float>(texture.config.width))).ToFloat32();
                 int t = (int)(uv[i].v() * float24::FromFloat32(static_cast<float>(texture.config.height))).ToFloat32();
+                auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val, unsigned size) {
+                    switch (mode) {
+                        case Regs::TextureConfig::ClampToEdge:
+                            val = std::max(val, 0);
+                            val = std::min(val, (int)size - 1);
+                            return val;
+
+                        case Regs::TextureConfig::Repeat:
+                            return (int)(((unsigned)val) % size);
+
+                        default:
+                            LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x\n", (int)mode);
+                            _dbg_assert_(HW_GPU, 0);
+                            return 0;
+                    }
+                };
+                s = GetWrappedTexCoord(registers.texture0.wrap_s, s, registers.texture0.width);
+                t = GetWrappedTexCoord(registers.texture0.wrap_t, t, registers.texture0.height);
+
                 int texel_index_within_tile = 0;
                 for (int block_size_index = 0; block_size_index < 3; ++block_size_index) {
                     int sub_tile_width = 1 << block_size_index;