From 119c908aa70e305047ad7f9f47e2e1009df6d0e5 Mon Sep 17 00:00:00 2001
From: Wunkolo <Wunkolo@gmail.com>
Date: Mon, 19 Jun 2023 21:18:51 -0700
Subject: [PATCH] Add explicit return-type overload for `getBits`

Allows the return-type to be specified, allowing a concise final cast
after extracting the bit-type.  Addresses the remaining `C4244` warnings
regarding `getBits`.
---
 include/helpers.hpp               | 13 ++++++++++---
 src/core/renderer_gl/etc1.cpp     | 32 +++++++++++++++----------------
 src/core/renderer_gl/textures.cpp | 20 +++++++++----------
 3 files changed, 36 insertions(+), 29 deletions(-)

diff --git a/include/helpers.hpp b/include/helpers.hpp
index 9830cc88..4162309e 100644
--- a/include/helpers.hpp
+++ b/include/helpers.hpp
@@ -113,9 +113,16 @@ namespace Helpers {
 	}
 
 	/// Extract bits from an integer-type
-	template <usize offset, usize bits, typename T>
-	static constexpr T getBits(T value) {
-		return (value >> offset) & ones<T, bits>();
+	template <usize offset, usize bits, typename ReturnT, typename ValueT>
+	static constexpr ReturnT getBits(ValueT value) {
+		static_assert((offset + bits) <= (CHAR_BIT * sizeof(ValueT)), "Invalid bit range");
+		static_assert(bits > 0, "Invalid bit size");
+		return ReturnT(ValueT(value >> offset) & ones<ValueT, bits>());
+	}
+
+	template <usize offset, usize bits, typename ValueT>
+	static constexpr ValueT getBits(ValueT value) {
+		return getBits<offset, bits, ValueT, ValueT>(value);
 	}
 
 #ifdef HELPERS_APPLE_CLANG
diff --git a/src/core/renderer_gl/etc1.cpp b/src/core/renderer_gl/etc1.cpp
index ae5abb65..82f06724 100644
--- a/src/core/renderer_gl/etc1.cpp
+++ b/src/core/renderer_gl/etc1.cpp
@@ -60,14 +60,14 @@ u32 Texture::decodeETC(u32 alpha, u32 u, u32 v, u64 colourData) {
     };
 
     // Parse colour data for 4x4 block
-    const u32 subindices = getBits<0, 16>(colourData);
-    const u32 negationFlags = getBits<16, 16>(colourData);
+    const u32 subindices = getBits<0, 16, u32>(colourData);
+    const u32 negationFlags = getBits<16, 16, u32>(colourData);
     const bool flip = getBit<32>(colourData);
     const bool diffMode = getBit<33>(colourData);
 
     // Note: index1 is indeed stored on the higher bits, with index2 in the lower bits
-    const u32 tableIndex1 = getBits<37, 3>(colourData);
-    const u32 tableIndex2 = getBits<34, 3>(colourData);
+    const u32 tableIndex1 = getBits<37, 3, u32>(colourData);
+    const u32 tableIndex2 = getBits<34, 3, u32>(colourData);
     const u32 texelIndex = u * 4 + v; // Index of the texel in the block
 
     if (flip)
@@ -75,14 +75,14 @@ u32 Texture::decodeETC(u32 alpha, u32 u, u32 v, u64 colourData) {
 
     s32 r, g, b;
     if (diffMode) {
-        r = getBits<59, 5>(colourData);
-        g = getBits<51, 5>(colourData);
-        b = getBits<43, 5>(colourData);
+        r = getBits<59, 5, s32>(colourData);
+        g = getBits<51, 5, s32>(colourData);
+        b = getBits<43, 5, s32>(colourData);
 
         if (u >= 2) {
-            r += signExtend3To32(getBits<56, 3>(colourData));
-            g += signExtend3To32(getBits<48, 3>(colourData));
-            b += signExtend3To32(getBits<40, 3>(colourData));
+            r += signExtend3To32(getBits<56, 3, u32>(colourData));
+            g += signExtend3To32(getBits<48, 3, u32>(colourData));
+            b += signExtend3To32(getBits<40, 3, u32>(colourData));
         }
 
         // Expand from 5 to 8 bits per channel
@@ -91,13 +91,13 @@ u32 Texture::decodeETC(u32 alpha, u32 u, u32 v, u64 colourData) {
         b = Colour::convert5To8Bit(b);
     } else {
         if (u < 2) {
-            r = getBits<60, 4>(colourData);
-            g = getBits<52, 4>(colourData);
-            b = getBits<44, 4>(colourData);
+            r = getBits<60, 4, s32>(colourData);
+            g = getBits<52, 4, s32>(colourData);
+            b = getBits<44, 4, s32>(colourData);
         } else {
-            r = getBits<56, 4>(colourData);
-            g = getBits<48, 4>(colourData);
-            b = getBits<40, 4>(colourData);
+            r = getBits<56, 4, s32>(colourData);
+            g = getBits<48, 4, s32>(colourData);
+            b = getBits<40, 4, s32>(colourData);
         }
 
         // Expand from 4 to 8 bits per channel
diff --git a/src/core/renderer_gl/textures.cpp b/src/core/renderer_gl/textures.cpp
index e4df36a0..819bf783 100644
--- a/src/core/renderer_gl/textures.cpp
+++ b/src/core/renderer_gl/textures.cpp
@@ -119,10 +119,10 @@ u32 Texture::decodeTexel(u32 u, u32 v, PICA::TextureFmt fmt, const void* data) {
             auto ptr = static_cast<const u8*>(data);
             u16 texel = u16(ptr[offset]) | (u16(ptr[offset + 1]) << 8);
 
-            u8 alpha = Colour::convert4To8Bit(getBits<0, 4>(texel));
-            u8 b = Colour::convert4To8Bit(getBits<4, 4>(texel));
-            u8 g = Colour::convert4To8Bit(getBits<8, 4>(texel));
-            u8 r = Colour::convert4To8Bit(getBits<12, 4>(texel));
+            u8 alpha = Colour::convert4To8Bit(getBits<0, 4, u8>(texel));
+            u8 b = Colour::convert4To8Bit(getBits<4, 4, u8>(texel));
+            u8 g = Colour::convert4To8Bit(getBits<8, 4, u8>(texel));
+            u8 r = Colour::convert4To8Bit(getBits<12, 4, u8>(texel));
 
             return (alpha << 24) | (b << 16) | (g << 8) | r;
         }
@@ -133,9 +133,9 @@ u32 Texture::decodeTexel(u32 u, u32 v, PICA::TextureFmt fmt, const void* data) {
             u16 texel = u16(ptr[offset]) | (u16(ptr[offset + 1]) << 8);
 
             u8 alpha = getBit<0>(texel) ? 0xff : 0;
-            u8 b = Colour::convert5To8Bit(getBits<1, 5>(texel));
-            u8 g = Colour::convert5To8Bit(getBits<6, 5>(texel));
-            u8 r = Colour::convert5To8Bit(getBits<11, 5>(texel));
+            u8 b = Colour::convert5To8Bit(getBits<1, 5, u8>(texel));
+            u8 g = Colour::convert5To8Bit(getBits<6, 5, u8>(texel));
+            u8 r = Colour::convert5To8Bit(getBits<11, 5, u8>(texel));
 
             return (alpha << 24) | (b << 16) | (g << 8) | r;
         }
@@ -145,9 +145,9 @@ u32 Texture::decodeTexel(u32 u, u32 v, PICA::TextureFmt fmt, const void* data) {
             auto ptr = static_cast<const u8*>(data);
             u16 texel = u16(ptr[offset]) | (u16(ptr[offset + 1]) << 8);
 
-            u8 b = Colour::convert5To8Bit(getBits<0, 5>(texel));
-            u8 g = Colour::convert6To8Bit(getBits<5, 6>(texel));
-            u8 r = Colour::convert5To8Bit(getBits<11, 5>(texel));
+            u8 b = Colour::convert5To8Bit(getBits<0, 5, u8>(texel));
+            u8 g = Colour::convert6To8Bit(getBits<5, 6, u8>(texel));
+            u8 r = Colour::convert5To8Bit(getBits<11, 5, u8>(texel));
 
             return (0xff << 24) | (b << 16) | (g << 8) | r;
         }