mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-17 15:00:27 +02:00
Compare commits
27
Commits
No files matched your search
+197
-5
@@ -25,6 +25,8 @@ named where code is taken over.
|
||||
| Menus | The PC version's menus in VR (`vr.menus`), clicked with a laser; text typed on the on-screen keyboard |
|
||||
| Multiplayer | Up to date with OpenCE (network version 20): cross-play, its server browser, co-op campaign, password lobbies; join codes and the VR online list |
|
||||
| Bots | Bots in multiplayer: on foot (paths, items, objectives), in vehicles and at turrets; they make room for a joining person |
|
||||
| Controls | Left-handed mode (`vr.handedness`): the weapon in the left hand, the arms and grips mirrored, sticks and buttons mirrored on both controllers (`vr.mirror_controls`), the assault rifle's counter read the right way round (2026-10-06) |
|
||||
| Graphics | Presets low / medium / high / max (`vr.graphics`), refresh rate and resolution in the VR options, all kept over a restart (2026-10-06) |
|
||||
| Arms and hands | Both arms by IK from shoulders that follow the torso, the elbow led by the hand's roll; fingers from trigger, grip and touch; `vr.body` arms / hands / off, `vr.fingers` (2026-10-06) |
|
||||
|
||||
## Next, in order
|
||||
@@ -33,12 +35,201 @@ named where code is taken over.
|
||||
| --- | --- | --- |
|
||||
| 1 | Steam Frame CPU time: Mesa's trace markers off (after astromaddie/HaloCE-VR), no `glGet` stalls in the visibility counters' copies | **done** (in `main` 2026-10-06): markers quieted, no problems; the frame's work about unchanged (11-12.5 ms of 13.9 in a bot game) |
|
||||
| 3a | Visible arms and hands: the arms by IK to the controllers, fingers by trigger and grip | **done** (in `main` 2026-10-06; Quest 3 and Steam Frame good; 0.02 ms a frame) |
|
||||
| 2 | Controls and comfort: left-handed mode, buttons remapped, flashlight by tapping the head, finer turning and vignette choices, graphics presets and refresh rate in the VR options | |
|
||||
| 2 | Controls and comfort: left-handed mode, buttons remapped, flashlight by tapping the head, finer turning and vignette choices, graphics presets and refresh rate in the VR options | first part **done** (in `main` 2026-10-06; Quest 3 and Steam Frame good): left-handed mode, graphics presets, refresh rate and resolution in the VR options. Second part **built** (branch `feature/vr-comfort`, headset test pending): buttons remapped, flashlight by tapping the head, finer turning and vignette choices |
|
||||
| 3b | The whole body: torso from head and hands, legs and feet following in the room; full / arms only / hands only | |
|
||||
| 3c | Weapons held physically, holsters at shoulder and hip (the buttons stay) | |
|
||||
| 3d | Other VR players shown with their heads, hands and bodies (today their bodies move as flat players' do: only their aim and throws come from their hands) | |
|
||||
| 4 | Later: disc image import in the launcher, sprint by arm swing (offline) | |
|
||||
|
||||
## Step 2, first part (done)
|
||||
|
||||
Left-handed mode and graphics presets, after HaloCE-Quest-VR (CC0): its
|
||||
mirrored first-person model, its graphics switches.
|
||||
|
||||
Left-handed (`vr.handedness = "left"`):
|
||||
- The weapon in the left hand: aim, shots, muzzle, laser, crosshair,
|
||||
scope disc, turret aim. The first-person model is posed as the right
|
||||
hand's in a mirror image of the room ("model space", `halo_vr.h`) and
|
||||
mirrored back; a model whose node matrices mirror has its triangles'
|
||||
winding turned over (`rasterizer_set_model_skinning`, `d3d8_gl.c`). The
|
||||
arms reach to the other shoulders, the foregrip is gripped with the
|
||||
right hand, the right hand's fingers follow its controller.
|
||||
- Grenades held and thrown with the right trigger and hand; melee by the
|
||||
left grip (a swing of either hand, as before); the motion tracker on the
|
||||
right wrist (`halo_xr_submit.wrist_hand`); the rumble's light motor in
|
||||
the weapon hand.
|
||||
- The left trigger fires, the right one throws; at the Warthog's wheel the
|
||||
left trigger accelerates, the right one brakes.
|
||||
- With `vr.mirror_controls` (default): the right stick moves, the left
|
||||
turns and steers; their clicks, the bumpers and the face buttons change
|
||||
sides (Quest: X jumps, Y light / held grenades, A action and reload, B
|
||||
switch weapon; Steam Frame: the left D-pad does A, B, X, Y as their
|
||||
mirror image, down jump, left light, right action, up switch weapon,
|
||||
and A, B, X, Y do the D-pad's). The menus keep their buttons; the
|
||||
laser pointer works from either hand as before.
|
||||
- Other machines see the shots leave the left hand (the network message
|
||||
is unchanged: aim and muzzle from the camera).
|
||||
- The assault rifle's ammo counter and compass read the right way round
|
||||
on the mirrored model (2026-10-06): their geometry stays mirrored, each
|
||||
digit's bitmap is drawn turned over in u and the digits' order across
|
||||
the display swapped (numeric shaders drawn mirrored,
|
||||
`rasterizer_xbox_transparent_geometry.c`). Checked flat in the emulator
|
||||
with `debug.mirror_first_person` (the first-person weapon mirrored off
|
||||
the headset): 60, 48, 36 ... 06 read correctly. Steam Frame good
|
||||
(2026-10-06).
|
||||
- Kept as they are (accepted 2026-10-06): the small static icons under the
|
||||
counter (round and "x") stay mirror images (a texture atlas, not
|
||||
numeric). The game's prompts still name the Xbox's buttons.
|
||||
- Settings kept: on Android `config.toml` is written beside itself and
|
||||
renamed over (`port_config.c`), so one pushed by adb (the shell's, which
|
||||
the app could not open for writing) no longer loses the VR options'
|
||||
changes at a restart.
|
||||
- Headset tests 2026-10-06: Quest 3 and Steam Frame good (left hand,
|
||||
controls mirrored and not, counter, presets, refresh rates, resolution,
|
||||
settings kept over a restart).
|
||||
|
||||
Graphics (`vr.graphics`, `port/linux/game/vr_graphics.c`), set each frame
|
||||
on the game's own switches:
|
||||
|
||||
| Preset | Leaves out |
|
||||
| --- | --- |
|
||||
| `"high"` (default) | nothing: as before |
|
||||
| `"medium"` | object shadows, environment reflections, lens flares |
|
||||
| `"low"` | also specular light, bump maps, grass and other detail objects, the screen's fog layer, contrails, weather, camouflage's second pass |
|
||||
| `"max"` | nothing; models lit for each pixel, shadows at 512x512 |
|
||||
|
||||
A client in another's game keeps grass, lens flares and the fog layer as
|
||||
the host's rules have them (`cheats.c`). Shadows, specular passes,
|
||||
reflections and detail objects are draws (CPU, which the Frame's GL
|
||||
driver is short of); bump maps, fog, camouflage and per-pixel lighting
|
||||
the GPU's fill.
|
||||
|
||||
VR options (Y): two pages, PLAY (the comfort rows, "Weapon hand",
|
||||
"Mirrored controls") and MORE ("Graphics", "Refresh rate", "Resolution",
|
||||
the controller buttons page, Quit); four since the second part (below). The refresh rate steps through what
|
||||
the runtime offers and changes at once; on the Steam Frame the row shows
|
||||
SteamOS's rate. The resolution (`vr.resolution_scale`, 70-120%) takes a
|
||||
restart. The controller buttons page shows the layout as set.
|
||||
|
||||
| Setting | Values |
|
||||
| --- | --- |
|
||||
| `vr.handedness` | `"right"` (default), `"left"` |
|
||||
| `vr.mirror_controls` | `true` (default): sticks and buttons mirrored when left-handed; `false`: as right-handed (triggers and grips still follow the hands) |
|
||||
| `vr.graphics` | `"low"`, `"medium"`, `"high"` (default), `"max"` |
|
||||
| `vr.refresh_rate` | Hz, as offered (Quest 3: 72, 80, 90, 120) |
|
||||
| `vr.resolution_scale` | 0.7 to 1.2, on restart |
|
||||
|
||||
To try in the headset (Quest 3 and Steam Frame):
|
||||
1. Left-handed: aim, laser, crosshair, scope of sniper and rocket
|
||||
launcher; weapon held right in the left hand, arms from the right
|
||||
shoulders, nothing inside out (faces culled the wrong way would show
|
||||
the inside of the gun or the glove).
|
||||
2. Two-handed grip with the right hand; grenades in the right hand (held
|
||||
and thrown); melee by grip and by swing; motion tracker on the right
|
||||
wrist.
|
||||
3. Buttons and sticks mirrored on the Touch and the Frame controllers
|
||||
(every function reachable), then `Mirrored controls: Off`.
|
||||
4. Vehicles: wheel, throttle and brake, steering stick, a gunner's aim;
|
||||
menus and the laser pointer; a network game (shots from the left hand
|
||||
on the other machine).
|
||||
5. Graphics: each preset's look and smoothness (`vr.log_performance`),
|
||||
in a bot game; Max on the Quest at 90 Hz; refresh rates 72/80/90/120
|
||||
on the Quest; the Frame's row.
|
||||
|
||||
## Step 2, second part (built)
|
||||
|
||||
On branch `feature/vr-comfort`, not yet tried in the headset. The VR
|
||||
options (Y) have four pages: PLAY ("Weapon hand", "Mirrored controls",
|
||||
laser, crosshair, motion tracker, body, fingers, the Warthog's wheel),
|
||||
COMFORT (turning, the vignettes), BUTTONS (the actions' buttons, the
|
||||
flashlight's tap, "Reset buttons to defaults", the controller buttons
|
||||
page) and MORE (graphics, refresh rate, resolution, Quit).
|
||||
|
||||
Buttons remapped (BUTTONS page; `vr.c` `controls_remapped`):
|
||||
- Jump, the flashlight (held: switch grenades), action/reload, switch
|
||||
weapon, crouch, zoom and melee each go on one of seven buttons: A, B,
|
||||
X, Y, the move stick's click, the turning stick's, the weapon hand's
|
||||
grip. Moving an action to a button swaps it with the action there, so
|
||||
none is ever left without one.
|
||||
- The triggers, the free hand's grip, the menu button, the Steam Frame's
|
||||
bumpers, D-pad and View button keep theirs; the menus keep the buttons
|
||||
as they are.
|
||||
- Applied after the left-handed mirroring, on the gamepad's sides: the
|
||||
same on the Touch and the Frame controllers, and a left-handed player's
|
||||
buttons are the mirror image of the right-handed ones (on the Frame,
|
||||
mirrored, the left D-pad's). The defaults are the old layout, the
|
||||
host's bindings and the ABI unchanged.
|
||||
- The melee's aim and jab follow its button; the grips on a Warthog's
|
||||
wheel press nothing, whatever the grip does.
|
||||
- The controller buttons page shows each action where its button is.
|
||||
|
||||
Flashlight by tapping the head (`vr.c` `flashlight_gesture_update`,
|
||||
after HaloCE-Quest-VR, CC0): either hand to the side or the top of the
|
||||
head and away, as a tap, toggles it; the button still does. A zone in
|
||||
the head's axes beside or over the head, never more than 6 cm in front
|
||||
of the eyes (a scope at the eye, a two-handed weapon, a punch and the
|
||||
wrist's tracker are in front of the face); the hand comes from 35 cm
|
||||
away, slower than 3 m/s, stays 40 to 600 ms, alone, and leaves; a second
|
||||
between toggles. None in the menus, with a grenade held or just thrown,
|
||||
just after a melee, with both hands on the weapon, the weapon hand while
|
||||
the scope is drawn, a hand on the wheel. A short rumble in the tapping
|
||||
hand. Its logic was run in a harness off the headset; the feel is the
|
||||
headset's to judge.
|
||||
|
||||
Comfort (COMFORT page): snap turns 10 to 45 degrees by 5, 60, 75, 90;
|
||||
smooth turning 30 to 150 degrees a second by 15, then to 300 by 30; the
|
||||
vehicle vignette Off, 15 to 100%; the on-foot vignette (off by default)
|
||||
while the stick turns smoothly, or also while the move stick moves, as
|
||||
far as the sticks are pushed, with its own strength. The old values are
|
||||
among the steps; defaults unchanged.
|
||||
|
||||
Transparent geometry: room for 2048 groups a window (the Xbox's 384,
|
||||
below).
|
||||
|
||||
| Setting | Values |
|
||||
| --- | --- |
|
||||
| `vr.button_jump` | `"a"` (default), `"b"`, `"x"`, `"y"`, `"move_stick"`, `"turn_stick"`, `"grip"`: as right-handed, mirrored with `vr.mirror_controls` |
|
||||
| `vr.button_light` | the flashlight, held switch grenades; `"b"` (default) |
|
||||
| `vr.button_action` | action, reload; `"x"` (default) |
|
||||
| `vr.button_weapon` | switch weapon; `"y"` (default) |
|
||||
| `vr.button_crouch` | `"move_stick"` (default) |
|
||||
| `vr.button_zoom` | `"turn_stick"` (default) |
|
||||
| `vr.button_melee` | `"grip"` (default) |
|
||||
| `vr.flashlight_gesture` | `true` (default): a tap of the head toggles the flashlight |
|
||||
| `vr.foot_vignette` | `"off"` (default), `"turning"` (smooth turns), `"moving"` (and moving) |
|
||||
| `vr.foot_vignette_strength` | 0.15 to 1, `0.7` (default) |
|
||||
| `debug.vr_options` | `false` (default); `true` shows the VR options off the headset (the emulator) |
|
||||
|
||||
Checked in the emulator (`debug.vr_options`): the four pages without
|
||||
overlaps, each row's values, swaps and reset, the controller buttons page
|
||||
right- and left-handed after swaps, the settings kept over a restart, a
|
||||
15-bot game as before.
|
||||
|
||||
To try in the headset (Quest 3 and Steam Frame):
|
||||
1. Defaults: every button as before (jump, light/held grenades, action,
|
||||
switch weapon, crouch, zoom, melee by grip and by swing), right- and
|
||||
left-handed, mirrored and not; the menus' A and B.
|
||||
2. BUTTONS: swap jump and melee (jump on the grip, melee on A): both work,
|
||||
the melee jabs and aims where the head looks; light on a stick click
|
||||
(tap: light, hold: grenades); the controller buttons page says so.
|
||||
At the Warthog's wheel with jump on the grip: no jump while holding
|
||||
the wheel. Reset: all back.
|
||||
3. The same left-handed with mirrored controls (on the Frame the left
|
||||
D-pad), and with `Mirrored controls: Off`.
|
||||
4. Flashlight tap with either hand, beside the head and over it; the
|
||||
rumble; the flashlight button still works. No toggle while: aiming
|
||||
through the sniper's and the pistol's scope, holding the weapon with
|
||||
both hands, holding and throwing a grenade (overhand past the ear),
|
||||
punching and swinging, putting on or adjusting the headset with both
|
||||
hands or one, looking at the wrist's tracker, at the wheel.
|
||||
5. COMFORT: snap 10 and 90, smooth 30 and 300; vehicle vignette 15% and
|
||||
100%; on-foot vignette "Smooth turns" (nothing with snap turns),
|
||||
"Moving, turning", strength 15% and 100%; no vignette in a vehicle
|
||||
from the on-foot one, none in the menus.
|
||||
6. A game of 30 and more players: effects, glass and water stay; the log
|
||||
(`adb logcat -s halo`) says `rasterizer: N transparent geometry groups
|
||||
in a window` once a window passes 384; frame time as before.
|
||||
|
||||
## Step 3a (done)
|
||||
|
||||
Tried on the Quest 3 and the Steam Frame, in `main`. The arm IK,
|
||||
@@ -97,10 +288,11 @@ the left hand animated through reloads.
|
||||
- Multiview on the Steam Frame: why the eyes do not fuse there (suspected
|
||||
Mesa zink/Turnip); tools in branch `frame/doubled-images` (86335828),
|
||||
not merged.
|
||||
- Transparent geometry groups: the Xbox's 384 a window overflow in games
|
||||
of 30 and more players.
|
||||
- The VR on-screen keyboard shows a password in the clear while it is
|
||||
typed.
|
||||
- Transparent geometry groups: the Xbox's 384 a window overflowed in
|
||||
games of 30 and more players (the last submitted, glass, water,
|
||||
particles, contrails, vanished). Raised to 2048 (320 KB) on
|
||||
`feature/vr-comfort`, to check in a large game (step 2, second part,
|
||||
test 6); upstream still has 384.
|
||||
|
||||
## Headset tests (2026-10-06, all three in `main`)
|
||||
|
||||
|
||||
@@ -135,6 +135,11 @@ into a layer's image, opaque */
|
||||
int host_xr_copy_layer_array(int layer, unsigned int texture, int array_layer);
|
||||
/* darkens the eye images from their edges, strength 0..1 (0: off) */
|
||||
void host_xr_set_vignette(float strength);
|
||||
/* the refresh rates the headset offers (Hz, at most maximum of them; 0 when
|
||||
it lets none be chosen), and the one it runs at (0: unknown); and asking
|
||||
for the highest offered at or below wanted (0: the highest) */
|
||||
int host_xr_refresh_rates(float *rates, int maximum, float *current);
|
||||
void host_xr_set_refresh_rate(float wanted);
|
||||
|
||||
/* ---------- Android */
|
||||
|
||||
|
||||
+56
-23
@@ -120,10 +120,10 @@ static struct
|
||||
XrAction haptic;
|
||||
struct xr_hand_actions hands[HALO_XR_HAND_COUNT];
|
||||
|
||||
/* where the head and the left hand are this frame (the wrist layer) */
|
||||
/* where the head and the hands are this frame (the wrist layer) */
|
||||
XrPosef head;
|
||||
XrPosef left_grip;
|
||||
int left_grip_valid;
|
||||
XrPosef grips[HALO_XR_HAND_COUNT];
|
||||
int grips_valid[HALO_XR_HAND_COUNT];
|
||||
|
||||
int has_performance_settings;
|
||||
/* (XR_META_performance_metrics: the compositor's counts, in the log,
|
||||
@@ -946,11 +946,8 @@ static void hands_read(struct halo_xr_frame *frame)
|
||||
{
|
||||
out->flags = flags_from_location(location.locationFlags);
|
||||
pose_from_xr(&out->grip, &location.pose);
|
||||
if (hand == HALO_XR_HAND_LEFT)
|
||||
{
|
||||
xr.left_grip = location.pose;
|
||||
xr.left_grip_valid = (out->flags & HALO_XR_POSE_VALID) != 0;
|
||||
}
|
||||
xr.grips[hand] = location.pose;
|
||||
xr.grips_valid[hand] = (out->flags & HALO_XR_POSE_VALID) != 0;
|
||||
}
|
||||
location.locationFlags = 0;
|
||||
if (XR_SUCCEEDED(xrLocateSpace(xr.hands[hand].aim_space, xr.local_space,
|
||||
@@ -1048,7 +1045,9 @@ On the back of the left wrist, like a watch: behind the palm, where the
|
||||
grip pose is, and out of the back of the hand. In the left grip pose -Z
|
||||
runs to the fingers, +Y up the handle and -X out of the back of the hand;
|
||||
the layer faces -X with its top towards the elbow, as the wrist turned to
|
||||
the eyes reads it. Shown only while it is. */
|
||||
the eyes reads it. Shown only while it is. Left-handed (wrist_hand), on the
|
||||
right wrist, as the mirror image: there +X runs out of the back of the
|
||||
hand. */
|
||||
|
||||
#define WRIST_IMAGE_SIZE 512
|
||||
#define CROSSHAIR_IMAGE_SIZE 256
|
||||
@@ -1088,26 +1087,32 @@ static void quaternion_rotate_vector(const XrQuaternionf *q, const XrVector3f *v
|
||||
|
||||
static int wrist_pose(const struct halo_xr_submit *submit, XrPosef *pose)
|
||||
{
|
||||
/* the layer's axes in the grip's: x = -Y, y = +Z, z = -X, so the
|
||||
layer's right and down, as it is read, are the grip's -Y and -Z */
|
||||
static const XrQuaternionf layer_in_grip = { 0.5f, -0.5f, -0.5f, 0.5f };
|
||||
const XrVector3f offset = { -WRIST_ABOVE_HAND, -WRIST_DOWN_HANDLE - submit->wrist_right,
|
||||
WRIST_BEHIND_PALM - submit->wrist_down };
|
||||
/* the layer's axes in the left grip's: x = -Y, y = +Z, z = -X, so the
|
||||
layer's right and down, as it is read, are the grip's -Y and -Z; in the
|
||||
right grip's x = +Y, y = +Z, z = +X (the mirror image, read the right
|
||||
way round: its x turned back) */
|
||||
static const XrQuaternionf layer_in_left_grip = { 0.5f, -0.5f, -0.5f, 0.5f };
|
||||
static const XrQuaternionf layer_in_right_grip = { 0.5f, 0.5f, 0.5f, 0.5f };
|
||||
int right = submit->wrist_hand == HALO_XR_HAND_RIGHT;
|
||||
const XrPosef *grip = &xr.grips[right ? HALO_XR_HAND_RIGHT : HALO_XR_HAND_LEFT];
|
||||
const XrVector3f offset = { right ? WRIST_ABOVE_HAND : -WRIST_ABOVE_HAND,
|
||||
-WRIST_DOWN_HANDLE - submit->wrist_right, WRIST_BEHIND_PALM - submit->wrist_down };
|
||||
const XrVector3f layer_normal = { 0.0f, 0.0f, 1.0f };
|
||||
/* clockwise as read: about the layer's normal, negatively */
|
||||
float half_turn = -submit->wrist_turn * WRIST_PI / 360.0f;
|
||||
/* clockwise as read: about the layer's normal, negatively (the mirror
|
||||
image's the other way) */
|
||||
float half_turn = (right ? 1.0f : -1.0f) * submit->wrist_turn * WRIST_PI / 360.0f;
|
||||
XrQuaternionf turn = { 0.0f, 0.0f, sinf(half_turn), cosf(half_turn) };
|
||||
XrQuaternionf unturned;
|
||||
XrVector3f moved, normal, to_eyes;
|
||||
float distance;
|
||||
|
||||
if (!xr.left_grip_valid)
|
||||
if (!xr.grips_valid[right ? HALO_XR_HAND_RIGHT : HALO_XR_HAND_LEFT])
|
||||
return 0;
|
||||
quaternion_rotate_vector(&xr.left_grip.orientation, &offset, &moved);
|
||||
pose->position.x = xr.left_grip.position.x + moved.x;
|
||||
pose->position.y = xr.left_grip.position.y + moved.y;
|
||||
pose->position.z = xr.left_grip.position.z + moved.z;
|
||||
quaternion_multiply(&xr.left_grip.orientation, &layer_in_grip, &unturned);
|
||||
quaternion_rotate_vector(&grip->orientation, &offset, &moved);
|
||||
pose->position.x = grip->position.x + moved.x;
|
||||
pose->position.y = grip->position.y + moved.y;
|
||||
pose->position.z = grip->position.z + moved.z;
|
||||
quaternion_multiply(&grip->orientation, right ? &layer_in_right_grip : &layer_in_left_grip, &unturned);
|
||||
quaternion_multiply(&unturned, &turn, &pose->orientation);
|
||||
|
||||
quaternion_rotate_vector(&pose->orientation, &layer_normal, &normal);
|
||||
@@ -1555,7 +1560,7 @@ int host_xr_begin_frame(struct halo_xr_frame *frame)
|
||||
pose_from_xr(&frame->head, &head.pose);
|
||||
xr.head = head.pose;
|
||||
}
|
||||
xr.left_grip_valid = 0;
|
||||
xr.grips_valid[HALO_XR_HAND_LEFT] = xr.grips_valid[HALO_XR_HAND_RIGHT] = 0;
|
||||
if (xr.focused)
|
||||
hands_read(frame);
|
||||
return 1;
|
||||
@@ -2047,6 +2052,34 @@ void host_xr_set_vignette(float strength)
|
||||
xr.vignette = strength < 0.0f ? 0.0f : strength > 1.0f ? 1.0f : strength;
|
||||
}
|
||||
|
||||
/* the VR options' refresh rates: those the runtime offers (none where it
|
||||
lets none be chosen, as SteamVR, whose rate is SteamOS's), and the one it
|
||||
runs at, by XR_FB_display_refresh_rate or else by its frames' period */
|
||||
int host_xr_refresh_rates(float *rates, int maximum, float *current)
|
||||
{
|
||||
float offered[16];
|
||||
uint32_t count = 0, index;
|
||||
|
||||
*current = 0.0f;
|
||||
if (!xr.initialized)
|
||||
return 0;
|
||||
if (xr.has_refresh_rate)
|
||||
xr.get_refresh_rate(xr.session, current);
|
||||
if (*current <= 0.0f && xr.frame_state.predictedDisplayPeriod > 0)
|
||||
*current = 1e9f / (float)xr.frame_state.predictedDisplayPeriod;
|
||||
if (!xr.has_refresh_rate || !XR_SUCCEEDED(xr.enumerate_refresh_rates(xr.session, 16, &count, offered)))
|
||||
return 0;
|
||||
for (index = 0; index < count && (int)index < maximum; index++)
|
||||
rates[index] = offered[index];
|
||||
return (int)index;
|
||||
}
|
||||
|
||||
void host_xr_set_refresh_rate(float wanted)
|
||||
{
|
||||
if (xr.initialized)
|
||||
refresh_rate_choose(wanted);
|
||||
}
|
||||
|
||||
void host_xr_haptic(int hand, float amplitude, float seconds)
|
||||
{
|
||||
XrHapticActionInfo information = { XR_TYPE_HAPTIC_ACTION_INFO };
|
||||
|
||||
@@ -61,6 +61,8 @@ host_xr_end_frame
|
||||
host_xr_haptic
|
||||
host_xr_set_vignette
|
||||
host_xr_copy_layer_array
|
||||
host_xr_refresh_rates
|
||||
host_xr_set_refresh_rate
|
||||
host_android_path
|
||||
|
||||
host_errno
|
||||
@@ -24,7 +24,7 @@ enum
|
||||
HALO_XR_LAYER_EYE_LEFT = 0,
|
||||
HALO_XR_LAYER_EYE_RIGHT = 1,
|
||||
HALO_XR_LAYER_OVERLAY = 2, /* HUD, menus, cinematics: a flat quad */
|
||||
HALO_XR_LAYER_WRIST = 3, /* the motion tracker, on the left wrist */
|
||||
HALO_XR_LAYER_WRIST = 3, /* the motion tracker, on the free hand's 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 */
|
||||
@@ -155,15 +155,18 @@ struct halo_xr_submit
|
||||
float overlay_width; /* metres; the height follows from 4:3 */
|
||||
/* the screen's placement in LOCAL space (HALO_XR_OVERLAY_SCREEN) */
|
||||
struct halo_xr_pose screen;
|
||||
/* the wrist layer was filled: shown on the back of the left wrist,
|
||||
this wide (metres), while the wrist is turned to the eyes */
|
||||
/* the wrist layer was filled: shown on the back of the left wrist (of
|
||||
the right one, left-handed: wrist_hand, a HALO_XR_HAND_*), this wide
|
||||
(metres), while the wrist is turned to the eyes */
|
||||
int wrist;
|
||||
float wrist_size;
|
||||
/* its placement as the wrist turned to the eyes reads it: turned this
|
||||
many degrees clockwise, and moved this far right and down (metres) */
|
||||
/* its placement as the left wrist turned to the eyes reads it: turned
|
||||
this many degrees clockwise, and moved this far right and down (metres;
|
||||
on the right wrist, the mirror image) */
|
||||
float wrist_turn;
|
||||
float wrist_right;
|
||||
float wrist_down;
|
||||
int wrist_hand;
|
||||
/* the scope layer was filled: a disc this wide (metres), here in LOCAL
|
||||
space, facing back along the weapon */
|
||||
int scope;
|
||||
|
||||
@@ -3,19 +3,22 @@ NETWORK_VR.C
|
||||
|
||||
VR players' hands for the other machines: an extension of the distributed
|
||||
netcode (port/linux/NETCODE.md, network_distributed.c). A VR player's
|
||||
weapon aims where the right controller points and fires from the hand, and
|
||||
the left hand holds a grenade and throws it its own way (port/linux/src/
|
||||
vr.c); the input the netcode relays has only where the head looks, so the
|
||||
other machines would show that player aiming and throwing where they look.
|
||||
weapon aims where the weapon hand's controller points and fires from the
|
||||
hand, and the free hand holds a grenade and throws it its own way
|
||||
(port/linux/src/vr.c; the right hand and the left, or left-handed the other
|
||||
way round); the input the netcode relays has only where the head looks, so
|
||||
the other machines would show that player aiming and throwing where they
|
||||
look.
|
||||
|
||||
Every tick, a machine with a VR player sends the host that player's hands
|
||||
(_distributed_message_vr_poses, unreliable): where the weapon aims, where
|
||||
its muzzle is from the unit's camera, whether the left hand holds a
|
||||
grenade, and the last throw (from where, which way, how hard) for a second
|
||||
after it. The host keeps them, its own VR players' too, and sends each
|
||||
client those of the players of other machines. A machine drives a VR
|
||||
player of another (players.c, weapons.c, units.c) as long as their hands
|
||||
keep coming, else as before.
|
||||
its muzzle is from the unit's camera (whichever hand holds it: the others
|
||||
see shots leave the left hand of a left-handed player), whether the free
|
||||
hand holds a grenade, and the last throw (from where, which way, how hard)
|
||||
for a second after it. The host keeps them, its own VR players' too, and
|
||||
sends each client those of the players of other machines. A machine drives
|
||||
a VR player of another (players.c, weapons.c, units.c) as long as their
|
||||
hands keep coming, else as before.
|
||||
|
||||
What the hands decide is only how the game looks: damage is the shooter's
|
||||
report, which the host checks as any other (network_damage.c).
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
VR_GRAPHICS.C
|
||||
|
||||
The VR graphics presets (vr.graphics, the VR options' "Graphics" row): which
|
||||
of the game's costlier effects are drawn, for headsets with little time to
|
||||
spare (the Steam Frame spends most of its frame in its GL driver: fewer
|
||||
draws help it most; the Quest 3 holds 90 Hz with all of them).
|
||||
|
||||
- "high", the default: everything, as before;
|
||||
- "medium": no object shadows, environment reflections or lens flares;
|
||||
- "low": nor specular light, bump maps, grass and other detail objects,
|
||||
the screen's fog layer, contrails, weather or camouflage's second pass;
|
||||
- "max": "high", the models lit for each pixel and the shadows drawn at
|
||||
512x512 (d3d8_gl.c asks halo_vr_graphics).
|
||||
|
||||
Each effect is a switch the game has already: the rasterizer's console
|
||||
variables (rasterizer_debug_options) and render.c's effect switches, after
|
||||
HaloCE-Quest-VR's vr_graphics.c (CC0). Scripts and the console set some of
|
||||
them (render_effects turns particles off in some cutscenes): a switch is
|
||||
drawn only while both the game and the preset want it. A change the game
|
||||
made since the last frame is taken as its wish, kept and combined with the
|
||||
preset's. Playing in another's game, a client draws grass, lens flares and
|
||||
the screen's fog as the host's rules have it (cheats.c), whatever the
|
||||
preset; the reductions it does keep there, cheats.c leaves alone
|
||||
(vr_graphics_reduces).
|
||||
|
||||
What each costs: shadows (each object's map, blur and projection: draws),
|
||||
specular light and reflections (passes of the level's geometry: draws and
|
||||
fill), detail objects (many small draws), lens flares (their visibility
|
||||
tests), contrails and weather (particles), bump maps, the fog layer and
|
||||
camouflage's pass (the GPU's fill).
|
||||
*/
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
|
||||
#include "cseries.h"
|
||||
#include "rasterizer/rasterizer_console_vars.h"
|
||||
#include "networking/network_game_globals.h"
|
||||
#include "halo_vr.h"
|
||||
|
||||
/* source/render/render.c, render_objects.c; source/effects/
|
||||
weather_particle_systems.c */
|
||||
extern boolean render_shadows;
|
||||
extern boolean render_contrails_enabled;
|
||||
extern boolean render_weather_particle_systems_enabled;
|
||||
extern boolean weather;
|
||||
|
||||
void platform_log(char const *format, ...);
|
||||
|
||||
/* an effect: whether each preset draws it (low, medium; high and max draw
|
||||
everything), whether a client in another's game draws it anyway, and the
|
||||
game's switches it governs */
|
||||
struct vr_graphics_effect
|
||||
{
|
||||
char const *name;
|
||||
boolean preset[2];
|
||||
boolean host_rules;
|
||||
boolean *switches[2];
|
||||
};
|
||||
|
||||
static struct vr_graphics_effect vr_graphics_effects[] =
|
||||
{
|
||||
{ "shadows", { FALSE, FALSE }, FALSE,
|
||||
{ &render_shadows, &rasterizer_debug_options.draw_environment_shadows } },
|
||||
{ "specular", { FALSE, TRUE }, FALSE,
|
||||
{ &rasterizer_debug_options.draw_environment_specular_lights,
|
||||
&rasterizer_debug_options.draw_environment_specular_lightmaps } },
|
||||
{ "reflections", { FALSE, FALSE }, FALSE,
|
||||
{ &rasterizer_debug_options.draw_environment_reflections, NULL } },
|
||||
{ "bump maps", { FALSE, TRUE }, FALSE,
|
||||
{ &rasterizer_debug_options.bump_mapping_enabled, NULL } },
|
||||
{ "detail objects", { FALSE, TRUE }, TRUE,
|
||||
{ &rasterizer_debug_options.draw_detail_objects, NULL } },
|
||||
{ "lens flares", { FALSE, FALSE }, TRUE,
|
||||
{ &rasterizer_debug_options.draw_lens_flares, NULL } },
|
||||
{ "screen fog", { FALSE, TRUE }, TRUE,
|
||||
{ &rasterizer_debug_options.draw_environment_fog_screen, NULL } },
|
||||
{ "contrails", { FALSE, TRUE }, FALSE,
|
||||
{ &render_contrails_enabled, NULL } },
|
||||
{ "weather", { FALSE, TRUE }, FALSE,
|
||||
{ &weather, &render_weather_particle_systems_enabled } },
|
||||
{ "camouflage pass", { FALSE, TRUE }, FALSE,
|
||||
{ &rasterizer_debug_options.active_camouflage_multipass_enabled, NULL } },
|
||||
};
|
||||
|
||||
#define NUMBER_OF_VR_GRAPHICS_EFFECTS (sizeof(vr_graphics_effects) / sizeof(vr_graphics_effects[0]))
|
||||
#define VR_GRAPHICS_SWITCHES (sizeof(vr_graphics_effects[0].switches) / sizeof(vr_graphics_effects[0].switches[0]))
|
||||
|
||||
static struct
|
||||
{
|
||||
boolean started;
|
||||
int preset;
|
||||
boolean client;
|
||||
/* whether the preset allows each effect; what the game wants of each
|
||||
switch, and what was written last frame */
|
||||
boolean allowed[NUMBER_OF_VR_GRAPHICS_EFFECTS];
|
||||
boolean wanted[NUMBER_OF_VR_GRAPHICS_EFFECTS][VR_GRAPHICS_SWITCHES];
|
||||
boolean written[NUMBER_OF_VR_GRAPHICS_EFFECTS][VR_GRAPHICS_SWITCHES];
|
||||
} vr_graphics;
|
||||
|
||||
static void vr_graphics_choose(
|
||||
int preset,
|
||||
boolean client)
|
||||
{
|
||||
static char const *const names[] = { "low", "medium", "high", "max" };
|
||||
unsigned int index;
|
||||
|
||||
vr_graphics.preset = preset;
|
||||
vr_graphics.client = client;
|
||||
for (index = 0; index < NUMBER_OF_VR_GRAPHICS_EFFECTS; index++)
|
||||
{
|
||||
struct vr_graphics_effect const *effect = &vr_graphics_effects[index];
|
||||
|
||||
vr_graphics.allowed[index] = preset >= HALO_VR_GRAPHICS_HIGH || effect->preset[preset] ||
|
||||
(client && effect->host_rules);
|
||||
}
|
||||
platform_log("VR: graphics %s%s", names[preset], client ? " (in another's game)" : "");
|
||||
}
|
||||
|
||||
/* each frame, before it is drawn (render.c) */
|
||||
void vr_graphics_update(
|
||||
void)
|
||||
{
|
||||
int preset = halo_vr_graphics();
|
||||
boolean client = network_game_distributed_client();
|
||||
unsigned int index, which;
|
||||
|
||||
if (!vr_graphics.started)
|
||||
{
|
||||
/* the game's switches as it starts are its wishes */
|
||||
for (index = 0; index < NUMBER_OF_VR_GRAPHICS_EFFECTS; index++)
|
||||
{
|
||||
for (which = 0; which < VR_GRAPHICS_SWITCHES && vr_graphics_effects[index].switches[which]; which++)
|
||||
{
|
||||
vr_graphics.wanted[index][which] = *vr_graphics_effects[index].switches[which];
|
||||
vr_graphics.written[index][which] = *vr_graphics_effects[index].switches[which];
|
||||
}
|
||||
}
|
||||
vr_graphics.started = TRUE;
|
||||
vr_graphics_choose(preset, client);
|
||||
}
|
||||
else if (preset != vr_graphics.preset || client != vr_graphics.client)
|
||||
{
|
||||
vr_graphics_choose(preset, client);
|
||||
}
|
||||
for (index = 0; index < NUMBER_OF_VR_GRAPHICS_EFFECTS; index++)
|
||||
{
|
||||
for (which = 0; which < VR_GRAPHICS_SWITCHES && vr_graphics_effects[index].switches[which]; which++)
|
||||
{
|
||||
boolean *game_switch = vr_graphics_effects[index].switches[which];
|
||||
boolean value;
|
||||
|
||||
/* (the game, a script, the console changed it since: its wish) */
|
||||
if (*game_switch != vr_graphics.written[index][which])
|
||||
vr_graphics.wanted[index][which] = *game_switch;
|
||||
value = vr_graphics.wanted[index][which] && vr_graphics.allowed[index];
|
||||
*game_switch = value;
|
||||
vr_graphics.written[index][which] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* whether the preset keeps this switch of the game's off now (cheats.c, a
|
||||
client's rules: those it may keep off) */
|
||||
boolean vr_graphics_reduces(
|
||||
boolean const *game_switch)
|
||||
{
|
||||
unsigned int index, which;
|
||||
|
||||
if (!vr_graphics.started)
|
||||
return FALSE;
|
||||
for (index = 0; index < NUMBER_OF_VR_GRAPHICS_EFFECTS; index++)
|
||||
{
|
||||
for (which = 0; which < VR_GRAPHICS_SWITCHES && vr_graphics_effects[index].switches[which]; which++)
|
||||
{
|
||||
if (vr_graphics_effects[index].switches[which] == game_switch)
|
||||
return !vr_graphics.allowed[index];
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -88,13 +88,14 @@ degrees on an axis (the other axis 0); nonzero if it has. The game counts
|
||||
it as looking around (player_control.c's action tests). */
|
||||
int halo_vr_look_delta(float *yaw, float *pitch);
|
||||
|
||||
/* The weapon in the right hand (vr.aim_with = "controller"; each returns 0,
|
||||
and the game does as before, when the hand is not tracked):
|
||||
/* The weapon in the right hand, or the left one (vr.handedness; vr.aim_with
|
||||
= "controller"; each returns 0, and the game does as before, when the hand
|
||||
is not tracked):
|
||||
- the direction the player's weapon aims, where the controller points (the
|
||||
body and the view keep facing where the head looks);
|
||||
- where its shots start, as an offset from the unit's camera (world units);
|
||||
- the camera the first-person weapon model is posed from, so that it lies
|
||||
in the hand;
|
||||
in the hand (in model space, below);
|
||||
- the aiming laser's start and direction; */
|
||||
int halo_vr_aim_vector(short local_player_index, float vector[3]);
|
||||
int halo_vr_weapon_origin_offset(short local_player_index, float offset[3]);
|
||||
@@ -104,9 +105,18 @@ int halo_vr_weapon_origin_offset(short local_player_index, float offset[3]);
|
||||
int halo_vr_weapon_origin(short local_player_index, float origin[3]);
|
||||
int halo_vr_weapon_camera(short local_player_index, float position[3], float forward[3], float up[3]);
|
||||
int halo_vr_laser(short local_player_index, float start[3], float direction[3]);
|
||||
/* Model space: the first-person model (first_person_weapons.c) is always
|
||||
posed as the right hand's. Left-handed, it is posed in a mirror image of
|
||||
the room and drawn mirrored back (its triangles' winding turned over); the
|
||||
mirror: a point on it (world units) and its normal, or 0 when it is not
|
||||
mirrored. What first_person_weapons.c and vr.c exchange about the model
|
||||
is in model space: the weapon camera, the free hand, the foregrip, the
|
||||
fingers (0 the model's left hand, the free one), the barrel and the laser
|
||||
along it. */
|
||||
int halo_vr_first_person_mirror(short local_player_index, float point[3], float normal[3]);
|
||||
/* the laser for this frame, along the barrel (first_person_weapons.c: while
|
||||
an animation turns the weapon, as in a reload), and the laser at the ready,
|
||||
where the controller aims */
|
||||
an animation turns the weapon, as in a reload; model space), and the laser
|
||||
at the ready, where the controller aims (in the room) */
|
||||
void halo_vr_set_laser(short local_player_index, const float start[3], const float direction[3]);
|
||||
int halo_vr_ready_laser(short local_player_index, float start[3], float direction[3]);
|
||||
/* The arms (interface/first_person_weapons.c):
|
||||
@@ -114,16 +124,16 @@ int halo_vr_ready_laser(short local_player_index, float start[3], float directio
|
||||
and the torso's flat heading (which follows the head beyond a few
|
||||
degrees, and the hands; the stick's turns turn it at once), from which
|
||||
the shoulders hang;
|
||||
- the left hand's pose;
|
||||
- the left hand on the weapon: given where the model's left hand holds it
|
||||
- the free hand's pose (the left one, left-handed the right; model space);
|
||||
- the free hand on the weapon: given where the model's left hand holds it
|
||||
(world units) and the line from its right hand to its left in the
|
||||
weapon's forward, right and up, whether the left hand grips it; then the
|
||||
weapon's forward, right and up, whether the free hand grips it; then the
|
||||
weapon aims along both hands; */
|
||||
int halo_vr_body_frame(short local_player_index, float head[3], float neck[3], float forward[3]);
|
||||
int halo_vr_left_hand(short local_player_index, float position[3], float forward[3], float up[3]);
|
||||
int halo_vr_free_hand(short local_player_index, float position[3], float forward[3], float up[3]);
|
||||
int halo_vr_two_hand(short local_player_index, const float foregrip[3], const float reference[3]);
|
||||
/* - the fingers of a hand (0 the left, 1 the right), from the controller's trigger,
|
||||
grip and touch: the thumb, index, middle finger and the last two, each
|
||||
/* - the fingers of a hand of the model (0 the left, the free hand; 1 the
|
||||
right, the weapon's), from the controller's trigger, grip and touch: the thumb, index, middle finger and the last two, each
|
||||
curled 0 (straight) to 1; 0 when the hand is not tracked or vr.fingers
|
||||
is off, else HALO_VR_FINGERS_CURLED, and HALO_VR_FINGERS_TOUCH too when
|
||||
the controller tells where the fingers rest (else a finger off the
|
||||
@@ -152,17 +162,21 @@ enum
|
||||
int halo_vr_body_mode(void);
|
||||
/* a hand has just been thrust forward: a melee attack (xinput_sdl.c) */
|
||||
int halo_vr_melee(void);
|
||||
/* a hand has just tapped the head (vr.flashlight_gesture): the flashlight's
|
||||
button, for a moment (xinput_sdl.c) */
|
||||
int halo_vr_flashlight_tap(void);
|
||||
/* the weight of the melee attack under way, from the swing's speed (0..1;
|
||||
0 with none): the game scales melee damage by the player's run instead,
|
||||
and in VR a player punches standing (units.c) */
|
||||
float halo_vr_melee_strength(void);
|
||||
/* The grenade (units.c): whether the left trigger holds it in the hand; and
|
||||
/* The grenade (units.c): whether the free hand's trigger holds it in the
|
||||
hand; and
|
||||
as it let go, whether the hand threw it: from where (world units), which
|
||||
way (the game's axes) and how hard (0..1 of the game's throw) */
|
||||
int halo_vr_grenade_held(short local_player_index);
|
||||
int halo_vr_grenade_throw(short local_player_index, float origin[3], float direction[3], float *strength);
|
||||
/* where the held grenade is drawn (render_objects.c): in the left palm, and
|
||||
at what size */
|
||||
/* where the held grenade is drawn (first_person_weapons.c): in the free
|
||||
hand's palm, and at what size */
|
||||
int halo_vr_grenade_in_hand(short local_player_index, float position[3], float forward[3], float up[3],
|
||||
float *scale);
|
||||
/* The scope (render.c): zoomed in by magnification, the camera for the
|
||||
@@ -193,9 +207,9 @@ void halo_vr_capture_names(void);
|
||||
void halo_vr_set_scope_raise(float metres);
|
||||
void halo_vr_capture_scope(float left, float top, float right, float bottom);
|
||||
/* where the weapon's gun node is as drawn, at the ready (world units;
|
||||
first_person_weapons.c, each frame): shots, the crosshair and the laser
|
||||
start there; and the direction its barrel points in the weapon camera's
|
||||
frame (forward, left, up), which the camera is turned to aim */
|
||||
first_person_weapons.c, each frame; model space): shots, the crosshair and
|
||||
the laser start there; and the direction its barrel points in the weapon
|
||||
camera's frame (forward, left, up), which the camera is turned to aim */
|
||||
void halo_vr_set_barrel(short local_player_index, const float world[3], const float direction[3]);
|
||||
/* how far, in world units, the weapon's aim runs before it hits something
|
||||
(render.c, each frame); the crosshair floats there */
|
||||
@@ -211,7 +225,8 @@ void halo_vr_capture_crosshair(void);
|
||||
/* Vehicles (player_control.c, each tick): the seat the player sits in and
|
||||
its vehicle's heading (yaw, radians). Seated, the body turns with the
|
||||
vehicle; a driver who steers by facing (HALO_VR_SEAT_STEER) steers with the
|
||||
right stick, else the right controller aims (HALO_VR_SEAT_AIM). And each
|
||||
turning stick, else the weapon hand's controller aims (HALO_VR_SEAT_AIM).
|
||||
And each
|
||||
frame (render.c) the heading as drawn, between ticks. */
|
||||
enum
|
||||
{
|
||||
@@ -237,6 +252,59 @@ int halo_vr_wheel_held(void);
|
||||
/* the controllers' layout (HALO_XR_LAYOUT_*: 0 the Quest's, 1 the Steam
|
||||
Frame's), for what the game tells the player */
|
||||
int halo_vr_controller_layout(void);
|
||||
/* the hand that holds the weapon (HALO_XR_HAND_*: 1 the right, 0 the left,
|
||||
vr.handedness) */
|
||||
int halo_vr_weapon_hand(void);
|
||||
/* The game's actions on the controllers' buttons (vr.button_*; the VR
|
||||
options' BUTTONS page): each action on one of seven buttons, named as
|
||||
right-handed (A and B on the right controller, X and Y, the Quest's, on
|
||||
the left; the move stick's click, the turning stick's, the weapon hand's
|
||||
grip); left-handed with vr.mirror_controls, their mirror images. The
|
||||
actions are numbered by the button each has by default. The triggers, the
|
||||
free hand's grip, the menu button and the Steam Frame's bumpers, D-pad and
|
||||
View button keep theirs; the menus keep the buttons as they are. */
|
||||
enum
|
||||
{
|
||||
HALO_VR_INPUT_A = 0,
|
||||
HALO_VR_INPUT_B,
|
||||
HALO_VR_INPUT_X,
|
||||
HALO_VR_INPUT_Y,
|
||||
HALO_VR_INPUT_MOVE_STICK,
|
||||
HALO_VR_INPUT_TURN_STICK,
|
||||
HALO_VR_INPUT_GRIP,
|
||||
HALO_VR_INPUT_COUNT,
|
||||
|
||||
HALO_VR_ACTION_JUMP = HALO_VR_INPUT_A,
|
||||
HALO_VR_ACTION_LIGHT = HALO_VR_INPUT_B, /* a tap the flashlight; held, switch grenades */
|
||||
HALO_VR_ACTION_ACTION = HALO_VR_INPUT_X, /* action, reload */
|
||||
HALO_VR_ACTION_WEAPON = HALO_VR_INPUT_Y, /* switch weapon */
|
||||
HALO_VR_ACTION_CROUCH = HALO_VR_INPUT_MOVE_STICK,
|
||||
HALO_VR_ACTION_ZOOM = HALO_VR_INPUT_TURN_STICK,
|
||||
HALO_VR_ACTION_MELEE = HALO_VR_INPUT_GRIP,
|
||||
HALO_VR_ACTION_COUNT = HALO_VR_INPUT_COUNT,
|
||||
};
|
||||
/* an action's setting ("vr.button_jump"), a button's value in it ("a"),
|
||||
and the button an action is on, as set */
|
||||
const char *halo_vr_action_setting(int action);
|
||||
const char *halo_vr_input_value(int input);
|
||||
int halo_vr_action_input(int action);
|
||||
/* the graphics preset (vr.graphics; HALO_VR_GRAPHICS_HIGH outside VR): which
|
||||
effects are drawn (port/linux/game/vr_graphics.c), and with "max" the
|
||||
models lit for each pixel and larger shadows (d3d8_gl.c) */
|
||||
enum
|
||||
{
|
||||
HALO_VR_GRAPHICS_LOW = 0,
|
||||
HALO_VR_GRAPHICS_MEDIUM,
|
||||
HALO_VR_GRAPHICS_HIGH,
|
||||
HALO_VR_GRAPHICS_MAX,
|
||||
};
|
||||
int halo_vr_graphics(void);
|
||||
/* the VR options: the refresh rates the headset offers (Hz, at most maximum;
|
||||
0 when it lets none be chosen, as SteamVR), and the one it runs at (0:
|
||||
unknown; vr.refresh_rate asks for one); and vr.resolution_scale as the app
|
||||
started (it takes a restart) */
|
||||
int halo_vr_refresh_rates(float *rates, int maximum, float *current);
|
||||
float halo_vr_started_resolution_scale(void);
|
||||
/* whether a seated player's view stays in first person (director.c) */
|
||||
int halo_vr_vehicle_first_person(void);
|
||||
/* VR test aid (debug.vehicle_spawn): both sticks held in for a moment asks
|
||||
@@ -266,7 +334,7 @@ coming (each returns 0 otherwise, and for this machine's own players, and
|
||||
the game does as before):
|
||||
- where the weapon aims, on foot;
|
||||
- where its shots start (world units), from the unit's camera;
|
||||
- whether the left hand holds the grenade;
|
||||
- whether the free hand holds the grenade;
|
||||
- the hand's throw, once, as the grenade goes (as halo_vr_grenade_throw);
|
||||
and this machine's own VR player's throw, to send (units.c). */
|
||||
int halo_vr_network_aim(long player_index, float vector[3]);
|
||||
|
||||
@@ -281,6 +281,10 @@ static long shadow_scale_choose(void)
|
||||
long resolution = config_integer("display.shadow_resolution");
|
||||
long scale = 1;
|
||||
|
||||
/* (VR's "max" graphics: 512 at least) */
|
||||
if (halo_vr_graphics() == HALO_VR_GRAPHICS_MAX && resolution < 512)
|
||||
resolution = 512;
|
||||
|
||||
while (scale < SHADOW_MAP_MAXIMUM_SCALE && SHADOW_MAP_SIZE * scale * 2 <= resolution)
|
||||
scale *= 2;
|
||||
return scale;
|
||||
@@ -3170,6 +3174,22 @@ static GLenum blend_equation(DWORD operation)
|
||||
}
|
||||
}
|
||||
|
||||
/* the model being drawn mirrors: its node matrices are left-handed (the
|
||||
left hand's first-person weapon in VR, first_person_weapons.c), and its
|
||||
triangles' winding is turned over (set by rasterizer_xbox.c as it sets them,
|
||||
after HaloCE-Quest-VR, CC0) */
|
||||
static int mirrored_skinning;
|
||||
|
||||
void d3d8_set_mirrored_skinning(int mirrored)
|
||||
{
|
||||
mirrored_skinning = mirrored != 0;
|
||||
}
|
||||
|
||||
int d3d8_mirrored_skinning(void)
|
||||
{
|
||||
return mirrored_skinning;
|
||||
}
|
||||
|
||||
static void apply_raster_state(BOOL has_depth)
|
||||
{
|
||||
DWORD *rs = D3D__RenderState;
|
||||
@@ -3305,6 +3325,8 @@ static void apply_raster_state(BOOL has_depth)
|
||||
#endif
|
||||
GLenum cull_mode = rs[D3DRS_CULLMODE] == rs[D3DRS_FRONTFACE] ? GL_FRONT : GL_BACK;
|
||||
|
||||
if (mirrored_skinning)
|
||||
front_face = front_face == GL_CW ? GL_CCW : GL_CW;
|
||||
if (gl_state.front_face != front_face)
|
||||
{
|
||||
gl_state.front_face = front_face;
|
||||
@@ -3416,9 +3438,10 @@ static void draw_flush(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* display.per_pixel_lighting: the model lighting programs' draws are lit for
|
||||
each pixel (nv2a_psh.c model_lighting), from shaders of their own; read
|
||||
again when a setting changes */
|
||||
/* display.per_pixel_lighting (or VR's "max" graphics, vr.graphics): the
|
||||
model lighting programs' draws are lit for each pixel (nv2a_psh.c
|
||||
model_lighting), from shaders of their own; read again when a setting
|
||||
changes */
|
||||
static BOOL per_pixel_lighting(void)
|
||||
{
|
||||
static unsigned long read_at = (unsigned long)-1;
|
||||
@@ -3427,7 +3450,7 @@ static BOOL per_pixel_lighting(void)
|
||||
if (read_at != config_changes())
|
||||
{
|
||||
read_at = config_changes();
|
||||
enabled = config_boolean("display.per_pixel_lighting") != 0;
|
||||
enabled = config_boolean("display.per_pixel_lighting") != 0 || halo_vr_graphics() == HALO_VR_GRAPHICS_MAX;
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ it exists, so that the player's edits and comments stay.
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -164,6 +165,13 @@ static const struct config_setting config_settings[] =
|
||||
{ "vr.refresh_rate", _config_real, "90.0", "HALO_VR_REFRESH_RATE", _environment_value, _platform_android,
|
||||
"The display refresh rate to ask the headset for, in Hz (72, 90, 120);\n"
|
||||
"it picks the nearest it has at or below. 0 for the highest." },
|
||||
{ "vr.graphics", _config_string, "\"high\"", "HALO_VR_GRAPHICS", _environment_value, _platform_android,
|
||||
"Which of the costlier effects are drawn: \"high\" all of them; \"medium\"\n"
|
||||
"no object shadows, environment reflections or lens flares; \"low\" nor\n"
|
||||
"specular light, bump maps, grass, the screen's fog, contrails, weather\n"
|
||||
"or camouflage's second pass (a client in another's game keeps grass,\n"
|
||||
"lens flares and fog); \"max\" all of them, the models lit for each\n"
|
||||
"pixel and shadows at 512x512." },
|
||||
{ "vr.positional_tracking", _config_boolean, "true", "HALO_VR_POSITIONAL", _environment_value, _platform_android,
|
||||
"Moving your head moves the view (leaning, ducking); false only turns it.\n"
|
||||
"The view recentres when play starts or resumes after a cinematic, and\n"
|
||||
@@ -180,8 +188,41 @@ static const struct config_setting config_settings[] =
|
||||
"Log the frame rate and where the frame time goes every five seconds\n"
|
||||
"(adb logcat -s halo)." },
|
||||
{ "vr.aim_with", _config_string, "\"controller\"", "HALO_VR_AIM_WITH", _environment_value, _platform_android,
|
||||
"\"controller\": the weapon is in your right hand and aims where it points,\n"
|
||||
"while you move and look with your head; \"head\": you aim where you look." },
|
||||
"\"controller\": the weapon is in your hand (vr.handedness) and aims where\n"
|
||||
"it points, while you move and look with your head; \"head\": you aim\n"
|
||||
"where you look." },
|
||||
{ "vr.handedness", _config_string, "\"right\"", "HALO_VR_HANDEDNESS", _environment_value, _platform_android,
|
||||
"The hand that holds the weapon: \"right\", or \"left\", which mirrors the\n"
|
||||
"weapon and the arms, throws grenades and grips the foregrip with the\n"
|
||||
"right hand, and fires with the left trigger." },
|
||||
{ "vr.mirror_controls", _config_boolean, "true", "HALO_VR_MIRROR_CONTROLS", _environment_value,
|
||||
_platform_android,
|
||||
"Left-handed, the sticks and buttons swap sides too: the right stick moves\n"
|
||||
"and the left one turns, X jumps and A reloads (on the Steam Frame the\n"
|
||||
"D-pad takes A, B, X and Y as their mirror image); false keeps them as\n"
|
||||
"right-handed. The menus keep their buttons either way." },
|
||||
{ "vr.button_jump", _config_string, "\"a\"", "HALO_VR_BUTTON_JUMP", _environment_value, _platform_android,
|
||||
"The button each of the game's actions is on (the VR options' BUTTONS\n"
|
||||
"page swaps them): \"a\", \"b\", \"x\", \"y\" (A and B on the right\n"
|
||||
"controller, X and Y the Quest's on the left; the Steam Frame has all\n"
|
||||
"four on the right), \"move_stick\" and \"turn_stick\" (their clicks),\n"
|
||||
"\"grip\" (the weapon hand's), named as right-handed: left-handed with\n"
|
||||
"mirror_controls, their mirror images. Jump," },
|
||||
{ "vr.button_light", _config_string, "\"b\"", "HALO_VR_BUTTON_LIGHT", _environment_value, _platform_android,
|
||||
"the flashlight (held: switch grenades)," },
|
||||
{ "vr.button_action", _config_string, "\"x\"", "HALO_VR_BUTTON_ACTION", _environment_value, _platform_android,
|
||||
"action and reload," },
|
||||
{ "vr.button_weapon", _config_string, "\"y\"", "HALO_VR_BUTTON_WEAPON", _environment_value, _platform_android,
|
||||
"switch weapon," },
|
||||
{ "vr.button_crouch", _config_string, "\"move_stick\"", "HALO_VR_BUTTON_CROUCH", _environment_value,
|
||||
_platform_android,
|
||||
"crouch," },
|
||||
{ "vr.button_zoom", _config_string, "\"turn_stick\"", "HALO_VR_BUTTON_ZOOM", _environment_value,
|
||||
_platform_android,
|
||||
"zoom" },
|
||||
{ "vr.button_melee", _config_string, "\"grip\"", "HALO_VR_BUTTON_MELEE", _environment_value, _platform_android,
|
||||
"and melee. The triggers, the free hand's grip and the menu button keep\n"
|
||||
"theirs, as do the menus." },
|
||||
{ "vr.laser", _config_boolean, "false", "HALO_VR_LASER", _environment_value, _platform_android,
|
||||
"A laser from the weapon to what it aims at (with aim_with = \"controller\")." },
|
||||
{ "vr.crosshair", _config_boolean, "true", "HALO_VR_CROSSHAIR", _environment_value, _platform_android,
|
||||
@@ -196,7 +237,7 @@ static const struct config_setting config_settings[] =
|
||||
{ "vr.weapon_down", _config_real, "0.14", "HALO_VR_WEAPON_DOWN", _environment_value, _platform_android,
|
||||
"See weapon_forward." },
|
||||
{ "vr.two_hand_reach", _config_real, "0.2", "HALO_VR_TWO_HAND_REACH", _environment_value, _platform_android,
|
||||
"How near, in metres, the left hand must be to the weapon's foregrip for\n"
|
||||
"How near, in metres, the free hand must be to the weapon's foregrip for\n"
|
||||
"its grip button to take hold of it with both hands." },
|
||||
{ "vr.body", _config_string, "\"arms\"", "HALO_VR_BODY", _environment_value, _platform_android,
|
||||
"What of your body is drawn with the weapon: \"arms\", the arms and hands\n"
|
||||
@@ -210,19 +251,26 @@ static const struct config_setting config_settings[] =
|
||||
{ "vr.arm_ik", _config_boolean, "true", "HALO_VR_ARM_IK", _environment_value, _platform_android,
|
||||
"The free hand's arm bends at the elbow to reach it from the shoulder;\n"
|
||||
"false keeps the arm's shape as on the weapon, pointed at the shoulder." },
|
||||
{ "vr.flashlight_gesture", _config_boolean, "true", "HALO_VR_FLASHLIGHT_GESTURE", _environment_value,
|
||||
_platform_android,
|
||||
"Tapping the side or the top of your head with either hand (to it and\n"
|
||||
"away again) turns the flashlight on or off; the flashlight's button\n"
|
||||
"still does. Not while aiming through a scope, holding the weapon with\n"
|
||||
"both hands, holding or throwing a grenade, just after a melee, or with\n"
|
||||
"both hands at the head." },
|
||||
{ "vr.melee_swing_speed", _config_real, "2.0", "HALO_VR_MELEE_SWING", _environment_value, _platform_android,
|
||||
"Thrusting a hand forward faster than this, in metres per second, is a\n"
|
||||
"melee attack (the right grip is too); 0 turns it off." },
|
||||
"melee attack (the weapon hand's grip is too); 0 turns it off." },
|
||||
{ "vr.grenade_throw_speed", _config_real, "1.5", "HALO_VR_GRENADE_THROW", _environment_value, _platform_android,
|
||||
"A grenade is held while the left trigger is, and thrown as it lets go:\n"
|
||||
"along the hand's throw, when the hand moved faster than this (metres per\n"
|
||||
"second; full strength at 4), else as the game throws it. 0 turns the\n"
|
||||
"hand's throw off." },
|
||||
"A grenade is held while the free hand's trigger is, and thrown as it\n"
|
||||
"lets go: along the hand's throw, when the hand moved faster than this\n"
|
||||
"(metres per second; full strength at 4), else as the game throws it. 0\n"
|
||||
"turns the hand's throw off." },
|
||||
{ "vr.grenade_scale", _config_real, "0.55", "HALO_VR_GRENADE_SCALE", _environment_value, _platform_android,
|
||||
"The size the grenade held in the left hand is drawn at (1 as in the game)." },
|
||||
"The size the grenade held in the free hand is drawn at (1 as in the game)." },
|
||||
{ "vr.grenade_right", _config_real, "0.055", "HALO_VR_GRENADE_RIGHT", _environment_value, _platform_android,
|
||||
"Where the held grenade is drawn, in metres from the left controller's\n"
|
||||
"grip: towards the palm (right),", },
|
||||
"Where the held grenade is drawn, in metres from the free controller's\n"
|
||||
"grip: towards the palm (the left hand's right),", },
|
||||
{ "vr.grenade_forward", _config_real, "0.01", "HALO_VR_GRENADE_FORWARD", _environment_value, _platform_android,
|
||||
"the grip's forward (through the fist, towards the index finger),", },
|
||||
{ "vr.grenade_down", _config_real, "0.01", "HALO_VR_GRENADE_DOWN", _environment_value, _platform_android,
|
||||
@@ -285,6 +333,13 @@ static const struct config_setting config_settings[] =
|
||||
{ "vr.comfort_vignette", _config_real, "0.7", "HALO_VR_COMFORT_VIGNETTE", _environment_value, _platform_android,
|
||||
"How far the view darkens from its edges while a vehicle turns you\n"
|
||||
"(0 never, 1 to a small window)." },
|
||||
{ "vr.foot_vignette", _config_string, "\"off\"", "HALO_VR_FOOT_VIGNETTE", _environment_value, _platform_android,
|
||||
"On foot, the view darkens from its edges too: \"turning\" while the stick\n"
|
||||
"turns you smoothly (smooth_turn), \"moving\" while a stick turns or moves\n"
|
||||
"you, as far as it is pushed; \"off\" never." },
|
||||
{ "vr.foot_vignette_strength", _config_real, "0.7", "HALO_VR_FOOT_VIGNETTE_STRENGTH", _environment_value,
|
||||
_platform_android,
|
||||
"How far it darkens then (as comfort_vignette)." },
|
||||
{ "vr.motion_tracker_on_wrist", _config_boolean, "true", "HALO_VR_MOTION_TRACKER_WRIST", _environment_value,
|
||||
_platform_android,
|
||||
"Show the motion tracker on the back of the left wrist, like a watch (turn\n"
|
||||
@@ -305,9 +360,11 @@ static const struct config_setting config_settings[] =
|
||||
{ "vr.smooth_turn", _config_boolean, "false", "HALO_VR_SMOOTH_TURN", _environment_value, _platform_android,
|
||||
"The right stick turns smoothly; false turns in steps (snap_turn_degrees)." },
|
||||
{ "vr.snap_turn_degrees", _config_real, "30.0", "HALO_VR_SNAP_TURN", _environment_value, _platform_android,
|
||||
"How far a flick of the right stick turns." },
|
||||
"How far a flick of the right stick turns, in degrees (the VR options step\n"
|
||||
"through 10 to 45 by 5, 60, 75 and 90)." },
|
||||
{ "vr.smooth_turn_speed", _config_real, "120.0", "HALO_VR_SMOOTH_TURN_SPEED", _environment_value, _platform_android,
|
||||
"Degrees per second the right stick turns at, fully pushed, with smooth_turn." },
|
||||
"Degrees per second the right stick turns at, fully pushed, with smooth_turn\n"
|
||||
"(the VR options step through 30 to 150 by 15, then to 300 by 30)." },
|
||||
{ "vr.cinematics_in_3d", _config_boolean, "false", "HALO_VR_CINEMATICS_3D", _environment_value, _platform_android,
|
||||
"Show cinematics around you, from the cinematic camera; false shows them\n"
|
||||
"on the screen in front of you (easier on the stomach)." },
|
||||
@@ -554,6 +611,13 @@ static const struct config_setting config_settings[] =
|
||||
"The headset's layer copies: 1 deferred (no waits for the GL thread or the\n"
|
||||
"GPU in the middle of the frame), 0 each one restored and released at once,\n"
|
||||
"-1 as the runtime needs (deferred on SteamVR). Read when the app starts." },
|
||||
{ "debug.vr_options", _config_boolean, "false", "HALO_DEBUG_VR_OPTIONS", _environment_value, _platform_android,
|
||||
"Off the headset (the emulator), show the VR options panel on the main\n"
|
||||
"and pause menus all the same, for checking its pages." },
|
||||
{ "debug.mirror_first_person", _config_boolean, "false", "HALO_MIRROR_FIRST_PERSON", _environment_value,
|
||||
_platform_android,
|
||||
"Off the headset (flat), the first-person weapon drawn mirrored, as the\n"
|
||||
"left hand's is in VR: a test aid for what reads mirrored there. Read once." },
|
||||
{ "debug.test_input", _config_string, "\"\"", "HALO_TEST_INPUT", _environment_value, _platform_all,
|
||||
"\"bot:<seed>\" plays controller 1 with a scripted pattern (automated\n"
|
||||
"network tests); \"look:<seed>\" stands still, only turning and looking\n"
|
||||
@@ -695,13 +759,24 @@ static char *config_read_file(const char *path, size_t *size)
|
||||
static int config_write_file(const char *path, const char *text)
|
||||
{
|
||||
#ifdef HALO_ANDROID
|
||||
FILE *file = fopen(path, "wb");
|
||||
/* written beside it and renamed over it: a file the app may not write
|
||||
(one pushed by adb belongs to the shell) is replaced all the same, as the
|
||||
folder is the app's, and a write cut short leaves the old file whole */
|
||||
char temporary[1100];
|
||||
FILE *file;
|
||||
int written;
|
||||
|
||||
snprintf(temporary, sizeof(temporary), "%s.tmp", path);
|
||||
file = fopen(temporary, "wb");
|
||||
if (!file)
|
||||
return 0;
|
||||
written = fwrite(text, 1, strlen(text), file) == strlen(text);
|
||||
return fclose(file) == 0 && written;
|
||||
written = fclose(file) == 0 && written;
|
||||
if (written && rename(temporary, path) == 0)
|
||||
return 1;
|
||||
platform_log("settings: cannot replace %s (%s)", path, strerror(errno));
|
||||
remove(temporary);
|
||||
return 0;
|
||||
#else
|
||||
return SDL_SaveFile(path, text, strlen(text));
|
||||
#endif
|
||||
|
||||
+676
-76
File diff suppressed because it is too large.
Load diff
@@ -840,7 +840,9 @@ In play, laid out for VR shooters rather than by position:
|
||||
|
||||
right trigger fire left trigger grenade: held in the hand, thrown as it lets go (vr.c)
|
||||
right grip melee (B) left grip hold the weapon with both hands (vr.c)
|
||||
(a hand thrust forward, vr.melee_swing_speed, is a melee attack too)
|
||||
(a hand thrust forward, vr.melee_swing_speed, is a melee attack too;
|
||||
a hand tapped on the side or top of the head, vr.flashlight_gesture,
|
||||
the flashlight)
|
||||
A jump X action, reload (X), as the game's prompts say
|
||||
B flashlight (white); held, switch grenade (black)
|
||||
Y switch weapon (Y)
|
||||
@@ -851,6 +853,19 @@ Holding a Warthog's wheel (vr.c), the right trigger is the throttle and the
|
||||
left one the brake (backwards, once stopped): the left stick pushed up or
|
||||
down as far, unless it is pushed further.
|
||||
|
||||
Left-handed (vr.handedness), vr.c hands the controllers over with the sides
|
||||
swapped where the hands' jobs are (halo_vr_controllers): the left trigger
|
||||
fires and the left grip strikes, the right ones hold and throw the grenade
|
||||
and grip the foregrip; and with vr.mirror_controls the sticks, bumpers and
|
||||
face buttons too (the right stick moves, X jumps, A reloads; on the Steam
|
||||
Frame the left D-pad takes A, B, X and Y). Here "right" and "left" are the
|
||||
sides so handed over.
|
||||
|
||||
The VR options' BUTTONS page (vr.button_*) moves jump, the flashlight,
|
||||
action, switch weapon, crouch, zoom and melee between A, B, X, Y, the
|
||||
stick clicks and the weapon hand's grip: vr.c hands each action's button
|
||||
over as the one above, so "A" here is the jump wherever it is.
|
||||
|
||||
In the menus the buttons are the Xbox's by position: A accepts, B goes back. */
|
||||
|
||||
#include "guest_host.h"
|
||||
@@ -858,6 +873,7 @@ In the menus the buttons are the Xbox's by position: A accepts, B goes back. */
|
||||
|
||||
int halo_vr_controllers(struct halo_xr_hand hands[HALO_XR_HAND_COUNT], int *menus);
|
||||
int halo_vr_wheel_held(void);
|
||||
int halo_vr_flashlight_tap(void);
|
||||
|
||||
/* a click that stands for the pad's A (ui_widget.c: the screen where
|
||||
controllers join by pressing it), held a moment */
|
||||
@@ -929,14 +945,15 @@ static void vr_gamepad_state(XINPUT_GAMEPAD *pad)
|
||||
}
|
||||
merge_button(pad, XINPUT_GAMEPAD_A, (right->buttons & HALO_XR_BUTTON_A) != 0);
|
||||
merge_button(pad, XINPUT_GAMEPAD_X, (left->buttons & HALO_XR_BUTTON_A) != 0);
|
||||
/* (the grips holding a Warthog's wheel are not a blow) */
|
||||
merge_button(pad, XINPUT_GAMEPAD_B,
|
||||
((right->buttons & HALO_XR_BUTTON_SQUEEZE) != 0 && !halo_vr_wheel_held()) || halo_vr_melee());
|
||||
/* (the grips holding a Warthog's wheel are not a blow: vr.c) */
|
||||
merge_button(pad, XINPUT_GAMEPAD_B, (right->buttons & HALO_XR_BUTTON_SQUEEZE) != 0 || halo_vr_melee());
|
||||
merge_button(pad, XINPUT_GAMEPAD_Y, (left->buttons & HALO_XR_BUTTON_B) != 0);
|
||||
/* (the Steam Frame's bumpers: the left switches grenades, the right is
|
||||
the flashlight) */
|
||||
merge_button(pad, XINPUT_GAMEPAD_BLACK, (left->buttons & HALO_XR_BUTTON_BUMPER) != 0);
|
||||
merge_button(pad, XINPUT_GAMEPAD_WHITE, (right->buttons & HALO_XR_BUTTON_BUMPER) != 0);
|
||||
/* (and a tap of the head, vr.flashlight_gesture: vr.c) */
|
||||
merge_button(pad, XINPUT_GAMEPAD_WHITE,
|
||||
(right->buttons & HALO_XR_BUTTON_BUMPER) != 0 || halo_vr_flashlight_tap());
|
||||
{
|
||||
/* B: a tap is the flashlight, holding it switches grenades; the
|
||||
game sees a short press of either */
|
||||
@@ -1038,12 +1055,15 @@ DWORD WINAPI XInputSetState(HANDLE device, PXINPUT_FEEDBACK feedback)
|
||||
if (port < 0)
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
#ifdef HALO_ANDROID
|
||||
/* VR: the heavy (left) motor in the left hand, the light one in the
|
||||
right, as the game refreshes them every frame */
|
||||
/* VR: the heavy (left) motor in the free hand, the light one in the
|
||||
weapon's (left-handed, the other way round), as the game refreshes them
|
||||
every frame */
|
||||
if (port == 0 && halo_vr_active())
|
||||
{
|
||||
host_xr_haptic(HALO_XR_HAND_LEFT, feedback->Rumble.wLeftMotorSpeed / 65535.0f, 0.1f);
|
||||
host_xr_haptic(HALO_XR_HAND_RIGHT, feedback->Rumble.wRightMotorSpeed / 65535.0f, 0.1f);
|
||||
int weapon = halo_vr_weapon_hand();
|
||||
|
||||
host_xr_haptic(HALO_XR_HAND_COUNT - 1 - weapon, feedback->Rumble.wLeftMotorSpeed / 65535.0f, 0.1f);
|
||||
host_xr_haptic(weapon, feedback->Rumble.wRightMotorSpeed / 65535.0f, 0.1f);
|
||||
}
|
||||
#endif
|
||||
count = sdl_gamepads(gamepads);
|
||||
|
||||
@@ -118,6 +118,10 @@ void cheats_dispose_from_old_map(
|
||||
|
||||
/* network_game_globals.c's */
|
||||
boolean network_game_distributed_client(void);
|
||||
#ifdef HALO_ANDROID
|
||||
/* port/linux/game/vr_graphics.c */
|
||||
boolean vr_graphics_reduces(boolean const *game_switch);
|
||||
#endif
|
||||
/* bipeds.c's, player_control.c's */
|
||||
extern boolean rider_ejection;
|
||||
extern boolean player_autoaim_flag;
|
||||
@@ -155,6 +159,12 @@ static boolean cheats_network_client_rasterizer_enforce(
|
||||
environment_part <= &rasterizer_debug_options.draw_environment_fog_screen;
|
||||
environment_part++)
|
||||
{
|
||||
#ifdef HALO_ANDROID
|
||||
/* (VR: a part the graphics preset keeps off, as it may in another's
|
||||
game: shadows, specular light, reflections; vr_graphics.c) */
|
||||
if (vr_graphics_reduces(environment_part))
|
||||
continue;
|
||||
#endif
|
||||
if (!*environment_part)
|
||||
changed = TRUE;
|
||||
*environment_part = TRUE;
|
||||
|
||||
@@ -488,10 +488,11 @@ static boolean first_person_weapon_vr_pose_kept(
|
||||
first_person_weapon_vr_pose_weapon[local_player_index]==first_person_weapon_get(local_player_index)->weapon_index;
|
||||
}
|
||||
|
||||
/* VR: the grenade the player holds (the left trigger, units.c) hangs from
|
||||
the body, which the first-person view leaves out, and with it the grenade:
|
||||
drawn instead in the left hand, as it is this frame, with the hands (which
|
||||
are drawn over the world, and would hide it wherever they overlap) */
|
||||
/* VR: the grenade the player holds (the free hand's trigger, units.c)
|
||||
hangs from the body, which the first-person view leaves out, and with it
|
||||
the grenade: drawn instead in the free hand, as it is this frame, with the
|
||||
hands (which are drawn over the world, and would hide it wherever they
|
||||
overlap; in the room, not mirrored) */
|
||||
static void first_person_weapon_draw_held_grenade(
|
||||
long unit_index,
|
||||
struct render_lighting *lighting,
|
||||
@@ -1217,17 +1218,132 @@ static void first_person_weapon_set_state(
|
||||
#ifdef HALO_ANDROID
|
||||
/* ---------- VR arms
|
||||
|
||||
The first-person skeleton hangs from the camera at the right controller
|
||||
(halo_vr_weapon_camera), so the weapon and the right hand lie where they
|
||||
should; its arms, though, reach up to shoulders that float with the weapon.
|
||||
Here each arm's upper arm and forearm are turned (two-bone inverse
|
||||
kinematics, port/linux/game/vr_arms.c) to run from the player's shoulders,
|
||||
below the neck and square to the torso, to its wrist, the controller's roll
|
||||
shared along the forearm. The left wrist, unless the hand holds the
|
||||
weapon's foregrip, goes to the left controller, its fingers with it. */
|
||||
The first-person skeleton hangs from the camera at the weapon hand's
|
||||
controller (halo_vr_weapon_camera), so the weapon and the right hand lie
|
||||
where they should; its arms, though, reach up to shoulders that float with
|
||||
the weapon. Here each arm's upper arm and forearm are turned (two-bone
|
||||
inverse kinematics, port/linux/game/vr_arms.c) to run from the player's
|
||||
shoulders, below the neck and square to the torso, to its wrist, the
|
||||
controller's roll shared along the forearm. The left wrist, unless the hand
|
||||
holds the weapon's foregrip, goes to the free controller, its fingers with
|
||||
it.
|
||||
|
||||
Left-handed (vr.handedness) all this is done in model space (halo_vr.h): a
|
||||
mirror image of the room, where the left controller holds the weapon as a
|
||||
right hand would; the body is mirrored into it, and the posed skeleton
|
||||
mirrored back (vr_mirror_pose), so that the weapon lies in the left hand,
|
||||
the model's left arm reaches to the right controller. */
|
||||
|
||||
#define VR_METRES_PER_WORLD_UNIT 3.048f
|
||||
|
||||
/* a point or a vector across the mirror (a point on it, its normal) */
|
||||
static void vr_mirror_point(
|
||||
float const on[3],
|
||||
float const normal[3],
|
||||
float point[3])
|
||||
{
|
||||
float along = (point[0] - on[0]) * normal[0] + (point[1] - on[1]) * normal[1] + (point[2] - on[2]) * normal[2];
|
||||
|
||||
point[0] -= 2.f * along * normal[0];
|
||||
point[1] -= 2.f * along * normal[1];
|
||||
point[2] -= 2.f * along * normal[2];
|
||||
}
|
||||
|
||||
static void vr_mirror_vector(
|
||||
float const normal[3],
|
||||
float vector[3])
|
||||
{
|
||||
float along = vector[0] * normal[0] + vector[1] * normal[1] + vector[2] * normal[2];
|
||||
|
||||
vector[0] -= 2.f * along * normal[0];
|
||||
vector[1] -= 2.f * along * normal[1];
|
||||
vector[2] -= 2.f * along * normal[2];
|
||||
}
|
||||
|
||||
/* the posed skeleton across a mirror: every node mirrored, its axes too
|
||||
(a left-handed frame: rasterizer_xbox.c turns its triangles' winding over).
|
||||
Numeric displays drawn so, the assault rifle's ammo counter and compass,
|
||||
are read the right way round by rasterizer_xbox_transparent_geometry.c. */
|
||||
static void vr_mirror_nodes(
|
||||
float const on[3],
|
||||
float const normal[3],
|
||||
real_matrix4x3 *node_matrices,
|
||||
short node_count)
|
||||
{
|
||||
short node_index;
|
||||
|
||||
for (node_index = 0; node_index < node_count; node_index++)
|
||||
{
|
||||
real_matrix4x3 *node = &node_matrices[node_index];
|
||||
real_vector3d *axes[3];
|
||||
float vector[3];
|
||||
short axis;
|
||||
|
||||
vector[0] = node->position.x;
|
||||
vector[1] = node->position.y;
|
||||
vector[2] = node->position.z;
|
||||
vr_mirror_point(on, normal, vector);
|
||||
node->position.x = vector[0];
|
||||
node->position.y = vector[1];
|
||||
node->position.z = vector[2];
|
||||
axes[0] = &node->forward;
|
||||
axes[1] = &node->left;
|
||||
axes[2] = &node->up;
|
||||
for (axis = 0; axis < 3; axis++)
|
||||
{
|
||||
vector[0] = axes[axis]->i;
|
||||
vector[1] = axes[axis]->j;
|
||||
vector[2] = axes[axis]->k;
|
||||
vr_mirror_vector(normal, vector);
|
||||
axes[axis]->i = vector[0];
|
||||
axes[axis]->j = vector[1];
|
||||
axes[axis]->k = vector[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* the posed skeleton out of model space (left-handed) */
|
||||
static void vr_mirror_pose(
|
||||
short local_player_index,
|
||||
real_matrix4x3 *node_matrices,
|
||||
short node_count)
|
||||
{
|
||||
float on[3], normal[3];
|
||||
|
||||
if (halo_vr_first_person_mirror(local_player_index, on, normal))
|
||||
vr_mirror_nodes(on, normal, node_matrices, node_count);
|
||||
}
|
||||
|
||||
/* debug.mirror_first_person (a test aid, flat): the first-person weapon
|
||||
mirrored across the camera's own forward and up, as the left hand's is in
|
||||
VR; its numeric displays can so be checked off the headset */
|
||||
int config_boolean(char const *name);
|
||||
|
||||
static void debug_mirror_first_person(
|
||||
struct render_camera const *camera,
|
||||
real_matrix4x3 *node_matrices,
|
||||
short node_count)
|
||||
{
|
||||
static int wanted = -1;
|
||||
real_vector3d left;
|
||||
float on[3], normal[3];
|
||||
|
||||
if (wanted < 0)
|
||||
wanted = config_boolean("debug.mirror_first_person") ? 1 : 0;
|
||||
if (!wanted)
|
||||
return;
|
||||
cross_product3d(&camera->up, &camera->forward, &left);
|
||||
if (normalize3d(&left) == 0.0f)
|
||||
return;
|
||||
on[0] = camera->position.x;
|
||||
on[1] = camera->position.y;
|
||||
on[2] = camera->position.z;
|
||||
normal[0] = left.i;
|
||||
normal[1] = left.j;
|
||||
normal[2] = left.k;
|
||||
vr_mirror_nodes(on, normal, node_matrices, node_count);
|
||||
}
|
||||
|
||||
struct vr_arm_nodes
|
||||
{
|
||||
long graph_index;
|
||||
@@ -1470,6 +1586,16 @@ static void vr_laser_follows_barrel(
|
||||
{
|
||||
return;
|
||||
}
|
||||
{
|
||||
/* (the laser at the ready is the room's: into model space) */
|
||||
float on[3], normal[3];
|
||||
|
||||
if (halo_vr_first_person_mirror(local_player_index, on, normal))
|
||||
{
|
||||
vr_mirror_point(on, normal, laser_start);
|
||||
vr_mirror_vector(normal, laser_direction);
|
||||
}
|
||||
}
|
||||
matrix4x3_from_point_and_vectors(&camera_matrix, &weapon_camera->position, &weapon_camera->forward,
|
||||
&weapon_camera->up);
|
||||
matrix4x3_multiply(&camera_matrix, &vr_arm_nodes.idle_pose[vr_arm_nodes.gun], &ready_gun);
|
||||
@@ -1656,6 +1782,18 @@ static void first_person_weapon_vr_arms(
|
||||
{
|
||||
return;
|
||||
}
|
||||
{
|
||||
/* (the body is the room's: into model space, where the shoulders
|
||||
change sides) */
|
||||
float on[3], normal[3];
|
||||
|
||||
if (halo_vr_first_person_mirror(local_player_index, on, normal))
|
||||
{
|
||||
vr_mirror_point(on, normal, head);
|
||||
vr_mirror_point(on, normal, neck);
|
||||
vr_mirror_vector(normal, body_forward);
|
||||
}
|
||||
}
|
||||
/* (the shoulders hang from the neck, which the head turns about) */
|
||||
eye.x = neck[0];
|
||||
eye.y = neck[1];
|
||||
@@ -1705,7 +1843,7 @@ static void first_person_weapon_vr_arms(
|
||||
return;
|
||||
if (!gripping && vr_arm_nodes.wrist[0] != NONE)
|
||||
{
|
||||
if (halo_vr_left_hand(local_player_index, hand_position, hand_forward, hand_up))
|
||||
if (halo_vr_free_hand(local_player_index, hand_position, hand_forward, hand_up))
|
||||
{
|
||||
/* (rigid: the hand and its arm carried to the controller now;
|
||||
bent, the arm is solved to it first, below, and the hand turned
|
||||
@@ -1834,8 +1972,8 @@ static void first_person_weapon_build_node_matrices(
|
||||
struct first_person_weapon *first_person_weapon= first_person_weapon_get(local_player_index);
|
||||
struct render_camera const *camera= &render.camera;
|
||||
#ifdef HALO_ANDROID
|
||||
/* VR: posed from the right controller, so the weapon lies in the hand
|
||||
(port/linux/src/vr.c) */
|
||||
/* VR: posed from the weapon hand's controller, so the weapon lies in the
|
||||
hand (port/linux/src/vr.c) */
|
||||
struct render_camera weapon_camera;
|
||||
float weapon_position[3], weapon_forward[3], weapon_up[3];
|
||||
|
||||
@@ -2202,8 +2340,17 @@ static void first_person_weapon_build_node_matrices(
|
||||
(short)animation_graph->nodes.count,
|
||||
camera,
|
||||
first_person_weapon->state);
|
||||
/* (left-handed: out of model space; what the frame takes from
|
||||
the pose after, markers, effects, is then the room's) */
|
||||
vr_mirror_pose(local_player_index, first_person_weapon->node_matrices,
|
||||
(short)MIN(animation_graph->nodes.count, MAXIMUM_NODES_PER_ANIMATION));
|
||||
halo_vr_timing_end(HALO_VR_TIMING_ARMS, timing);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_mirror_first_person(camera, first_person_weapon->node_matrices,
|
||||
(short)MIN(animation_graph->nodes.count, MAXIMUM_NODES_PER_ANIMATION));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+756
-111
File diff suppressed because it is too large.
Load diff
@@ -31,7 +31,14 @@ enum
|
||||
RASTERIZER_MAXIMUM_TRIANGLES_PER_TRIANGLE_BUFFER = 24576,
|
||||
RASTERIZER_MAXIMUM_DEBUG_PRIMITIVES = 131072,
|
||||
RASTERIZER_MAXIMUM_DEBUG_VERTICES = 393216,
|
||||
RASTERIZER_MAXIMUM_TRANSPARENT_GEOMETRY_GROUPS = 384,
|
||||
/* port: the Xbox's 384 groups a window (each a model's transparent part,
|
||||
a particle system, a contrail, a light volume, a window's or water's
|
||||
surface) are spent in games of 30 and more players, and whatever is
|
||||
submitted after the last is dropped, the structure's glass and water
|
||||
and the particles first (render_window submits the objects before
|
||||
them). Their indices are shorts, the pending flags a bit vector of
|
||||
this size: 2048 groups take 320 KB. */
|
||||
RASTERIZER_MAXIMUM_TRANSPARENT_GEOMETRY_GROUPS = 2048,
|
||||
RASTERIZER_MAXIMUM_TRANSPARENT_GEOMETRY_GROUPS2 = 32,
|
||||
RASTERIZER_MAXIMUM_DYNAMIC_TRIANGLES = 32768,
|
||||
RASTERIZER_MAXIMUM_DYNAMIC_TRIANGLE_BUFFERS = 1024,
|
||||
|
||||
@@ -150,6 +150,7 @@ typedef char transparent_geometry_group_cortana_hack_offset_assert[
|
||||
/* ---------- prototypes */
|
||||
static void rasterizer_sort_external(
|
||||
void);
|
||||
void platform_log(char const *format, ...);
|
||||
|
||||
/* ---------- globals */
|
||||
|
||||
@@ -162,6 +163,9 @@ static long transparent_geometry_group_count = 0;
|
||||
static long transparent_geometry_group_count2 = 0;
|
||||
static short *transparent_geometry_group_sorted_indices = NULL;
|
||||
static short transparent_geometry_next_group_sorted_index = 0;
|
||||
/* port: the most groups a window has had, logged as it passes the Xbox's
|
||||
384 and every 128 beyond (rasterizer.h) */
|
||||
static long transparent_geometry_group_count_logged = 384;
|
||||
|
||||
|
||||
/* ---------- public code */
|
||||
@@ -200,6 +204,12 @@ boolean rasterizer_transparent_geometry_initialize(
|
||||
void rasterizer_transparent_geometry_begin(
|
||||
void)
|
||||
{
|
||||
if (transparent_geometry_group_count>transparent_geometry_group_count_logged)
|
||||
{
|
||||
platform_log("rasterizer: %ld transparent geometry groups in a window (the Xbox had room for 384, the port %d)",
|
||||
transparent_geometry_group_count, RASTERIZER_MAXIMUM_TRANSPARENT_GEOMETRY_GROUPS);
|
||||
transparent_geometry_group_count_logged = (transparent_geometry_group_count/128 + 1)*128;
|
||||
}
|
||||
transparent_geometry_group_count = 0;
|
||||
transparent_geometry_next_group_sorted_index = 0;
|
||||
memset(transparent_geometry_group_pending_flags, 0,
|
||||
|
||||
@@ -1227,6 +1227,11 @@ void rasterizer_set_model_lighting(
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
/* port/linux/src/d3d8_gl.c */
|
||||
void d3d8_set_mirrored_skinning(int mirrored);
|
||||
#endif
|
||||
|
||||
void rasterizer_set_model_skinning(
|
||||
struct render_skinning const *skinning)
|
||||
{
|
||||
@@ -1263,6 +1268,21 @@ void rasterizer_set_model_skinning(
|
||||
constants[2][2] = scale * matrix->up.k;
|
||||
constants[2][3] = matrix->position.z;
|
||||
}
|
||||
#ifdef HALO_ANDROID
|
||||
/* port: node matrices that mirror (VR, the left hand's first-person
|
||||
weapon: first_person_weapons.c) turn the triangles' winding over while
|
||||
they are drawn (after HaloCE-Quest-VR, CC0); _rasterizer_model_end and
|
||||
rasterizer_transparent_geometry_group_draw end it */
|
||||
{
|
||||
real_matrix4x3 const *m = &skinning->node_matrices[0];
|
||||
real determinant =
|
||||
m->forward.i * (m->left.j * m->up.k - m->left.k * m->up.j) -
|
||||
m->forward.j * (m->left.i * m->up.k - m->left.k * m->up.i) +
|
||||
m->forward.k * (m->left.i * m->up.j - m->left.j * m->up.i);
|
||||
|
||||
d3d8_set_mirrored_skinning(determinant < 0.0f);
|
||||
}
|
||||
#endif
|
||||
D3DDevice_SetVertexShaderConstant(
|
||||
-36,
|
||||
vsh_constants__nodematrices,
|
||||
|
||||
@@ -596,9 +596,18 @@ void _rasterizer_models_end(
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
/* port/linux/src/d3d8_gl.c: the model's mirroring (rasterizer_xbox.c) ends
|
||||
with it */
|
||||
void d3d8_set_mirrored_skinning(int mirrored);
|
||||
#endif
|
||||
|
||||
void _rasterizer_model_end(
|
||||
void)
|
||||
{
|
||||
#ifdef HALO_ANDROID
|
||||
d3d8_set_mirrored_skinning(0);
|
||||
#endif
|
||||
if (rasterizer_debug_options.draw_models)
|
||||
{
|
||||
match_assert(
|
||||
|
||||
@@ -970,9 +970,83 @@ real_vector4d *offset_vector4d(
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
/* port: a group's draw, its mirroring (rasterizer_set_model_skinning) put
|
||||
back after it to what it was: a group drawn in the middle of a model's
|
||||
(not queued) leaves the model's own */
|
||||
int d3d8_mirrored_skinning(void);
|
||||
void d3d8_set_mirrored_skinning(int mirrored);
|
||||
|
||||
/* port: a numeric display drawn mirrored (rasterizer_set_model_skinning:
|
||||
the left hand's first-person weapon in VR; the assault rifle's ammo counter
|
||||
and compass) reads the right way round. Its geometry stays mirrored with the
|
||||
weapon (its vertices hang from the gun's nodes as well as the display's);
|
||||
instead each digit's quad shows its bitmap turned over in u
|
||||
(rasterizer_numeric_mirror_u), and as the quads' order across the display is
|
||||
turned over too, the quad of the n-th digit from the right shows the n-th
|
||||
from the left. The digits: as many as the counter's largest value needs,
|
||||
that value itself wrapping to 0 (the compass's whole turn). FALSE, the
|
||||
digit untouched, when not mirrored. Only for a first map in the model's own
|
||||
u and v (2d, not in screen space), which rasterizer_numeric_mirror_u turns. */
|
||||
static boolean rasterizer_numeric_mirrored_digit(
|
||||
real value,
|
||||
short counter_limit,
|
||||
short frame_count,
|
||||
short digit_index,
|
||||
short *bitmap_sequence_index)
|
||||
{
|
||||
short counter_value;
|
||||
short digit_count;
|
||||
short place;
|
||||
long power;
|
||||
|
||||
if (!d3d8_mirrored_skinning() || frame_count < 2)
|
||||
return FALSE;
|
||||
|
||||
counter_value = PIN(fast_ftol(floor(counter_limit*value + 0.5f)), 0, counter_limit);
|
||||
digit_count = 1;
|
||||
for (power = frame_count; power < counter_limit; power *= frame_count)
|
||||
digit_count++;
|
||||
place = digit_count - 1 - digit_index;
|
||||
if (place < 0)
|
||||
place = digit_index;
|
||||
while (place-- > 0)
|
||||
counter_value /= frame_count;
|
||||
*bitmap_sequence_index = counter_value%frame_count;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* the first map's u turned over (1-u: each digit's quad spans its bitmap) */
|
||||
static void rasterizer_numeric_mirror_u(
|
||||
real u_transform[4])
|
||||
{
|
||||
u_transform[0] = -u_transform[0];
|
||||
u_transform[1] = -u_transform[1];
|
||||
u_transform[2] = -u_transform[2];
|
||||
u_transform[3] = 1.0f - u_transform[3];
|
||||
}
|
||||
|
||||
static void rasterizer_transparent_geometry_group_draw_unmirrored(
|
||||
struct transparent_geometry_group *group,
|
||||
boolean dirty);
|
||||
|
||||
void rasterizer_transparent_geometry_group_draw(
|
||||
struct transparent_geometry_group *group,
|
||||
boolean dirty)
|
||||
{
|
||||
int mirrored = d3d8_mirrored_skinning();
|
||||
|
||||
rasterizer_transparent_geometry_group_draw_unmirrored(group, dirty);
|
||||
d3d8_set_mirrored_skinning(mirrored);
|
||||
}
|
||||
|
||||
static void rasterizer_transparent_geometry_group_draw_unmirrored(
|
||||
#else
|
||||
void rasterizer_transparent_geometry_group_draw(
|
||||
#endif
|
||||
struct transparent_geometry_group *group,
|
||||
boolean dirty)
|
||||
{
|
||||
boolean success = TRUE;
|
||||
boolean draw_active_camouflage_groups2 = FALSE;
|
||||
@@ -1813,6 +1887,9 @@ void rasterizer_transparent_geometry_group_draw(
|
||||
short map_index;
|
||||
short stage_index;
|
||||
long result;
|
||||
#ifdef HALO_ANDROID
|
||||
boolean numeric_mirrored = FALSE;
|
||||
#endif
|
||||
|
||||
for (layer_index = 0;
|
||||
layer_index < shader_transparent_generic->generic.extra_layers.count;
|
||||
@@ -1872,6 +1949,18 @@ void rasterizer_transparent_geometry_group_draw(
|
||||
counter_value /= frame_count;
|
||||
|
||||
bitmap_sequence_index = counter_value%frame_count;
|
||||
#ifdef HALO_ANDROID
|
||||
numeric_mirrored =
|
||||
shader_transparent_generic->generic.type==_shader_transparent_generic_type_2d_map &&
|
||||
!TEST_FLAG(shader_transparent_generic->generic.flags,
|
||||
_shader_transparent_flag_first_map_is_in_screenspace_bit) &&
|
||||
rasterizer_numeric_mirrored_digit(
|
||||
group->animation->values[function_index],
|
||||
counter_limit,
|
||||
frame_count,
|
||||
group->shader_permutation_index,
|
||||
&bitmap_sequence_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (shader_transparent_generic->generic.maps.count > 0)
|
||||
@@ -2034,6 +2123,10 @@ void rasterizer_transparent_geometry_group_draw(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
if (numeric_mirrored)
|
||||
rasterizer_numeric_mirror_u(vsh_constants__texanim[0]);
|
||||
#endif
|
||||
result = IDirect3DDevice8_SetVertexShaderConstant(
|
||||
global_d3d_device,
|
||||
VSH_CONSTANTS__TEXANIM_OFFSET,
|
||||
@@ -2300,6 +2393,9 @@ void rasterizer_transparent_geometry_group_draw(
|
||||
short layer_index;
|
||||
short map_index;
|
||||
long result;
|
||||
#ifdef HALO_ANDROID
|
||||
boolean numeric_mirrored = FALSE;
|
||||
#endif
|
||||
|
||||
/* BUG (preserved for exact matching): January never advances layer_index, so the
|
||||
* loop redraws extra layer 0 for as long as the block is non-empty (the bytes push
|
||||
@@ -2374,6 +2470,18 @@ void rasterizer_transparent_geometry_group_draw(
|
||||
counter_value /= frame_count;
|
||||
|
||||
bitmap_sequence_index = counter_value%frame_count;
|
||||
#ifdef HALO_ANDROID
|
||||
numeric_mirrored =
|
||||
shader_transparent_chicago->chicago.type==_shader_transparent_chicago_type_2d_map &&
|
||||
!TEST_FLAG(shader_transparent_chicago->chicago.flags,
|
||||
_shader_transparent_flag_first_map_is_in_screenspace_bit) &&
|
||||
rasterizer_numeric_mirrored_digit(
|
||||
group->animation->values[function_index],
|
||||
counter_limit,
|
||||
frame_count,
|
||||
group->shader_permutation_index,
|
||||
&bitmap_sequence_index);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2548,6 +2656,10 @@ void rasterizer_transparent_geometry_group_draw(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
if (numeric_mirrored)
|
||||
rasterizer_numeric_mirror_u(vsh_constants__texanim[0]);
|
||||
#endif
|
||||
result = IDirect3DDevice8_SetVertexShaderConstant(
|
||||
global_d3d_device,
|
||||
VSH_CONSTANTS__TEXANIM_OFFSET,
|
||||
|
||||
@@ -92,6 +92,9 @@ symbols in this file:
|
||||
#include "physics/collisions.h"
|
||||
#include "units/units.h"
|
||||
#include "halo_vr.h"
|
||||
|
||||
/* port/linux/game/vr_graphics.c */
|
||||
void vr_graphics_update(void);
|
||||
#endif
|
||||
#include "main/main.h"
|
||||
#include "structures/structures.h"
|
||||
@@ -948,6 +951,11 @@ void render_frame(
|
||||
|
||||
render.frame_index++;
|
||||
render.time_delta_since_tick_sec = time_delta_since_tick_sec;
|
||||
#ifdef HALO_ANDROID
|
||||
/* VR: the graphics preset's effects (port/linux/game/vr_graphics.c) */
|
||||
if (halo_vr_active())
|
||||
vr_graphics_update();
|
||||
#endif
|
||||
memset(¶meters, 0, sizeof(parameters));
|
||||
/* continuous between ticks (render_interpolation.c) */
|
||||
parameters.game_time_sec = render_interpolation_game_time_sec(game_time_get());
|
||||
|
||||
Reference in new issue
Block a user