Compare commits

...
Author SHA1 Message Date
Stefan MaierandClaude Opus 5.5 0fc85d6c67 Steam Frame: the overlays' alpha from their colour on SteamVR
SteamVR draws a quad's texels by their alpha alone, and the game's menus,
HUD and text have none in their additive parts: on the Frame nothing showed.
On SteamVR (the runtime's name says) the copy into the quads' images takes
their alpha from their colour where it is higher; HALO_XR_QUAD_ALPHA
(colour, keep) overrides, for trying. The Frame's notes updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 20:17:43 +02:00
Stefan MaierandClaude Opus 5.5 c0a08f395e Steam Frame: the game's data in the SteamOS user's Documents when it is there
Lepton empties the app's own folders (and uninstalls the app) whenever it
starts again; Documents is the SteamOS user's and kept. When
/home/steamos/Documents/HaloCE holds the maps and is writable, the launcher
and the game take it as the data folder (maps, config.toml, saves, logs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 19:51:08 +02:00
4 changed files with 71 additions and 4 deletions

No files matched your search

+29 -4
View File
@@ -32,18 +32,43 @@ What differs is found at run time, not by a build of its own.
| # | Stage | State |
| --- | --- | --- |
| 1 | Base: the fixes above on the current main | in progress |
| 2 | The game's data where Lepton keeps it | |
| 3 | Menus, HUD and text visible (quad layers) | |
| 4 | The freeze at the cryo bay's calibration | |
| 1 | Base: the fixes above on the current main | done |
| 2 | The game's data where Lepton keeps it | done: `/home/steamos/Documents/HaloCE` |
| 3 | Menus, HUD and text visible (quad layers) | done: their alpha from their colour |
| 4 | The freeze at the cryo bay's calibration | not seen again (2026-10-04) |
| 5 | The Frame's controllers | |
| 6 | Frame rate, resolution | |
| 7 | Multiplayer, voice, cross-play with the Quest | |
| 8 | Installing it, for others | |
## The game's data
Lepton uninstalls the app and empties its folders whenever it starts again.
The game's data lives in the SteamOS user's Documents instead: when
`/home/steamos/Documents/HaloCE` holds `maps/ui.map` and is writable, the
launcher and the game take it as their data folder (config.toml, saves and
debug.txt go there too). Once:
adb -s <frame-ip>:5555 shell mkdir -p /home/steamos/Documents/HaloCE/maps
adb -s <frame-ip>:5555 push assets/maps/. /home/steamos/Documents/HaloCE/maps/
adb -s <frame-ip>:5555 shell chmod -R 777 /home/steamos/Documents/HaloCE
After a Lepton restart only the APK is installed again. (Use the path under
/home, not /sdcard/Documents: Android 11's scoped storage stands between the
app and the latter.)
## Findings
- 2026-10-02: runs flat and in VR (GLES 3.2 by Mesa zink on Turnip, eyes
1728x1728, 72 Hz, XR_FB_display_refresh_rate absent). Quad layers
(menus, HUD, instructions) are not shown; the projection layer is. Froze
at the cryo bay's look calibration; its log was lost to Lepton's wipe.
- 2026-10-04: SteamVR draws a quad's texels by their alpha alone; the
game's menus and HUD have none in their additive parts, so nothing showed.
On SteamVR (by the runtime's name) the overlays' alpha now comes from their
colour (host_xr.c; `HALO_XR_QUAD_ALPHA=colour|keep` overrides). With it,
menus, HUD and the campaign ran well (the user: "lief 1a"); no freeze.
- 2026-10-04: no online games found: the public MQTT brokers had banned the
home connection for a while (too many connections from tests that day);
broker.emqx.io came back within minutes. Lepton's network is the Frame's
own (same IP), DNS works.
@@ -35,6 +35,7 @@ import java.nio.channels.FileChannel;
*/
public class LauncherActivity extends Activity {
private static final int PICK_IMAGE = 1;
private static final String SHARED_DATA_ROOT = "/home/steamos/Documents/HaloCE";
private File dataRoot;
private TextView status;
@@ -46,6 +47,12 @@ public class LauncherActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dataRoot = getExternalFilesDir(null);
// the Steam Frame: Lepton empties the app's own folders whenever it
// starts again; the game's data lives in the SteamOS user's
// Documents instead, when it is there (port/android/STEAM_FRAME.md;
// the same choice as host_main.c's)
if (new File(SHARED_DATA_ROOT, "maps/ui.map").isFile() && new File(SHARED_DATA_ROOT).canWrite())
dataRoot = new File(SHARED_DATA_ROOT);
// created by the app, so that files pushed into it with adb stay
// readable (a directory adb creates there belongs to the shell user)
if (dataRoot != null)
+8
View File
@@ -90,6 +90,8 @@ int host_errno(void)
static char data_root[512];
static char save_root[512];
/* where a device that empties the app's folders keeps the game's data */
#define SHARED_DATA_ROOT "/home/steamos/Documents/HaloCE"
void host_android_path(int which, char *buffer, uint32_t size)
{
@@ -269,6 +271,12 @@ static void *game_main(void *unused)
external = SDL_GetAndroidExternalStoragePath();
if (!external)
host_fatal("Android storage is unavailable: %s", SDL_GetError());
/* the Steam Frame: Lepton empties the app's own folders whenever it
starts again; the game's data lives in the SteamOS user's Documents
instead, when it is there (port/android/STEAM_FRAME.md; the same choice
as LauncherActivity's) */
if (directory_has_maps(SHARED_DATA_ROOT) && access(SHARED_DATA_ROOT, W_OK) == 0)
external = SHARED_DATA_ROOT;
snprintf(data_root, sizeof(data_root), "%s", external);
snprintf(save_root, sizeof(save_root), "%s/save", external);
/* readable by adb (the shell user), for managing saves */
+27
View File
@@ -122,6 +122,11 @@ static struct
GLint rect_uniform;
GLint cut_disc_uniform;
GLint vignette_uniform;
GLint alpha_from_colour_uniform;
/* the runtime draws a quad's texels by their alpha alone, ignoring the
colour of those with none (SteamVR on the Steam Frame): the game's
overlays, whose additive parts have none, get alpha from their colour */
int quad_alpha_from_colour;
GLint tangents_uniform;
float vignette;
/* the same copy from a layer of a texture array (the eyes drawn at
@@ -223,6 +228,7 @@ static const char copy_fragment_shader[] =
"precision highp float;\n"
"uniform sampler2D source;\n"
"uniform float cut_disc;\n"
"uniform float alpha_from_colour; /* 1: as opaque as it is bright (a quad's, SteamVR) */\n"
"uniform float vignette; /* 0..1: the eye images darken from their edges */\n"
"uniform vec4 tangents; /* the eye's edges: left, right, down, up */\n"
"in vec2 coordinate;\n"
@@ -236,6 +242,8 @@ static const char copy_fragment_shader[] =
"{\n"
" vec4 texel = texture(source, coordinate);\n"
" color = vec4(to_linear(texel.rgb), texel.a);\n"
" if (alpha_from_colour > 0.5)\n"
" color.a = max(color.a, max(color.r, max(color.g, color.b)));\n"
" if (cut_disc > 0.5)\n"
" {\n"
" float inside = 1.0 - smoothstep(0.95, 1.0, length(disc));\n"
@@ -326,6 +334,7 @@ static int copy_initialize(void)
xr.rect_uniform = glGetUniformLocation(xr.program, "rect");
xr.cut_disc_uniform = glGetUniformLocation(xr.program, "cut_disc");
xr.vignette_uniform = glGetUniformLocation(xr.program, "vignette");
xr.alpha_from_colour_uniform = glGetUniformLocation(xr.program, "alpha_from_colour");
xr.tangents_uniform = glGetUniformLocation(xr.program, "tangents");
xr.copy_array_layer = -1;
{
@@ -966,6 +975,22 @@ int host_xr_probe(float resolution_scale, int *eye_width, int *eye_height)
}
xrGetSystemProperties(xr.instance, xr.system, &properties);
strncpy(xr.system_name, properties.systemName, sizeof(xr.system_name) - 1);
{
/* (SteamVR: the quads' alpha from their colour; HALO_XR_QUAD_ALPHA
"colour" or "keep" says otherwise, for trying) */
XrInstanceProperties instance = { XR_TYPE_INSTANCE_PROPERTIES };
const char *choice = getenv("HALO_XR_QUAD_ALPHA");
if (XR_SUCCEEDED(xrGetInstanceProperties(xr.instance, &instance)))
{
xr.quad_alpha_from_colour = strstr(instance.runtimeName, "SteamVR") != NULL;
host_logf(HOST_LOG_INFO, "xr: runtime %s", instance.runtimeName);
}
if (choice)
xr.quad_alpha_from_colour = !strcmp(choice, "colour");
if (xr.quad_alpha_from_colour)
host_logf(HOST_LOG_INFO, "xr: the overlays' alpha from their colour");
}
views[0].type = views[1].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
views[0].next = views[1].next = NULL;
@@ -1322,6 +1347,8 @@ int host_xr_copy_layer_region(int layer, uint32_t texture, int clear_alpha, floa
glUniform1i(xr.source_uniform, 0);
glUniform4f(xr.rect_uniform, left, top, right, bottom);
glUniform1f(xr.cut_disc_uniform, clear_alpha == HALO_XR_COPY_DISC ? 1.0f : 0.0f);
glUniform1f(xr.alpha_from_colour_uniform, xr.quad_alpha_from_colour && clear_alpha == HALO_XR_COPY_ALPHA &&
layer != HALO_XR_LAYER_EYE_LEFT && layer != HALO_XR_LAYER_EYE_RIGHT ? 1.0f : 0.0f);
if ((layer == HALO_XR_LAYER_EYE_LEFT || layer == HALO_XR_LAYER_EYE_RIGHT) && xr.vignette > 0.001f)
{
const XrFovf *fov = &xr.views[layer - HALO_XR_LAYER_EYE_LEFT].fov;