Compare commits

..
Author SHA1 Message Date
Stefan MaierandClaude Opus 5.5 0e6327cadf The controls page lists switching grenades (B held) on a line of its own
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:41:56 +02:00
Stefan MaierandClaude Opus 5.5 5f82df71f0 VR options: Y on the main menu or the pause menu
A panel of the VR settings one may change while playing (turning, snap
angle, smooth speed, the vehicles' comfort vignette, the Warthog's wheel,
the weapon laser, the crosshair, the motion tracker on the wrist), written
to config.toml, which vr.c reads again as they change; and a page of what
the controllers' buttons do, on foot, in vehicles and in the menus. The
pointer works both, and its hint opens the panel. The menus' screens are
named in the log as they come up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:37:10 +02:00
2 changed files with 513 additions and 95 deletions

No files matched your search

+21 -36
View File
@@ -132,6 +132,7 @@ static struct
unsigned long long last_frame_ms;
/* settings (config.toml, [vr]) */
unsigned long settings_read_at; /* config_changes() when the live ones were read */
int smooth_turn;
float snap_turn_degrees;
float smooth_turn_degrees_per_second;
@@ -418,22 +419,33 @@ static void world_to_local(const float world[3], float local[3])
/* ---------- platform side */
/* the settings the VR options (ui_widget.c) change while the game runs:
read at the start, and again whenever one changes */
static void vr_read_live_settings(void)
{
vr.settings_read_at = config_changes();
vr.smooth_turn = config_boolean("vr.smooth_turn");
vr.snap_turn_degrees = (float)config_real("vr.snap_turn_degrees");
vr.smooth_turn_degrees_per_second = (float)config_real("vr.smooth_turn_speed");
vr.motion_tracker_on_wrist = config_boolean("vr.motion_tracker_on_wrist");
vr.crosshair = config_boolean("vr.crosshair");
vr.laser = config_boolean("vr.laser");
vr.vehicle_wheel = config_boolean("vr.vehicle_wheel");
vr.comfort_vignette = (float)config_real("vr.comfort_vignette");
}
void halo_vr_initialize(void)
{
if (vr.active || !getenv("HALO_VR"))
return;
vr.smooth_turn = config_boolean("vr.smooth_turn");
vr.snap_turn_degrees = (float)config_real("vr.snap_turn_degrees");
vr.smooth_turn_degrees_per_second = (float)config_real("vr.smooth_turn_speed");
vr_read_live_settings();
vr.cinematics_3d = config_boolean("vr.cinematics_in_3d");
vr.hud_distance = (float)config_real("vr.hud_distance");
vr.hud_width = 2.0f * vr.hud_distance * tanf((float)config_real("vr.hud_field_of_view") * PI / 360.0f);
vr.screen_distance = (float)config_real("vr.screen_distance");
vr.screen_width = (float)config_real("vr.screen_width");
vr.positional_tracking = config_boolean("vr.positional_tracking");
vr.motion_tracker_on_wrist = config_boolean("vr.motion_tracker_on_wrist");
vr.scope_size = (float)config_real("vr.scope_size");
vr.crosshair = config_boolean("vr.crosshair");
vr.motion_tracker_size = (float)config_real("vr.motion_tracker_size");
vr.motion_tracker_turn = (float)config_real("vr.motion_tracker_turn");
vr.motion_tracker_right = (float)config_real("vr.motion_tracker_right");
@@ -443,7 +455,6 @@ void halo_vr_initialize(void)
vr.rise_limit = 0.25f;
vr.log_performance = config_boolean("vr.log_performance");
vr.aim_with_controller = strcmp(config_string("vr.aim_with"), "head") != 0;
vr.laser = config_boolean("vr.laser");
vr.weapon_offset[0] = (float)config_real("vr.weapon_forward");
vr.weapon_offset[1] = (float)config_real("vr.weapon_right");
vr.weapon_offset[2] = (float)config_real("vr.weapon_down");
@@ -465,13 +476,11 @@ void halo_vr_initialize(void)
vr.vehicle_steer_angle = (float)config_real("vr.vehicle_steer_degrees") * PI / 180.0f;
vr.vehicle_gun_steer_angle = (float)config_real("vr.vehicle_gun_steer_degrees") * PI / 180.0f;
vr.vehicle_pitch_angle = (float)config_real("vr.vehicle_pitch_degrees") * PI / 180.0f;
vr.vehicle_wheel = config_boolean("vr.vehicle_wheel");
vr.vehicle_wheel_angle = (float)config_real("vr.vehicle_wheel_degrees") * PI / 180.0f;
if (vr.vehicle_wheel_angle < 10.0f * PI / 180.0f)
vr.vehicle_wheel_angle = 10.0f * PI / 180.0f;
vr.vehicle_steer_curve = (float)config_real("vr.vehicle_steer_curve");
vr.vehicle_steer_smoothing = (float)config_real("vr.vehicle_steer_smoothing");
vr.comfort_vignette = (float)config_real("vr.comfort_vignette");
vr.grenade_scale = (float)config_real("vr.grenade_scale");
vr.grenade_offset[0] = (float)config_real("vr.grenade_right");
vr.grenade_offset[1] = 0.0f;
@@ -1191,6 +1200,8 @@ void halo_vr_frame_begin(void)
vr.recentre_frames--;
vr_recentre();
}
if (vr.settings_read_at != config_changes())
vr_read_live_settings();
turn_update();
wheel_update();
vignette_update();
@@ -2139,10 +2150,6 @@ static struct
int valid;
float x, y;
float reported_x, reported_y;
/* (a stick moved the menu's choice: the pointer, not moved far from
here since, leaves it be) */
int stick_quiet;
float stick_x, stick_y;
int hand;
int trigger_down[HALO_XR_HAND_COUNT];
int clicks;
@@ -2237,31 +2244,9 @@ int halo_vr_menu_pointer(int *x, int *y, int *click_x, int *click_y, int *moved,
return 0;
*x = (int)menu_pointer.x;
*y = (int)menu_pointer.y;
/* (a stick pushed: what it chooses stays chosen until the pointer
moves well away) */
{
int index;
for (index = 0; index < HALO_XR_HAND_COUNT; index++)
{
const struct halo_xr_hand *hand = &vr.frame.hands[index];
if (hand->active && (fabsf(hand->thumbstick[0]) > 0.4f || fabsf(hand->thumbstick[1]) > 0.4f))
{
menu_pointer.stick_quiet = 1;
menu_pointer.stick_x = menu_pointer.x;
menu_pointer.stick_y = menu_pointer.y;
}
}
if (menu_pointer.stick_quiet && (fabsf(menu_pointer.x - menu_pointer.stick_x) > 25.0f ||
fabsf(menu_pointer.y - menu_pointer.stick_y) > 25.0f))
{
menu_pointer.stick_quiet = 0;
}
}
/* (moved past a hand's tremor: a few pixels) */
*moved = !menu_pointer.stick_quiet && (fabsf(menu_pointer.x - menu_pointer.reported_x) >= 3.0f ||
fabsf(menu_pointer.y - menu_pointer.reported_y) >= 3.0f);
*moved = fabsf(menu_pointer.x - menu_pointer.reported_x) >= 3.0f ||
fabsf(menu_pointer.y - menu_pointer.reported_y) >= 3.0f;
if (*moved)
{
menu_pointer.reported_x = menu_pointer.x;
+492 -59
View File
@@ -5751,57 +5751,6 @@ static void ui_mouse_list_directions(
return;
}
#ifdef HALO_ANDROID
/* VR: a click beside a list's slots or a value's box, along the way it
steps, where its arrows are drawn: a step back or on (TRUE: taken) */
static boolean ui_mouse_click_beside_list(
short x,
short y)
{
struct widget_instance *list = NULL;
rectangle2d bounds;
long index;
short back, forward;
boolean across;
for (index = 0; index < ui_mouse_target_count; index++)
{
struct ui_mouse_target const *target = &ui_mouse_targets[index];
struct widget_instance *owner = target->kind == _ui_mouse_target_list_slot ? target->widget->parent :
target->kind == _ui_mouse_target_value ? target->widget : NULL;
if (!owner)
continue;
if (!list)
{
list = owner;
bounds = target->bounds;
}
else if (owner == list)
{
bounds.x0 = MIN(bounds.x0, target->bounds.x0);
bounds.y0 = MIN(bounds.y0, target->bounds.y0);
bounds.x1 = MAX(bounds.x1, target->bounds.x1);
bounds.y1 = MAX(bounds.y1, target->bounds.y1);
}
}
if (!list)
return FALSE;
ui_mouse_list_directions(list, &back, &forward);
across = back == _widget_event_dpad_left;
if (across ? y < bounds.y0 - 24 || y >= bounds.y1 + 24 : x < bounds.x0 - 24 || x >= bounds.x1 + 24)
return FALSE;
ui_mouse_give_focus(list);
if (across ? x < bounds.x0 && x >= bounds.x0 - 80 : y < bounds.y0 && y >= bounds.y0 - 48)
ui_mouse_press(back);
else if (across ? x >= bounds.x1 && x < bounds.x1 + 80 : y >= bounds.y1 && y < bounds.y1 + 48)
ui_mouse_press(forward);
else
return FALSE;
return TRUE;
}
#endif
/* steps a list that shows several items to the one shown in a slot, as
pressing the d-pad that many times would */
static void ui_mouse_step_list_to_slot(
@@ -5886,6 +5835,7 @@ the public games and a way to type a code in, either of which then joins as
an invite link does (the game shows up in the list once its host is
reached). */
void platform_log(char const *format, ...);
int p2p_join_code(char *text, int size);
int p2p_join_with_code(char const *typed);
int p2p_join_code_status(void);
@@ -6225,6 +6175,18 @@ static boolean ui_join_code_take_pointer(
static void ui_join_code_update(
void)
{
{
/* (each screen's name in the log, as it comes up) */
static char const *logged;
char const *name = widget_globals.active_widgets[0] ? widget_globals.active_widgets[0]->name : NULL;
if (name != logged)
{
logged = name;
if (name)
platform_log("menus: screen %s", name);
}
}
char text[sizeof(ui_join_code_globals.typed) / sizeof(wchar_t)];
short index;
@@ -6458,6 +6420,482 @@ static void ui_join_code_render(
}
}
/* ---------- VR options (the VR port's)
In VR, Y on the main menu or the pause menu opens a panel of the VR
settings one may want to change while playing (vr.c reads them again as
they change), and from it a page of what the controllers' buttons do. */
int config_boolean(char const *name);
double config_real(char const *name);
int config_write(char const *name, char const *value);
int config_write_boolean(char const *name, int value);
enum
{
_vr_option_turning,
_vr_option_snap_angle,
_vr_option_smooth_speed,
_vr_option_vignette,
_vr_option_wheel,
_vr_option_laser,
_vr_option_crosshair,
_vr_option_motion_tracker,
_vr_option_controls,
NUMBER_OF_VR_OPTIONS,
VR_OPTIONS_TOP = 102,
VR_OPTIONS_ROW_HEIGHT = 28,
VR_OPTIONS_FOOTER = 362,
_vr_controls_on_foot = 0,
_vr_controls_vehicles,
_vr_controls_menus,
NUMBER_OF_VR_CONTROLS_PAGES,
};
static struct
{
boolean open;
boolean controls;
short selection;
short page;
} ui_vr_options_globals;
static real const vr_snap_angles[] = { 30.0f, 45.0f, 60.0f, 90.0f };
static real const vr_smooth_speeds[] = { 60.0f, 90.0f, 120.0f, 150.0f, 180.0f };
static real const vr_vignettes[] = { 0.0f, 0.35f, 0.7f, 1.0f };
static char const *const vr_vignette_names[] = { "Off", "Light", "Medium", "Strong" };
static boolean ui_vr_options_screen(
void)
{
struct widget_instance *screen = widget_globals.active_widgets[0];
return halo_vr_active() && screen && screen->name &&
(main_menu_screen_is_active() || strstr(screen->name, "pause_game") != NULL);
}
/* which of the choices a setting is nearest */
static short ui_vr_options_nearest(
real value,
real const *choices,
short count)
{
short index;
short nearest = 0;
for (index = 1; index < count; index++)
{
if (fabs(choices[index] - value) < fabs(choices[nearest] - value))
nearest = index;
}
return nearest;
}
static void ui_vr_options_step(
char const *name,
real const *choices,
short count,
short change)
{
char text[16];
short index = ui_vr_options_nearest((real)config_real(name), choices, count);
index = (short)((index + change + count) % count);
snprintf(text, sizeof(text), "%g", choices[index]);
config_write(name, text);
}
/* a row's setting changed: forward or back, going round */
static void ui_vr_options_change(
short change)
{
switch (ui_vr_options_globals.selection)
{
case _vr_option_turning: config_write_boolean("vr.smooth_turn", !config_boolean("vr.smooth_turn")); break;
case _vr_option_snap_angle:
ui_vr_options_step("vr.snap_turn_degrees", vr_snap_angles, NUMBEROF(vr_snap_angles), change);
break;
case _vr_option_smooth_speed:
ui_vr_options_step("vr.smooth_turn_speed", vr_smooth_speeds, NUMBEROF(vr_smooth_speeds), change);
break;
case _vr_option_vignette:
ui_vr_options_step("vr.comfort_vignette", vr_vignettes, NUMBEROF(vr_vignettes), change);
break;
case _vr_option_wheel: config_write_boolean("vr.vehicle_wheel", !config_boolean("vr.vehicle_wheel")); break;
case _vr_option_laser: config_write_boolean("vr.laser", !config_boolean("vr.laser")); break;
case _vr_option_crosshair: config_write_boolean("vr.crosshair", !config_boolean("vr.crosshair")); break;
case _vr_option_motion_tracker:
config_write_boolean("vr.motion_tracker_on_wrist", !config_boolean("vr.motion_tracker_on_wrist"));
break;
case _vr_option_controls:
ui_vr_options_globals.controls = TRUE;
ui_vr_options_globals.page = _vr_controls_on_foot;
break;
}
ui_play_audio_feedback_sound(_ui_audio_feedback_forward);
}
static void ui_vr_options_close(
void)
{
ui_vr_options_globals.open = FALSE;
ui_vr_options_globals.controls = FALSE;
}
/* the panel's input: up and down choose a row, left and right (or A)
change it, B or Y closes it (the controls page: left and right turn its
pages, B goes back) */
static boolean ui_vr_options_take_event(
struct widget_instance *widget,
struct event_record const *event)
{
short move = 0;
short change = 0;
boolean accept = FALSE;
boolean back = FALSE;
if (widget != widget_globals.active_widgets[0])
return FALSE;
if (ui_vr_options_globals.open && !ui_vr_options_screen())
ui_vr_options_close();
if (!ui_vr_options_globals.open)
{
if (event->type == _event_type_button && event->data.button.value == 1 &&
event->data.button.index == _gamepad_analog_button_y && ui_vr_options_screen())
{
ui_vr_options_globals.open = TRUE;
ui_vr_options_globals.controls = FALSE;
ui_vr_options_globals.selection = 0;
ui_play_audio_feedback_sound(_ui_audio_feedback_forward);
return TRUE;
}
return FALSE;
}
if (event->type == _event_type_left_stick)
{
if (event->data.stick.y == SHORT_MAX)
move = -1;
else if (event->data.stick.y == SHORT_MIN)
move = 1;
else if (event->data.stick.x == SHORT_MAX)
change = 1;
else if (event->data.stick.x == SHORT_MIN)
change = -1;
}
else if (event->type == _event_type_button && event->data.button.value == 1)
{
switch (event->data.button.index)
{
case _gamepad_binary_button_dpad_up: move = -1; break;
case _gamepad_binary_button_dpad_down: move = 1; break;
case _gamepad_binary_button_dpad_right: change = 1; break;
case _gamepad_binary_button_dpad_left: change = -1; break;
case _gamepad_analog_button_a:
case _gamepad_binary_button_start:
accept = TRUE;
break;
case _gamepad_analog_button_b:
case _gamepad_analog_button_y:
case _gamepad_binary_button_back:
back = TRUE;
break;
}
}
if (ui_vr_options_globals.controls)
{
if (back)
{
ui_vr_options_globals.controls = FALSE;
ui_play_audio_feedback_sound(_ui_audio_feedback_back);
}
else if (change || accept)
{
ui_vr_options_globals.page = (short)((ui_vr_options_globals.page + (change ? change : 1) +
NUMBER_OF_VR_CONTROLS_PAGES) % NUMBER_OF_VR_CONTROLS_PAGES);
ui_play_audio_feedback_sound(_ui_audio_feedback_cursor);
}
return TRUE;
}
if (back)
{
ui_vr_options_close();
ui_play_audio_feedback_sound(_ui_audio_feedback_back);
}
else if (move)
{
ui_vr_options_globals.selection = (short)PIN(ui_vr_options_globals.selection + move, 0, NUMBER_OF_VR_OPTIONS - 1);
ui_play_audio_feedback_sound(_ui_audio_feedback_cursor);
}
else if (accept)
{
ui_vr_options_change(1);
}
else if (change && ui_vr_options_globals.selection != _vr_option_controls)
{
ui_vr_options_change(change);
}
return TRUE;
}
/* the pointer over the panel: the row under it chosen, a click on it as A;
on the controls page the tabs, and the footer's Back (TRUE: the panel is
open and took it) */
static boolean ui_vr_options_take_pointer(
struct halo_ui_pointer const *pointer)
{
short x = pointer->left_clicks ? pointer->click_x : pointer->x;
short y = pointer->left_clicks ? pointer->click_y : pointer->y;
if (!ui_vr_options_globals.open)
{
/* (its hint clicked: open) */
if (pointer->left_clicks && x >= 256 && x < 400 && y >= 434 && y < 464 && ui_vr_options_screen())
{
ui_vr_options_globals.open = TRUE;
ui_vr_options_globals.controls = FALSE;
ui_vr_options_globals.selection = 0;
ui_play_audio_feedback_sound(_ui_audio_feedback_forward);
return TRUE;
}
return FALSE;
}
if (!ui_vr_options_screen())
{
ui_vr_options_close();
return FALSE;
}
if (ui_vr_options_globals.controls)
{
if (!pointer->left_clicks)
return TRUE;
if (y >= 50 && y < 74 && x >= 40 && x < 600)
{
ui_vr_options_globals.page = (short)PIN((x - 40) / 186, 0, NUMBER_OF_VR_CONTROLS_PAGES - 1);
ui_play_audio_feedback_sound(_ui_audio_feedback_cursor);
}
else if (y >= 410 && y < 434)
{
ui_vr_options_globals.controls = FALSE;
ui_play_audio_feedback_sound(_ui_audio_feedback_back);
}
return TRUE;
}
if (x >= 118 && x < 522 && y >= VR_OPTIONS_TOP - 4 &&
y < VR_OPTIONS_TOP - 4 + NUMBER_OF_VR_OPTIONS * VR_OPTIONS_ROW_HEIGHT)
{
ui_vr_options_globals.selection = (short)((y - (VR_OPTIONS_TOP - 4)) / VR_OPTIONS_ROW_HEIGHT);
if (pointer->left_clicks)
ui_vr_options_change(1);
}
else if (pointer->left_clicks && x >= 118 && x < 522 && y >= VR_OPTIONS_FOOTER + 4 && y < VR_OPTIONS_FOOTER + 30)
{
ui_vr_options_close();
ui_play_audio_feedback_sound(_ui_audio_feedback_back);
}
return TRUE;
}
/* a line of the controls page: what is pressed, dim, and what it does */
static void ui_vr_controls_line(
short x,
short y,
char const *control,
char const *action)
{
real_argb_color control_color = { 1.0f, 0.55f, 0.75f, 1.0f };
real_argb_color action_color = { 1.0f, 0.88f, 0.88f, 0.88f };
ui_join_code_draw_text(x, (short)(x + 92), y, control, FALSE, 0, &control_color);
ui_join_code_draw_text((short)(x + 92), (short)(x + 280), y, action, FALSE, 0, &action_color);
}
static void ui_vr_controls_note(
short y,
char const *text)
{
real_argb_color color = { 1.0f, 0.88f, 0.88f, 0.88f };
ui_join_code_draw_text(44, 596, y, text, FALSE, 0, &color);
}
static void ui_vr_controls_render(
void)
{
static char const *const tabs[] = { "ON FOOT", "VEHICLES", "MENUS" };
real_argb_color title_color = { 1.0f, 0.55f, 0.75f, 1.0f };
real_argb_color tab_color = { 1.0f, 0.6f, 0.6f, 0.6f };
real_argb_color selected_color = { 1.0f, 1.0f, 1.0f, 1.0f };
short tab;
short left = 44;
short right = 328;
short y = 112;
ui_join_code_draw_quad(24, 40, 616, 440, 0xFF050A18);
ui_join_code_draw_quad(24, 40, 616, 42, 0xFF3A6EA5);
ui_join_code_draw_quad(24, 438, 616, 440, 0xFF3A6EA5);
for (tab = 0; tab < NUMBER_OF_VR_CONTROLS_PAGES; tab++)
{
short x0 = (short)(40 + tab * 186);
if (tab == ui_vr_options_globals.page)
ui_join_code_draw_quad(x0, 50, (short)(x0 + 180), 74, 0x803A6EA5);
ui_join_code_draw_text(x0, (short)(x0 + 180), 52, tabs[tab], FALSE, 2,
tab == ui_vr_options_globals.page ? &selected_color : &tab_color);
}
ui_join_code_draw_text(left, (short)(left + 270), 86, "LEFT CONTROLLER", FALSE, 0, &title_color);
ui_join_code_draw_text(right, (short)(right + 270), 86, "RIGHT CONTROLLER", FALSE, 0, &title_color);
ui_join_code_draw_quad(320, 86, 321, 300, 0xFF3A6EA5);
switch (ui_vr_options_globals.page)
{
case _vr_controls_on_foot:
ui_vr_controls_line(left, y, "Stick", "Move");
ui_vr_controls_line(left, y + 22, "Stick click", "Crouch");
ui_vr_controls_line(left, y + 44, "Trigger", "Grenade: hold it,");
ui_vr_controls_line(left, y + 62, "", "let go as you throw");
ui_vr_controls_line(left, y + 84, "Grip", "Weapon in both hands");
ui_vr_controls_line(left, y + 106, "X", "Action, reload");
ui_vr_controls_line(left, y + 128, "Y", "Switch weapon");
ui_vr_controls_line(left, y + 150, "Menu", "Pause");
ui_vr_controls_line(right, y, "Stick", "Turn");
ui_vr_controls_line(right, y + 22, "Stick click", "Zoom");
ui_vr_controls_line(right, y + 44, "Trigger", "Fire");
ui_vr_controls_line(right, y + 66, "Grip", "Melee (or punch");
ui_vr_controls_line(right, y + 84, "", "forward)");
ui_vr_controls_line(right, y + 106, "A", "Jump");
ui_vr_controls_line(right, y + 128, "B", "Flashlight");
ui_vr_controls_line(right, y + 150, "B held", "Switch grenades");
ui_vr_controls_note(320, "Motion tracker: turn the back of your left wrist towards you.");
ui_vr_controls_note(340, "Scope: zoom, and look through the disc above the weapon.");
ui_vr_controls_note(360, "Hold the Meta button to recentre the view.");
break;
case _vr_controls_vehicles:
ui_vr_controls_line(left, y, "Stick", "Drive");
ui_vr_controls_line(left, y + 22, "Trigger", "Second weapon");
ui_vr_controls_line(left, y + 40, "", "(Banshee, tank)");
ui_vr_controls_line(left, y + 62, "X", "Get in, get out");
ui_vr_controls_line(right, y, "Stick", "Steer; up and down:");
ui_vr_controls_line(right, y + 18, "", "climb, dive");
ui_vr_controls_line(right, y + 40, "Trigger", "Fire");
ui_vr_controls_line(right, y + 62, "B", "Flashlight");
ui_vr_controls_note(300, "Warthog: grip the wheel with one hand or both and turn it.");
ui_vr_controls_note(320, "Holding it, the right trigger accelerates, the left one brakes");
ui_vr_controls_note(338, "and reverses. Let go, and the right stick steers.");
ui_vr_controls_note(360, "At a gun or as a passenger: aim with the right controller.");
break;
default:
ui_vr_controls_line(left, y, "Stick", "Choose");
ui_vr_controls_line(left, y + 22, "X, Y", "As the screen shows");
ui_vr_controls_line(left, y + 44, "Trigger", "Click where it points");
ui_vr_controls_line(right, y, "Stick", "Choose, scroll");
ui_vr_controls_line(right, y + 22, "A", "Accept");
ui_vr_controls_line(right, y + 44, "B", "Back");
ui_vr_controls_line(right, y + 66, "Trigger", "Click where it points");
ui_vr_controls_note(300, "Point at the menus with either controller; its trigger clicks.");
ui_vr_controls_note(320, "On the keyboard, BACK and ENTER under it can be clicked too.");
ui_vr_controls_note(340, "Y on the main menu or the pause menu: these VR options.");
break;
}
ui_join_code_draw_text(44, 596, 412, "%b-button Back Left, right: the other pages", TRUE, 0, &tab_color);
}
static void ui_vr_options_render(
void)
{
real_argb_color title_color = { 1.0f, 0.55f, 0.75f, 1.0f };
real_argb_color text_color = { 1.0f, 0.88f, 0.88f, 0.88f };
real_argb_color dim_color = { 1.0f, 0.5f, 0.5f, 0.5f };
real_argb_color hint_color = { 1.0f, 0.85f, 0.85f, 0.85f };
char value[48];
short row;
boolean smooth = config_boolean("vr.smooth_turn") != 0;
if (!ui_vr_options_screen())
{
ui_vr_options_close();
return;
}
if (!ui_vr_options_globals.open)
{
/* (under the menu; centred by hand, as icons are drawn from the
left) */
ui_join_code_draw_text(266, 400, 440, "%y-button VR options", TRUE, 0, &hint_color);
return;
}
if (ui_vr_options_globals.controls)
{
ui_vr_controls_render();
return;
}
ui_join_code_draw_quad(110, 62, 530, 396, 0xFF050A18);
ui_join_code_draw_quad(110, 62, 530, 64, 0xFF3A6EA5);
ui_join_code_draw_quad(110, 394, 530, 396, 0xFF3A6EA5);
ui_join_code_draw_text(126, 514, 72, "VR OPTIONS", FALSE, 0, &title_color);
for (row = 0; row < NUMBER_OF_VR_OPTIONS; row++)
{
short y = (short)(VR_OPTIONS_TOP + row * VR_OPTIONS_ROW_HEIGHT);
char const *label = "";
boolean unused = FALSE;
value[0] = 0;
switch (row)
{
case _vr_option_turning:
label = "Turning";
snprintf(value, sizeof(value), "%s", smooth ? "Smooth" : "Snap");
break;
case _vr_option_snap_angle:
label = "Snap turn";
snprintf(value, sizeof(value), "%.0f degrees", vr_snap_angles[ui_vr_options_nearest(
(real)config_real("vr.snap_turn_degrees"), vr_snap_angles, NUMBEROF(vr_snap_angles))]);
unused = smooth;
break;
case _vr_option_smooth_speed:
label = "Smooth turn speed";
snprintf(value, sizeof(value), "%.0f degrees/s", vr_smooth_speeds[ui_vr_options_nearest(
(real)config_real("vr.smooth_turn_speed"), vr_smooth_speeds, NUMBEROF(vr_smooth_speeds))]);
unused = !smooth;
break;
case _vr_option_vignette:
label = "Vehicle comfort vignette";
snprintf(value, sizeof(value), "%s", vr_vignette_names[ui_vr_options_nearest(
(real)config_real("vr.comfort_vignette"), vr_vignettes, NUMBEROF(vr_vignettes))]);
break;
case _vr_option_wheel:
label = "Warthog steering wheel";
snprintf(value, sizeof(value), "%s", config_boolean("vr.vehicle_wheel") ? "On" : "Off (stick)");
break;
case _vr_option_laser:
label = "Weapon laser";
snprintf(value, sizeof(value), "%s", config_boolean("vr.laser") ? "On" : "Off");
break;
case _vr_option_crosshair:
label = "Crosshair";
snprintf(value, sizeof(value), "%s", config_boolean("vr.crosshair") ? "On" : "Off");
break;
case _vr_option_motion_tracker:
label = "Motion tracker";
snprintf(value, sizeof(value), "%s", config_boolean("vr.motion_tracker_on_wrist") ? "On the wrist" : "In the HUD");
break;
case _vr_option_controls:
label = "Controller buttons...";
break;
}
if (row == ui_vr_options_globals.selection)
ui_join_code_draw_quad(118, (short)(y - 4), 522, (short)(y + VR_OPTIONS_ROW_HEIGHT - 6), 0x803A6EA5);
ui_join_code_draw_text(128, 330, y, label, FALSE, 0, unused ? &dim_color : &text_color);
if (value[0])
{
char shown[56];
snprintf(shown, sizeof(shown), "< %s >", value);
ui_join_code_draw_text(330, 512, y, shown, FALSE, 1, unused ? &dim_color : &text_color);
}
}
ui_join_code_draw_text(126, 514, VR_OPTIONS_FOOTER + 8, "%a-button Change %b-button Done", TRUE, 0, &text_color);
}
/* whether a menu is up (VR shows it on a screen in the room: render.c) */
boolean ui_widgets_menus_active(
void)
@@ -6496,7 +6934,7 @@ static void ui_widgets_process_mouse(
{
#ifdef HALO_ANDROID
/* (the VR port's panels over the menus take the pointer themselves) */
if (ui_join_code_take_pointer(&pointer))
if (ui_vr_options_take_pointer(&pointer) || ui_join_code_take_pointer(&pointer))
return;
#endif
if (pointer.moved)
@@ -6591,12 +7029,6 @@ static void ui_widgets_process_mouse(
{
long index;
#ifdef HALO_ANDROID
/* (VR: beside a list, on its arrows) */
if (halo_vr_active() && ui_mouse_click_beside_list(ui_mouse_click_x, ui_mouse_click_y))
index = 0;
else
#endif
/* a screen with nothing to pick (a message to dismiss): the
click is its A */
for (index = 0; index < ui_mouse_target_count; index++)
@@ -6976,6 +7408,7 @@ void render_ui_widgets(
}
#ifdef HALO_ANDROID
ui_join_code_render();
ui_vr_options_render();
#endif
if (widget_globals.fade_to_black >= 0.0f &&
widget_globals.fade_to_black <= 1.0f)
@@ -8030,7 +8463,7 @@ void process_ui_widgets(
do
{
#ifdef HALO_ANDROID
if (ui_join_code_take_event(widget, &event))
if (ui_vr_options_take_event(widget, &event) || ui_join_code_take_event(widget, &event))
continue;
#endif
if (!pause_pressed)