Files
m3te/vendors/file_utils/file_utils.c
swipelab c5ed5cc4f7 P4.3: render seeded board with real gem sprites (sx, iOS sim)
Adopt the modules/ui UIPipeline framework (as the chess reference app does)
and replace the P0 placeholder quad with a BoardView (View protocol, modeled
on chess/board_view.sx):
- background.png fills the screen; an 8x8 cell.png grid is centered in the
  safe area; each cell's gem is sampled from gems.png by UV column = gem index
  (0=red .. 5=purple).
- Drive it from board.sx seeded with 1337 (the board_init golden's seed), so
  the on-screen layout matches that snapshot gem-for-gem.

main.sx now hosts the view via UIPipeline (Metal on iOS, GL on desktop) and
heap-allocates the board/asset state behind pointers (UFCS method calls on a
value-typed global mutate a copy, so mutable state must live behind a pointer
as the reference app does).

Vendor the C deps the UI module's image/font path needs (stb_image,
stb_truetype, kb_text_shape, file_utils); their #include "vendors/..." paths
resolve relative to the project root.

Evidence: ios-sim build links clean; tools/run_tests.sh 11/11 pass; running
app captured at goldens/p4_board.png.
2026-06-04 23:34:05 +03:00

56 lines
1.9 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __ANDROID__
#include <android/asset_manager.h>
// Caller-installed AAssetManager pointer. Chess's android_main extracts
// it from `app->activity->assetManager` (via sx-side platform module's
// `g_android_asset_manager` global) and feeds it here once at startup.
// Until the setter has been called, Android falls through to fopen —
// gives a predictable "file not found" rather than a NULL-deref.
static AAssetManager* g_aam = NULL;
void sx_android_set_asset_manager(void* m) {
g_aam = (AAssetManager*)m;
}
#endif
unsigned char* read_file_bytes(const char* path, int* out_size) {
#ifdef __ANDROID__
if (g_aam != NULL) {
// AAssetManager paths are relative to the APK's `assets/`
// directory. Strip a leading "assets/" so callers can use the
// same paths across iOS/macOS/Android (those platforms read
// assets via `assets/...` rooted in the bundle or CWD).
const char* lookup = path;
if (strncmp(path, "assets/", 7) == 0) {
lookup = path + 7;
}
AAsset* a = AAssetManager_open(g_aam, lookup, AASSET_MODE_BUFFER);
if (a != NULL) {
off_t n = AAsset_getLength(a);
*out_size = (int)n;
unsigned char* buf = (unsigned char*)malloc((size_t)n);
if (buf != NULL) {
memcpy(buf, AAsset_getBuffer(a), (size_t)n);
}
AAsset_close(a);
return buf;
}
// Falls through to fopen — useful when assets land in the data
// dir via extraction or app updates.
}
#endif
FILE* f = fopen(path, "rb");
if (!f) return 0;
fseek(f, 0, SEEK_END);
*out_size = (int)ftell(f);
fseek(f, 0, SEEK_SET);
unsigned char* buf = (unsigned char*)malloc(*out_size);
fread(buf, 1, *out_size, f);
fclose(f);
return buf;
}