Compare commits

...

2 Commits

Author SHA1 Message Date
238343b5e8 Fix -Wformat-truncation warning in window title formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 10:28:26 +01:00
7e67589150 Embed controls.png into binary so it can run from any directory
The spritesheet is compiled in as a C byte array. An external
controls.png in cwd still takes precedence for skinning. Includes
tools/embed_png.py to regenerate the header if the asset changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 10:25:22 +01:00
5 changed files with 2169 additions and 4 deletions

View File

@ -15,16 +15,16 @@ See `docs/sdlamp2-fsd.md` for the full functional specification and changelog.
```sh ```sh
./build.sh # macOS — builds to build/sdlamp2 ./build.sh # macOS — builds to build/sdlamp2
./build_aarch64.sh # Linux aarch64 variant ./build_aarch64.sh # Linux aarch64 variant
cd build && ./sdlamp2 [audio_directory] ./build/sdlamp2 [audio_directory]
``` ```
The binary must be run from `build/` because it loads `controls.png` from the current working directory. Audio directory defaults to cwd if not specified. The controls spritesheet (`controls.png`) is embedded in the binary. If an external `controls.png` exists in the current working directory it takes precedence, allowing custom skins. Audio directory defaults to cwd if not specified.
No test suite, no linter, no Makefile/CMake. No test suite, no linter, no Makefile/CMake.
## Architecture ## Architecture
Single-file C program: `src/sdlamp2.c` (~650 lines). No headers, no separate compilation units. Single-file C program: `src/sdlamp2.c` (~650 lines). One generated header: `src/controls_png.h` (embedded PNG byte array — regenerate with `./tools/embed_png.py build/controls.png src/controls_png.h` if the spritesheet changes).
Key sections in order: Key sections in order:
- **Decoder struct** — holds all FFmpeg state (format/codec contexts, swr resampler, album art texture) - **Decoder struct** — holds all FFmpeg state (format/codec contexts, swr resampler, album art texture)

View File

@ -43,6 +43,11 @@ This document specifies the functional requirements for an SDL2 based media play
## 6. Changelog ## 6. Changelog
### 2026-02-13 — Embed controls spritesheet into binary
- **Embedded asset**: `controls.png` is now compiled into the binary as a C byte array (`src/controls_png.h`), eliminating the requirement to run from the `build/` directory.
- **External override**: If a `controls.png` file exists in the current working directory, it is loaded in preference to the embedded data, preserving the ability to use custom skins.
### 2026-02-11 — Debug flag for input diagnostics ### 2026-02-11 — Debug flag for input diagnostics
- **`--debug` flag**: New command-line option (`./sdlamp2 --debug [audio_dir]`) that enables verbose logging of all SDL input events to stdout. Designed to diagnose controller issues on retro handheld devices where non-standard controllers may not be recognized by SDL's GameController API. - **`--debug` flag**: New command-line option (`./sdlamp2 --debug [audio_dir]`) that enables verbose logging of all SDL input events to stdout. Designed to diagnose controller issues on retro handheld devices where non-standard controllers may not be recognized by SDL's GameController API.

2123
src/controls_png.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,8 @@
#include "SDL.h" #include "SDL.h"
#include "SDL_image.h" #include "SDL_image.h"
#include "controls_png.h"
#define MAX_FILES 64 #define MAX_FILES 64
#define SEEK_SECONDS 10.0 #define SEEK_SECONDS 10.0
@ -473,7 +475,7 @@ static void switch_file(int index) {
decoder_seek(pos); decoder_seek(pos);
} }
char title[256]; char title[768];
snprintf(title, sizeof(title), "SDLamp2 - %s", current_file); snprintf(title, sizeof(title), "SDLamp2 - %s", current_file);
SDL_SetWindowTitle(window, title); SDL_SetWindowTitle(window, title);
@ -626,6 +628,12 @@ int main(int argc, char** argv) {
} }
SDL_Surface* controls_surface = IMG_Load("controls.png"); SDL_Surface* controls_surface = IMG_Load("controls.png");
if (!controls_surface) {
SDL_RWops* rw = SDL_RWFromConstMem(controls_png_data, controls_png_size);
if (rw) {
controls_surface = IMG_Load_RW(rw, 1);
}
}
if (!controls_surface) { if (!controls_surface) {
panic_and_abort("Could not load controls asset!", SDL_GetError()); panic_and_abort("Could not load controls asset!", SDL_GetError());
} }

29
tools/embed_png.py Executable file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env python3
#
# embed_png.py — Convert a PNG file into a C header with a byte array.
#
# Usage: ./tools/embed_png.py build/controls.png src/controls_png.h
#
import sys
import os
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <input.png> <output.h>", file=sys.stderr)
sys.exit(1)
input_path = sys.argv[1]
output_path = sys.argv[2]
data = open(input_path, "rb").read()
with open(output_path, "w") as out:
out.write("/* Auto-generated from controls.png — do not edit */\n\n")
out.write("static const unsigned char controls_png_data[] = {\n")
for i in range(0, len(data), 16):
chunk = data[i : i + 16]
out.write(" " + ", ".join(f"0x{b:02x}" for b in chunk) + ",\n")
out.write("};\n\n")
out.write(f"static const unsigned int controls_png_size = {len(data)};\n")
print(f"{input_path} -> {output_path} ({len(data)} bytes)")