SDL: cmake: convert bmp images to c headers using python script

From 80da0cf06dd7c83d37dca601f272aadcd4144dc8 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Sun, 16 Jul 2023 15:50:32 +0200
Subject: [PATCH] cmake: convert bmp images to c headers using python script

A pure CMake script was too slow
---
 cmake/xxd.py        | 37 +++++++++++++++++++++++++++++++++++++
 test/CMakeLists.txt | 40 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 76 insertions(+), 1 deletion(-)
 create mode 100755 cmake/xxd.py

diff --git a/cmake/xxd.py b/cmake/xxd.py
new file mode 100755
index 000000000000..27afbcd383ad
--- /dev/null
+++ b/cmake/xxd.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+import argparse
+import os
+import pathlib
+import re
+
+def main():
+    parser = argparse.ArgumentParser(allow_abbrev=False, description="Convert file into includable C header")
+    parser.add_argument("--in", "-i", type=pathlib.Path, metavar="INPUT", dest="input", required=True, help="Input file")
+    parser.add_argument("--out", "-o", type=pathlib.Path, metavar="OUTPUT", dest="output", required=True, help="Output header")
+    parser.add_argument("--columns", type=int, default=12, help="Column count")
+    args = parser.parse_args()
+
+    t = pathlib.Path()
+    varname, _ = re.subn("[^a-zA-Z0-9]", "_", str(args.input.name))
+
+    binary_data = args.input.open("rb").read()
+
+    with open(args.output, "w") as fout:
+        fout.write("unsigned char {}[] = {{\n".format(varname))
+        bytes_written = 0
+        while bytes_written < len(binary_data):
+            col = bytes_written % args.columns
+            if col == 0:
+                fout.write("  ")
+            column_data = binary_data[bytes_written:bytes_written+args.columns]
+            fout.write(", ".join("0x{:02x}".format(d) for d in column_data))
+            bytes_written += len(column_data)
+            if bytes_written < len(binary_data):
+                fout.write(",\n")
+            else:
+                fout.write("\n")
+        fout.write("}};\nunsigned int {}_len = {:d};\n".format(varname, len(binary_data)))
+
+if __name__ == "__main__":
+    raise SystemExit(main())
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index a6dfdb35f36c..f05bf4ea5bac 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -208,8 +208,46 @@ if(SDL3_TESTS_SUBPROJECT)
     endforeach()
 endif()
 
+set(gamepad_images
+    gamepad_axis_arrow.bmp
+    gamepad_axis.bmp
+    gamepad_back.bmp
+    gamepad_battery_empty.bmp
+    gamepad_battery_full.bmp
+    gamepad_battery_low.bmp
+    gamepad_battery_medium.bmp
+    gamepad_battery_unknown.bmp
+    gamepad_battery_wired.bmp
+    gamepad_button_background.bmp
+    gamepad_button.bmp
+    gamepad_button_small.bmp
+    gamepad_face_abxy.bmp
+    gamepad_face_bayx.bmp
+    gamepad_face_sony.bmp
+    gamepad_front.bmp
+    gamepad_touchpad.bmp
+)
+set(gamepad_image_headers)
+find_package(PythonInterp)
+if(PYTHONINTERP_FOUND AND NOT PYTHON_VERSION_STRING VERSION_LESS "3.2")
+    set(xxd "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/xxd.py")
+    foreach(bmp ${gamepad_images})
+        get_filename_component(bmp_we "${bmp}" NAME_WE)
+        set(intermediate "${CMAKE_CURRENT_BINARY_DIR}/${bmp_we}.h")
+        set(final "${CMAKE_CURRENT_SOURCE_DIR}/${bmp_we}.h")
+        # Don't add the 'final' headers to the output, to avoid marking them as GENERATED
+        # (generated files are removed when running the CLEAN target)
+        add_custom_command(OUTPUT "${intermediate}"
+            COMMAND "${PYTHON_EXECUTABLE}" "${xxd}" -i "${CMAKE_CURRENT_SOURCE_DIR}/${bmp}" "-o" "${intermediate}"
+            COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${intermediate}" "${final}"
+            DEPENDS "${xxd}" "${bmp}"
+        )
+        list(APPEND gamepad_image_headers "${intermediate}" "${final}")
+    endforeach()
+endif()
+
 add_sdl_test_executable(testfile NONINTERACTIVE SOURCES testfile.c)
-add_sdl_test_executable(testcontroller TESTUTILS SOURCES testcontroller.c gamepadutils.c)
+add_sdl_test_executable(testcontroller TESTUTILS SOURCES testcontroller.c gamepadutils.c ${gamepad_image_headers})
 add_sdl_test_executable(testgeometry TESTUTILS SOURCES testgeometry.c)
 add_sdl_test_executable(testgl SOURCES testgl.c)
 add_sdl_test_executable(testgles SOURCES testgles.c)