Compare commits

..
Author SHA1 Message Date
Stefan MaierandClaude Opus 5.5 b0d454ae9b Keep the new settings out of the network table
The settings file is written in the table's order, so settings of another
section between network.* entries wrote [network] twice, and the whole
file was then refused (defaults used). They now follow the network
settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 17:52:12 +02:00
686 changed files with 443 additions and 65583 deletions

No files matched your search

+4 -1
View File
@@ -242,7 +242,10 @@ jobs:
mkdir release
for build in artifacts/*/; do
name="$(basename "$build")"
(cd "$build" && zip -qr "$GITHUB_WORKSPACE/release/$name.zip" .)
# stored, not deflated: the updater in builds up to 57 waits for
# an end of stream the game's zlib 1.1 does not always report,
# and fails on a deflated entry that unpacked correctly
(cd "$build" && zip -0 -qr "$GITHUB_WORKSPACE/release/$name.zip" .)
done
ls -l release
-2
View File
@@ -24,8 +24,6 @@ xbox/
# Locally extracted proprietary game data (never commit)
assets/
# (but the high-res assets, drawn for the port: tools/hud_assets.py)
!port/assets/
original/
# CI build outputs (tools/ci_build.py)
+1 -2
View File
@@ -168,8 +168,7 @@ the Xbox:
- The HUD stays at the edges of the screen.
- The menus, the loading bar and the screens after a game have 640
columns, at the center of the screen.
- Black bars and fades cover all of the screen, and so do the menus' dims
and backgrounds (the pause menu's dim, dialogs, the menus' gradient).
- Black bars and fades cover all of the screen.
## VR
-95
View File
@@ -1,95 +0,0 @@
# Steam Frame
The same APK as for the Quest runs on the Steam Frame, in Lepton (SteamOS's
Android, a Waydroid fork: Android 11, arm64), with SteamVR's OpenXR runtime.
What differs is found at run time, not by a build of its own.
## The device
- Steam Settings > System > Enable Developer Mode; then start "Lepton
Development" from the library. While the headset sleeps Lepton stops, and
adb with it.
- adb over the network: `adb connect <frame-ip>:5555`; over USB:
`adb forward tcp:5555 tcp:5555` then `adb connect localhost:5555`.
Always name the device (`adb -s <frame-ip>:5555 ...`): a Quest may be
connected as well.
- Install with `adb install -r --no-streaming`. It prints "Lepton post
installation failed due to APP_PATH being unset", but installs. Start the
game with `am start -n com.halo.decomp/.LauncherActivity`.
- Lepton empties `/sdcard/Android/data` whenever it starts again: the game's
data must live elsewhere (stage 2). `/sdcard/Documents` and
`/sdcard/Download` are the SteamOS user's folders and are kept.
## What the port does for it
- SDL3's clipboard handler takes a clipboard service for granted, which
Lepton has not: `tools/android_build.py` patches it to do without.
- SteamVR lists an implicit OpenXR layer for Vulkan apps whose library an
app cannot load: the APK carries a pass-through layer under its name
(`port/android/xr_layer/fdm_injection_stub.c`).
## Stages
| # | Stage | State |
| --- | --- | --- |
| 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 | done: their own profile, the Xbox's layout |
| 6 | Frame rate, resolution | done: 72 Hz steady, multiview on |
| 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.)
## The controllers
SteamVR offers the Frame's controllers as themselves
(`XR_VALVE_frame_controller_interaction`,
`/interaction_profiles/valve/frame_controller_valve`; Valve's "Steam Frame
Input" page). Without bindings for it, SteamVR maps the Quest's onto them,
and the left Touch controller's X and Y land on the D-pad. With them the
game gets the Xbox's layout, as the right controller has it: A jump, B
flashlight (held: switch grenades), X action and reload, Y switch weapon,
menu pause; the left one's View is Back (scores), its D-pad the D-pad, the
bumpers switch grenades (left) and the flashlight (right). The VR options'
page of buttons shows this layout on the Frame.
## 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.
- 2026-10-04: the refresh rate is SteamOS's setting; the runtime offers
only that one (the game asks for the highest at or below
`vr.refresh_rate`, and logs the rates offered). At 72 Hz the game holds
72 fps (about 11.6 ms a frame with multiview, eyes 7.6 ms; without it
eyes about 9 ms). At 90 Hz it cannot (11.1 ms a frame), and SteamVR's
making up of the missed frames showed as a doubled picture when turning
the head. Keep the Frame at 72 Hz, or lower `vr.resolution_scale` (about
0.85) for 90.
@@ -39,7 +39,6 @@ import java.nio.channels.FileChannel;
public class LauncherActivity extends Activity {
private static final int PICK_IMAGE = 1;
private static final int ASK_MICROPHONE = 2;
private static final String SHARED_DATA_ROOT = "/home/steamos/Documents/HaloCE";
private File dataRoot;
private TextView status;
@@ -51,12 +50,6 @@ 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)
-3
View File
@@ -68,9 +68,6 @@ int host_sdl_gl_swap_window(unsigned int window);
int host_sdl_poll_event(void *event);
int host_sdl_set_clipboard_text(const char *text);
void host_sdl_get_clipboard_text(char *buffer, unsigned int size);
/* the keyboard's keys by name (the controls' bindings, xinput_sdl.c) */
void host_sdl_scancode_name(int scancode, char *buffer, unsigned int size);
int host_sdl_scancode_from_name(const char *name);
int host_sdl_show_toast(const char *message, int duration, int gravity, int x, int y);
int host_sdl_show_simple_message_box(unsigned int flags, const char *title, const char *message);
int host_sdl_get_gamepads(unsigned int *ids, int capacity);
-13
View File
@@ -39,19 +39,6 @@ const char *SDL_GetError(void)
return buffer;
}
const char *SDL_GetScancodeName(SDL_Scancode scancode)
{
static __thread char buffer[64];
host_sdl_scancode_name((int)scancode, buffer, sizeof(buffer));
return buffer;
}
SDL_Scancode SDL_GetScancodeFromName(const char *name)
{
return (SDL_Scancode)host_sdl_scancode_from_name(name);
}
Uint64 SDL_GetTicks(void)
{
return (Uint64)host_sdl_ticks();
-8
View File
@@ -90,8 +90,6 @@ 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)
{
@@ -271,12 +269,6 @@ 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 */
-10
View File
@@ -98,16 +98,6 @@ void host_sdl_get_error(char *buffer, uint32_t size)
SDL_strlcpy(buffer, SDL_GetError(), size);
}
void host_sdl_scancode_name(int32_t scancode, char *buffer, uint32_t size)
{
SDL_strlcpy(buffer, SDL_GetScancodeName((SDL_Scancode)scancode), size);
}
int32_t host_sdl_scancode_from_name(const char *name)
{
return (int32_t)SDL_GetScancodeFromName(name);
}
int64_t host_sdl_ticks(void)
{
return (int64_t)SDL_GetTicks();
+3 -207
View File
@@ -102,14 +102,6 @@ static struct
XrAction button_b; /* B on the right controller, Y on the left */
XrAction menu;
XrAction thumbrest;
/* the Steam Frame's controllers' own (XR_VALVE_frame_controller_interaction) */
int has_frame_controller;
int frame_layout;
XrAction button_x;
XrAction button_y;
XrAction view;
XrAction bumper;
XrAction dpad[4];
XrAction haptic;
struct xr_hand_actions hands[HALO_XR_HAND_COUNT];
@@ -130,11 +122,6 @@ 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
@@ -236,7 +223,6 @@ 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"
@@ -250,8 +236,6 @@ 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"
@@ -342,7 +326,6 @@ 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;
{
@@ -597,14 +580,6 @@ static int actions_initialize(void)
xr.button_b = action_create("button_upper", "B / Y", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.menu = action_create("menu", "Menu", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.thumbrest = action_create("thumbrest", "Thumb rest", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.button_x = action_create("button_x", "X", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.button_y = action_create("button_y", "Y", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.view = action_create("view", "View", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.bumper = action_create("bumper", "Bumper", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.dpad[0] = action_create("dpad_up", "D-pad up", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.dpad[1] = action_create("dpad_down", "D-pad down", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.dpad[2] = action_create("dpad_left", "D-pad left", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.dpad[3] = action_create("dpad_right", "D-pad right", XR_ACTION_TYPE_BOOLEAN_INPUT);
xr.haptic = action_create("haptic", "Rumble", XR_ACTION_TYPE_VIBRATION_OUTPUT);
{
@@ -669,44 +644,6 @@ static int actions_initialize(void)
{ &xr.haptic, "/user/hand/right/output/haptic" },
};
/* the Steam Frame's controllers, as themselves: the right one has
A, B, X, Y and a menu button, the left one a D-pad and a View button
(port/android/STEAM_FRAME.md) */
static const struct binding frame_controller[] =
{
{ &xr.grip_pose, "/user/hand/left/input/grip/pose" },
{ &xr.grip_pose, "/user/hand/right/input/grip/pose" },
{ &xr.aim_pose, "/user/hand/left/input/aim/pose" },
{ &xr.aim_pose, "/user/hand/right/input/aim/pose" },
{ &xr.trigger, "/user/hand/left/input/trigger/value" },
{ &xr.trigger, "/user/hand/right/input/trigger/value" },
{ &xr.squeeze, "/user/hand/left/input/squeeze/value" },
{ &xr.squeeze, "/user/hand/right/input/squeeze/value" },
{ &xr.thumbstick, "/user/hand/left/input/thumbstick" },
{ &xr.thumbstick, "/user/hand/right/input/thumbstick" },
{ &xr.thumbstick_click, "/user/hand/left/input/thumbstick/click" },
{ &xr.thumbstick_click, "/user/hand/right/input/thumbstick/click" },
{ &xr.button_a, "/user/hand/right/input/a/click" },
{ &xr.button_b, "/user/hand/right/input/b/click" },
{ &xr.button_x, "/user/hand/right/input/x/click" },
{ &xr.button_y, "/user/hand/right/input/y/click" },
{ &xr.menu, "/user/hand/right/input/menu/click" },
{ &xr.view, "/user/hand/left/input/view/click" },
{ &xr.bumper, "/user/hand/left/input/bumper/click" },
{ &xr.bumper, "/user/hand/right/input/bumper/click" },
{ &xr.dpad[0], "/user/hand/left/input/dpad_up/click" },
{ &xr.dpad[1], "/user/hand/left/input/dpad_down/click" },
{ &xr.dpad[2], "/user/hand/left/input/dpad_left/click" },
{ &xr.dpad[3], "/user/hand/left/input/dpad_right/click" },
{ &xr.haptic, "/user/hand/left/output/haptic" },
{ &xr.haptic, "/user/hand/right/output/haptic" },
};
if (xr.has_frame_controller)
{
suggest("/interaction_profiles/valve/frame_controller_valve", frame_controller,
sizeof(frame_controller) / sizeof(frame_controller[0]));
}
suggest("/interaction_profiles/oculus/touch_controller", touch, sizeof(touch) / sizeof(touch[0]));
suggest("/interaction_profiles/valve/index_controller", index, sizeof(index) / sizeof(index[0]));
suggest("/interaction_profiles/khr/simple_controller", simple, sizeof(simple) / sizeof(simple[0]));
@@ -776,30 +713,6 @@ static void hands_read(struct halo_xr_frame *frame)
sync.activeActionSets = &active;
if (!XR_SUCCEEDED(xrSyncActions(xr.session, &sync)))
return;
{
/* (the controllers' profile the runtime chose, in the log as it
changes) */
static XrPath logged[HALO_XR_HAND_COUNT];
for (hand = 0; hand < HALO_XR_HAND_COUNT; hand++)
{
XrInteractionProfileState state = { XR_TYPE_INTERACTION_PROFILE_STATE };
if (XR_SUCCEEDED(xrGetCurrentInteractionProfile(xr.session, xr.hands[hand].path, &state)) &&
state.interactionProfile != logged[hand])
{
char name[XR_MAX_PATH_LENGTH] = "none";
uint32_t length = 0;
logged[hand] = state.interactionProfile;
if (state.interactionProfile != XR_NULL_PATH)
xrPathToString(xr.instance, state.interactionProfile, sizeof(name), &length, name);
if (hand == HALO_XR_HAND_RIGHT)
xr.frame_layout = strstr(name, "frame_controller") != NULL;
host_logf(HOST_LOG_INFO, "xr: the %s hand's controller: %s", hand ? "right" : "left", name);
}
}
}
for (hand = 0; hand < HALO_XR_HAND_COUNT; hand++)
{
struct halo_xr_hand *out = &frame->hands[hand];
@@ -844,31 +757,7 @@ static void hands_read(struct halo_xr_frame *frame)
(action_boolean(xr.menu, hand) ? HALO_XR_BUTTON_MENU : 0) |
(action_boolean(xr.thumbrest, hand) ? HALO_XR_BUTTON_THUMBREST : 0) |
(out->trigger > 0.5f ? HALO_XR_BUTTON_TRIGGER : 0) |
(out->squeeze > 0.5f ? HALO_XR_BUTTON_SQUEEZE : 0) |
(action_boolean(xr.view, hand) ? HALO_XR_BUTTON_VIEW : 0) |
(action_boolean(xr.bumper, hand) ? HALO_XR_BUTTON_BUMPER : 0) |
(action_boolean(xr.dpad[0], hand) ? HALO_XR_BUTTON_DPAD_UP : 0) |
(action_boolean(xr.dpad[1], hand) ? HALO_XR_BUTTON_DPAD_DOWN : 0) |
(action_boolean(xr.dpad[2], hand) ? HALO_XR_BUTTON_DPAD_LEFT : 0) |
(action_boolean(xr.dpad[3], hand) ? HALO_XR_BUTTON_DPAD_RIGHT : 0);
}
frame->controller_layout = xr.frame_layout ? HALO_XR_LAYOUT_FRAME : HALO_XR_LAYOUT_TOUCH;
if (xr.frame_layout)
{
/* (the Frame's right X, Y and menu button: the game's X, Y and Start,
which the Quest has on the left) */
struct halo_xr_hand *left = &frame->hands[HALO_XR_HAND_LEFT];
struct halo_xr_hand *right = &frame->hands[HALO_XR_HAND_RIGHT];
if (action_boolean(xr.button_x, HALO_XR_HAND_RIGHT))
left->buttons |= HALO_XR_BUTTON_A;
if (action_boolean(xr.button_y, HALO_XR_HAND_RIGHT))
left->buttons |= HALO_XR_BUTTON_B;
if (right->buttons & HALO_XR_BUTTON_MENU)
{
right->buttons &= ~HALO_XR_BUTTON_MENU;
left->buttons |= HALO_XR_BUTTON_MENU;
}
(out->squeeze > 0.5f ? HALO_XR_BUTTON_SQUEEZE : 0);
}
}
@@ -885,13 +774,6 @@ static void refresh_rate_choose(float wanted)
{
return;
}
{
char line[128] = "";
for (index = 0; index < count; index++)
snprintf(line + strlen(line), sizeof(line) - strlen(line), " %.0f", rates[index]);
host_logf(HOST_LOG_INFO, "xr: refresh rates offered:%s Hz", line);
}
/* the highest rate not above the one wanted (0: the highest) */
for (index = 0; index < count; index++)
{
@@ -912,12 +794,6 @@ the eyes reads it. Shown only while it is. */
#define WRIST_IMAGE_SIZE 512
#define CROSSHAIR_IMAGE_SIZE 256
/* the names layer: HALO_XR_MAXIMUM_NAMES slots of 4:1, one over another */
#define NAMES_IMAGE_WIDTH 512
#define NAMES_IMAGE_HEIGHT (NAMES_IMAGE_WIDTH / 4 * HALO_XR_MAXIMUM_NAMES)
/* a name's slot, as the game draws it: wider than its image's 4:1 (the
game's 640x480 drawn square): the height a slot shows at, to its width */
#define NAME_SLOT_ASPECT (30.0f / 160.0f)
#define WRIST_BEHIND_PALM 0.05f
#define WRIST_DOWN_HANDLE 0.02f
#define WRIST_ABOVE_HAND 0.04f
@@ -1013,12 +889,6 @@ int host_xr_probe(float resolution_scale, int *eye_width, int *eye_height)
/* the loader and the runtime keep the activity */
activity = (*environment)->NewGlobalRef(environment, activity);
/* (The Steam Frame lists an implicit API layer of its own for Vulkan
apps, XR_APILAYER_VALVE_fdm_injection, whose library an app cannot load
from its namespace, failing xrCreateInstance; the Android loader reads
no variable to turn it off, so the app carries a pass-through layer
under that library's name: port/android/xr_layer/fdm_injection_stub.c) */
if (!XR_SUCCEEDED(xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR",
(PFN_xrVoidFunction *)&initialize_loader)) || !initialize_loader)
{
@@ -1046,23 +916,6 @@ int host_xr_probe(float resolution_scale, int *eye_width, int *eye_height)
extensions[index].next = NULL;
}
xrEnumerateInstanceExtensionProperties(NULL, extension_count, &extension_count, extensions);
{
/* (the runtime's extensions, in the log: what a headset offers) */
char line[512] = "";
for (index = 0; index < extension_count; index++)
{
if (strlen(line) + strlen(extensions[index].extensionName) + 2 >= sizeof(line))
{
host_logf(HOST_LOG_INFO, "xr: extensions %s", line);
line[0] = 0;
}
strcat(line, " ");
strcat(line, extensions[index].extensionName);
}
if (line[0])
host_logf(HOST_LOG_INFO, "xr: extensions %s", line);
}
if (!has_extension(extensions, extension_count, XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME))
{
host_logf(HOST_LOG_ERROR, "xr: the runtime has no OpenGL ES support");
@@ -1074,9 +927,6 @@ int host_xr_probe(float resolution_scale, int *eye_width, int *eye_height)
xr.has_performance_settings = has_extension(extensions, extension_count, XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME);
if (xr.has_performance_settings)
enabled[enabled_count++] = XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME;
xr.has_frame_controller = has_extension(extensions, extension_count, "XR_VALVE_frame_controller_interaction");
if (xr.has_frame_controller)
enabled[enabled_count++] = "XR_VALVE_frame_controller_interaction";
xr.has_refresh_rate = has_extension(extensions, extension_count, XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME);
if (xr.has_refresh_rate)
enabled[enabled_count++] = XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME;
@@ -1104,22 +954,6 @@ 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;
@@ -1198,15 +1032,8 @@ int host_xr_initialize(struct halo_xr_info *info, float wanted_refresh_rate)
{
int size = layer == HALO_XR_LAYER_WRIST || layer == HALO_XR_LAYER_SCOPE ? WRIST_IMAGE_SIZE :
layer == HALO_XR_LAYER_CROSSHAIR ? CROSSHAIR_IMAGE_SIZE : 0;
int width = size ? size : xr.eye_width;
int height = size ? size : xr.eye_height;
if (layer == HALO_XR_LAYER_NAMES)
{
width = NAMES_IMAGE_WIDTH;
height = NAMES_IMAGE_HEIGHT;
}
if (!swapchain_create(&xr.swapchains[layer], width, height))
if (!swapchain_create(&xr.swapchains[layer], size ? size : xr.eye_width, size ? size : xr.eye_height))
return 0;
}
if (!copy_initialize() || !actions_initialize())
@@ -1476,8 +1303,6 @@ 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;
@@ -1529,8 +1354,7 @@ int host_xr_end_frame(const struct halo_xr_submit *submit)
XrCompositionLayerQuad wrist = { XR_TYPE_COMPOSITION_LAYER_QUAD };
XrCompositionLayerQuad scope = { XR_TYPE_COMPOSITION_LAYER_QUAD };
XrCompositionLayerQuad crosshair = { XR_TYPE_COMPOSITION_LAYER_QUAD };
XrCompositionLayerQuad names[HALO_XR_MAXIMUM_NAMES];
const XrCompositionLayerBaseHeader *layers[5 + HALO_XR_MAXIMUM_NAMES];
const XrCompositionLayerBaseHeader *layers[5];
uint32_t layer_count = 0;
int eye;
@@ -1634,34 +1458,6 @@ int host_xr_end_frame(const struct halo_xr_submit *submit)
layers[layer_count++] = (const XrCompositionLayerBaseHeader *)&crosshair;
}
if (xr.frame_state.shouldRender && submit->name_count > 0 && xr.swapchains[HALO_XR_LAYER_NAMES].filled)
{
struct xr_swapchain *swapchain = &xr.swapchains[HALO_XR_LAYER_NAMES];
int slot_height = swapchain->height / HALO_XR_MAXIMUM_NAMES;
int name;
for (name = 0; name < submit->name_count && name < HALO_XR_MAXIMUM_NAMES; name++)
{
XrCompositionLayerQuad *quad_name = &names[name];
memset(quad_name, 0, sizeof(*quad_name));
quad_name->type = XR_TYPE_COMPOSITION_LAYER_QUAD;
quad_name->layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
quad_name->space = xr.local_space;
quad_name->eyeVisibility = XR_EYE_VISIBILITY_BOTH;
quad_name->subImage.swapchain = swapchain->handle;
/* (slot 0 at the image's top: GL's rows run bottom up) */
quad_name->subImage.imageRect.offset.x = 0;
quad_name->subImage.imageRect.offset.y = swapchain->height - (name + 1) * slot_height;
quad_name->subImage.imageRect.extent.width = swapchain->width;
quad_name->subImage.imageRect.extent.height = slot_height;
quad_name->size.width = submit->name_widths[name];
quad_name->size.height = submit->name_widths[name] * NAME_SLOT_ASPECT;
pose_to_xr(&quad_name->pose, &submit->name_poses[name]);
layers[layer_count++] = (const XrCompositionLayerBaseHeader *)quad_name;
}
}
end.displayTime = xr.frame_state.predictedDisplayTime;
end.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
end.layerCount = layer_count;
-2
View File
@@ -38,8 +38,6 @@ host_sdl_gamepad_axis
host_sdl_gamepad_button
host_sdl_gamepad_type
host_sdl_rumble_gamepad
host_sdl_scancode_name
host_sdl_scancode_from_name
host_sdl_open_audio_stream
host_sdl_put_audio_stream_data
host_sdl_resume_audio_stream_device
+1 -28
View File
@@ -27,10 +27,7 @@ enum
HALO_XR_LAYER_WRIST = 3, /* the motion tracker, on the left wrist */
HALO_XR_LAYER_SCOPE = 4, /* the zoomed view, a disc over the weapon */
HALO_XR_LAYER_CROSSHAIR = 5, /* the weapon's crosshair, where it aims */
HALO_XR_LAYER_NAMES = 6, /* players' names, each a quad over a head */
HALO_XR_LAYER_COUNT = 7,
/* the names layer's slots, one a name, stacked from its top */
HALO_XR_MAXIMUM_NAMES = 8,
HALO_XR_LAYER_COUNT = 6,
/* host_xr_copy_layer's clear_alpha: the source's alpha kept, made
opaque, or cut to a disc (premultiplied) */
@@ -53,23 +50,6 @@ enum
HALO_XR_BUTTON_TRIGGER = 1 << 4, /* trigger past its click point */
HALO_XR_BUTTON_SQUEEZE = 1 << 5, /* grip past its click point */
HALO_XR_BUTTON_THUMBREST = 1 << 6, /* thumb resting (touch) */
/* the Steam Frame's controllers' (HALO_XR_LAYOUT_FRAME): the left one's
View button and D-pad, either one's bumper (their right one's X, Y and
menu button come as the left hand's A, B and MENU: the game's X, Y and
Start, as on the Quest) */
HALO_XR_BUTTON_VIEW = 1 << 7,
HALO_XR_BUTTON_BUMPER = 1 << 8,
HALO_XR_BUTTON_DPAD_UP = 1 << 9,
HALO_XR_BUTTON_DPAD_DOWN = 1 << 10,
HALO_XR_BUTTON_DPAD_LEFT = 1 << 11,
HALO_XR_BUTTON_DPAD_RIGHT = 1 << 12,
};
/* the controllers' layout, for what the game tells the player */
enum
{
HALO_XR_LAYOUT_TOUCH = 0, /* the Quest's: X, Y and menu on the left */
HALO_XR_LAYOUT_FRAME = 1, /* the Steam Frame's: A, B, X, Y and menu on the right, a D-pad on the left */
};
/* halo_xr_hand.flags, halo_xr_view.flags, halo_xr_frame.head_flags */
@@ -129,7 +109,6 @@ struct halo_xr_frame
struct halo_xr_pose head;
struct halo_xr_view views[HALO_XR_EYE_COUNT];
struct halo_xr_hand hands[HALO_XR_HAND_COUNT];
int controller_layout; /* HALO_XR_LAYOUT_* */
};
/* halo_xr_submit.overlay_mode */
@@ -168,12 +147,6 @@ struct halo_xr_submit
int crosshair;
float crosshair_size;
struct halo_xr_pose crosshair_pose;
/* the names layer was filled: its first name_count slots, each shown
this wide (metres, a slot's height following from its shape), here in
LOCAL space, facing the eyes */
int name_count;
float name_widths[HALO_XR_MAXIMUM_NAMES];
struct halo_xr_pose name_poses[HALO_XR_MAXIMUM_NAMES];
};
#endif
@@ -1,62 +0,0 @@
/*
FDM_INJECTION_STUB.C
An OpenXR API layer that does nothing, named as the Steam Frame's
XR_APILAYER_VALVE_fdm_injection names its library
(libVkLayer_VALVE_fdm_injection.so). The Frame lists that layer as implicit
for every OpenXR app (/vendor/etc/openxr/1/api_layers/implicit.d), but an
Android app (in Lepton) cannot load the system's library from its own
namespace, and the Khronos loader then fails xrCreateInstance altogether;
nor does the Android loader read the variable that would turn the layer
off. With this one in the app's libraries the loader finds a layer of that
name, which hands every call on to the next. (The real layer adds fragment
density maps to Vulkan apps; this game draws with OpenGL ES.) On a Quest no
manifest names it and it is never loaded.
*/
#include <openxr/openxr.h>
#include <openxr/openxr_loader_negotiation.h>
#include <stddef.h>
static PFN_xrGetInstanceProcAddr next_get_instance_proc_addr;
static XRAPI_ATTR XrResult XRAPI_CALL layer_get_instance_proc_addr(XrInstance instance, const char *name,
PFN_xrVoidFunction *function)
{
if (!next_get_instance_proc_addr)
return XR_ERROR_HANDLE_INVALID;
return next_get_instance_proc_addr(instance, name, function);
}
static XRAPI_ATTR XrResult XRAPI_CALL layer_create_api_layer_instance(const XrInstanceCreateInfo *info,
const XrApiLayerCreateInfo *layer_info, XrInstance *instance)
{
XrApiLayerCreateInfo next_layer_info;
if (!layer_info || !layer_info->nextInfo)
return XR_ERROR_INITIALIZATION_FAILED;
next_get_instance_proc_addr = layer_info->nextInfo->nextGetInstanceProcAddr;
next_layer_info = *layer_info;
next_layer_info.nextInfo = layer_info->nextInfo->next;
return layer_info->nextInfo->nextCreateApiLayerInstance(info, &next_layer_info, instance);
}
__attribute__((visibility("default")))
XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loader_info,
const char *layer_name, XrNegotiateApiLayerRequest *request)
{
(void)layer_name;
if (!loader_info || !request || loader_info->structType != XR_LOADER_INTERFACE_STRUCT_LOADER_INFO ||
request->structType != XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST ||
loader_info->minInterfaceVersion > XR_CURRENT_LOADER_API_LAYER_VERSION ||
loader_info->maxInterfaceVersion < XR_CURRENT_LOADER_API_LAYER_VERSION)
{
return XR_ERROR_INITIALIZATION_FAILED;
}
request->layerInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION;
request->layerApiVersion = loader_info->maxApiVersion < XR_CURRENT_API_VERSION ? loader_info->maxApiVersion :
XR_CURRENT_API_VERSION;
request->getInstanceProcAddr = layer_get_instance_proc_addr;
request->createApiLayerInstance = layer_create_api_layer_instance;
return XR_SUCCESS;
}
-32
View File
@@ -1,32 +0,0 @@
Newtown
Copyright (c) Roger White, 1994. Released by its author into the public domain.
Newtown-Regular.ttf is the TrueType file of Newtown, as Roger White
distributed it (NEWTOW__.TTF, version 1.00, SHA-256
376d82c5b660c059c182d848d0a96da9dbe7277d7c8820f6e9a2c99b1a256c65), here
renamed. OpenCE (OpenCE-Regular.ttf) is made from it by tools/title_font.py.
The file's copyright notice ("All Rights Reserved - see .txt file for terms
for distribution and use") and the readme it was first distributed with
(personal use free, commercial use for a fee) date from 1994. Its author
later released all of his fonts into the public domain. His website,
rogersfonts.org.uk, said so from 2008 until it closed:
"Despite what is said in the readme files associated with the fonts all
fonts on this site are now public domain, whether used for personal use
or for commercial purposes. All that I ask is that the source is
acknowledged if you are using any for commercial purposes."
The statement is in the Internet Archive's copies of the site's home page,
the first of them from 24 July 2008:
https://web.archive.org/web/20080724224405/http://www.rogersfonts.org.uk/body_index.html
https://web.archive.org/web/20110724011202/http://www.rogersfonts.org.uk/body_index.html
and Newtown was one of the site's fonts (its samples are archived from 2004,
https://web.archive.org/web/20040909032418/http://www.rogersfonts.org.uk/assets/images/Newtown.gif).
The site says its fonts were made from the author's own hand-drawn artwork,
scanned and cleaned up.
As he asked, the source is acknowledged: OpenCE is based on Newtown by
Roger White.
Binary file not shown.
-95
View File
@@ -1,95 +0,0 @@
Copyright 2026 The OpenCE Project Authors, for its changes to Newtown's spacing.
OpenCE is based on Newtown, by Roger White (1994), which its author released
into the public domain (Newtown-LICENSE.txt).
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-93
View File
@@ -1,93 +0,0 @@
Copyright 2021 The Overpass Project Authors (https://github.com/RedHatOfficial/Overpass)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
-45
View File
@@ -1,45 +0,0 @@
# Fonts
The fonts the game's text is drawn with, at the display's resolution, in
place of the bitmap fonts of the maps (`port/linux/src/text_hires.c`).
`fonts.json` says which font draws each of the maps' font tags.
| File | Draws | From |
| --- | --- | --- |
| `Overpass-900.ttf` | `ui\large_ui`, `ui\interstate` | Overpass, weight 900 (Black) |
| `Overpass-750.ttf` | `ui\small_ui` | Overpass, weight 750 |
| `OpenCE-Regular.ttf` | the menus' titles, as pictures (`port/assets/titles`) | OpenCE: Newtown, respaced for this project (`tools/title_font.py`) |
| `Newtown-Regular.ttf` | (OpenCE's source) | Newtown by Roger White, unmodified |
The maps' fonts are Interstate (Tobias Frere-Jones, The Font Bureau), a
commercial typeface that cannot be shipped. Overpass (Red Hat, Delve
Withrington) follows the same Highway Gothic road-sign alphabet and is
under the SIL Open Font License 1.1 (`Overpass-OFL.txt`), without a
Reserved Font Name. Matched against the maps' glyphs, its weights 900 and 750 overlap
them as much as Interstate Bold does, at the same letter widths.
The menus' titles are pictures of text in the maps, set in another
commercial typeface. OpenCE (Open Community Edition) stands in for it:
Newtown, a typeface in the same style by Roger White (1994), which its author
released into the public domain (`Newtown-LICENSE.txt` quotes his statement
and where it is archived), respaced for this project. Only its spacing is
changed, its outlines are Newtown's: each letter's side spaces and the
kerning pairs are measured from where the letters sit in the maps' titles.
OpenCE is under the SIL Open Font License 1.1 (`OpenCE-OFL.txt`), without a
Reserved Font Name. It is not embedded: `tools/title_assets.py` draws the
titles with it, and the builds embed those pictures. To measure its spacing
again and rebuild it:
python3 tools/title_font.py --measure # paste the values into tools/title_font.py
python3 tools/title_font.py
python3 tools/title_assets.py --map assets/maps/ui.map
The Overpass files are static instances of Google Fonts' variable Overpass
(`ofl/overpass/Overpass[wght].ttf`, google/fonts commit
9710da1eacb3be272583c3224dcb70f9da6eadbb), made with fontTools:
python3 -m fontTools.varLib.instancer 'Overpass[wght].ttf' wght=900 -o Overpass-900.ttf
python3 -m fontTools.varLib.instancer 'Overpass[wght].ttf' wght=750 -o Overpass-750.ttf
The builds embed the Overpass files (`tools/embed_assets.py`), and the
release packages carry `Overpass-OFL.txt`, as the license asks.
-8
View File
@@ -1,8 +0,0 @@
{
"comment": "Which font draws each of the maps' font tags (port/linux/src/text_hires.c).",
"fonts": [
{"tag": "ui\\large_ui", "file": "Overpass-900.ttf"},
{"tag": "ui\\interstate", "file": "Overpass-900.ttf"},
{"tag": "ui\\small_ui", "file": "Overpass-750.ttf"}
]
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because it is too large. Load diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

@@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="64" viewBox="0 0 512 64">
<!-- ammo meter fill alpha: slanted bar whose top sweeps up into a tab on the right -->
<path d="M7.56,32 H209.2 C289.7,32 340.8,7.2 353.7,0 H406.9 A8.3,8.3 0 0 1 414.1,11.4 L393.2,56 H5 A5,5 0 0 1 0,51 V48.1 Z" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 323 B

@@ -1,66 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="128" viewBox="0 0 512 128">
<!-- 3 rows x 20 slanted bullet rounds (alpha mask) -->
<defs>
<path id="b" d="M51.34,0 H51.79 L54.02,6 L42.83,30 H32.47 L43.71,5.89 Z" fill="#fff"/>
</defs>
<use href="#b"/>
<use href="#b" x="20.63" y="0"/>
<use href="#b" x="41.26" y="0"/>
<use href="#b" x="61.89" y="0"/>
<use href="#b" x="82.52" y="0"/>
<use href="#b" x="103.16" y="0"/>
<use href="#b" x="123.79" y="0"/>
<use href="#b" x="144.42" y="0"/>
<use href="#b" x="165.05" y="0"/>
<use href="#b" x="185.68" y="0"/>
<use href="#b" x="206.31" y="0"/>
<use href="#b" x="226.94" y="0"/>
<use href="#b" x="247.57" y="0"/>
<use href="#b" x="268.20" y="0"/>
<use href="#b" x="288.83" y="0"/>
<use href="#b" x="309.47" y="0"/>
<use href="#b" x="330.10" y="0"/>
<use href="#b" x="350.73" y="0"/>
<use href="#b" x="371.36" y="0"/>
<use href="#b" x="391.99" y="0"/>
<use href="#b" x="-15.85" y="34"/>
<use href="#b" x="4.78" y="34"/>
<use href="#b" x="25.41" y="34"/>
<use href="#b" x="46.04" y="34"/>
<use href="#b" x="66.67" y="34"/>
<use href="#b" x="87.30" y="34"/>
<use href="#b" x="107.93" y="34"/>
<use href="#b" x="128.56" y="34"/>
<use href="#b" x="149.19" y="34"/>
<use href="#b" x="169.82" y="34"/>
<use href="#b" x="190.46" y="34"/>
<use href="#b" x="211.09" y="34"/>
<use href="#b" x="231.72" y="34"/>
<use href="#b" x="252.35" y="34"/>
<use href="#b" x="272.98" y="34"/>
<use href="#b" x="293.61" y="34"/>
<use href="#b" x="314.24" y="34"/>
<use href="#b" x="334.87" y="34"/>
<use href="#b" x="355.50" y="34"/>
<use href="#b" x="376.14" y="34"/>
<use href="#b" x="-31.71" y="68"/>
<use href="#b" x="-11.08" y="68"/>
<use href="#b" x="9.55" y="68"/>
<use href="#b" x="30.19" y="68"/>
<use href="#b" x="50.82" y="68"/>
<use href="#b" x="71.45" y="68"/>
<use href="#b" x="92.08" y="68"/>
<use href="#b" x="112.71" y="68"/>
<use href="#b" x="133.34" y="68"/>
<use href="#b" x="153.97" y="68"/>
<use href="#b" x="174.60" y="68"/>
<use href="#b" x="195.23" y="68"/>
<use href="#b" x="215.86" y="68"/>
<use href="#b" x="236.49" y="68"/>
<use href="#b" x="257.13" y="68"/>
<use href="#b" x="277.76" y="68"/>
<use href="#b" x="298.39" y="68"/>
<use href="#b" x="319.02" y="68"/>
<use href="#b" x="339.65" y="68"/>
<use href="#b" x="360.28" y="68"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

@@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="64" viewBox="0 0 512 64">
<!-- rocket ammo: tail fin + body, grey translucent fill with white outline; pair repeated -->
<defs>
<g id="rocket" fill="#a6a6a6" fill-opacity=".651" stroke="#fff" stroke-width="4.1" stroke-miterlimit="10">
<path d="M30.7,1.35 H51.4 L58.4,22 H90.6 L79.5,46 H48.1 L24.5,62.2 H3.5 L18.4,46.2 H11.6 L22.65,22 H29.35 Z"/>
<path d="M88.5,48.4 L124.3,52 L191.9,46.1 L210.8,32.8 L202.7,21.9 L142.6,16 L101.8,19.8 Z"/>
</g>
</defs>
<use href="#rocket"/>
<use href="#rocket" x="214"/>
</svg>

Before

Width:  |  Height:  |  Size: 644 B

@@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="64" viewBox="0 0 512 64">
<!-- slanted meter bar, grey translucent fill fading slightly darker downwards (rgb = alpha) -->
<defs>
<linearGradient id="g" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="44">
<stop offset="0" stop-color="#c7c7c7" stop-opacity=".781"/>
<stop offset="1" stop-color="#b4b4b4" stop-opacity=".705"/>
</linearGradient>
</defs>
<path d="M20,0 H412 L392,44 H0 Z" fill="url(#g)"/>
</svg>

Before

Width:  |  Height:  |  Size: 506 B

@@ -1,26 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="64" viewBox="0 0 512 64">
<!-- 20 slanted blade ticks (alpha mask) -->
<defs>
<path id="t" d="M28.03,0 H40.39 L17.73,48.6 L0.58,59.39 L1.03,57.87 Z" fill="#fff"/>
</defs>
<use href="#t" x="0.000"/>
<use href="#t" x="20.704"/>
<use href="#t" x="41.408"/>
<use href="#t" x="62.112"/>
<use href="#t" x="82.816"/>
<use href="#t" x="103.520"/>
<use href="#t" x="124.224"/>
<use href="#t" x="144.928"/>
<use href="#t" x="165.632"/>
<use href="#t" x="186.336"/>
<use href="#t" x="207.040"/>
<use href="#t" x="227.744"/>
<use href="#t" x="248.448"/>
<use href="#t" x="269.152"/>
<use href="#t" x="289.856"/>
<use href="#t" x="310.560"/>
<use href="#t" x="331.264"/>
<use href="#t" x="351.968"/>
<use href="#t" x="372.672"/>
<use href="#t" x="393.376"/>
</svg>

Before

Width:  |  Height:  |  Size: 905 B

@@ -1,20 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="64" viewBox="0 0 512 64">
<!-- 12 tilted shotgun shells (alpha mask): tapered body with rim + separate tip -->
<defs>
<path id="s" transform="translate(15.87,38.77) rotate(25)" fill="#fff"
d="M-8.04,-18.2 H8.04 V4.82 L6.23,12.94 H9.78 V17.06 H-9.78 V12.94 H-6.23 L-8.04,4.82 Z
M-8.08,-21.95 H8.08 L4.93,-40.72 H-4.93 Z"/>
</defs>
<use href="#s" x="0.000"/>
<use href="#s" x="35.273"/>
<use href="#s" x="70.546"/>
<use href="#s" x="105.819"/>
<use href="#s" x="141.092"/>
<use href="#s" x="176.365"/>
<use href="#s" x="211.638"/>
<use href="#s" x="246.911"/>
<use href="#s" x="282.184"/>
<use href="#s" x="317.457"/>
<use href="#s" x="352.730"/>
<use href="#s" x="388.003"/>
</svg>

Before

Width:  |  Height:  |  Size: 841 B

@@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="128" viewBox="0 0 512 128">
<!-- 2x2 rifle rounds (alpha mask): rimmed case with rounded shoulder + ogive bullet -->
<defs>
<path id="r" fill="#fff" d="M20,0 H28 V5.5 H101.8 V6.4 H108.5 A7.5,7.5 0 0 1 116,13.9 V22.1 A7.5,7.5 0 0 1 108.5,29.6 H101.8 V30.5 H28 V36 H20 Z
M120,8 H135 C163.6,9 194.5,13.65 212.3,18 C194.5,22.35 163.6,27 135,28 H120 Z"/>
</defs>
<use href="#r"/>
<use href="#r" x="208"/>
<use href="#r" x="-20" y="44"/>
<use href="#r" x="188" y="44"/>
</svg>

Before

Width:  |  Height:  |  Size: 598 B

@@ -1,19 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="64" viewBox="0 0 512 64">
<!-- 12 two-part slanted ammo ticks (alpha mask); lower part has a flared foot -->
<defs>
<path id="t" fill="#fff" d="M33.4,0 h19 L33.76,40 h-19 Z
M12.89,44 h19 L24.43,60 h2.7 L25.03,64.5 H0.66 L2.75,60 h2.68 Z"/>
</defs>
<use href="#t" x="0.000"/>
<use href="#t" x="34.973"/>
<use href="#t" x="69.946"/>
<use href="#t" x="104.919"/>
<use href="#t" x="139.892"/>
<use href="#t" x="174.865"/>
<use href="#t" x="209.838"/>
<use href="#t" x="244.811"/>
<use href="#t" x="279.784"/>
<use href="#t" x="314.757"/>
<use href="#t" x="349.730"/>
<use href="#t" x="384.703"/>
</svg>

Before

Width:  |  Height:  |  Size: 742 B

Loaded 100 of 686 files, more files were not shown because too many files have changed in this diff. Show more