Commit Graph
45 Commits
Author SHA1 Message Date
bearstonem d9968210aa fix(vr): correct visual glitches and reduce rendering overhead
Restore desktop HUD behavior and objective state, fix stereo text lifetimes, HUD placement and colors, sprite culling, and font shader passes. Handle swapchain timeouts and incomplete stereo frames safely, remove forced GPU waits, and correct rendering timing attribution.

Track client-game source additions in CMake. Validated desktop and Android GL1/GL2 builds plus targeted regression and sanitizer checks. Headset appearance and performance remain unverified.
2026-10-14 14:48:22 -07:00
bearstonem e6a7c76f84 feat(vr): one HUD in the middle of the view, and the two bugs that hid it
The retail HUD is five menus from ui/hud_*.urc, each aligned to a corner of a
4:3 screen. On a monitor those corners are a glance away; through a lens they
are the far edge, present and unreadable. cg_vrhud.cpp draws the same
information again as one group below the centre of the view.

Nothing is read back out of the widgets, because there is nothing in them to
read: every one is a formatter over cl.snap.ps.stats[], thirty-two integers,
and the .urc files are pure layout - hud_health.urc is "playerstat 0,
maxplayerstat 1, draw it as a vertical bar". cgame has the same array as
cg.snap->ps.stats[]. The .urc files were still worth reading, as the spec for
which stat index and which shader each element uses, and the decode of the two
compass angles is taken from the widgets that already do it rather than guessed:
the heading is the eye yaw less stats[STAT_COMPASSNORTH]/182, a sixteen bit
angle, and the objective is stat/10 - 180 and is already relative to the view,
because hud_compass.urc draws it as a plain spinner and not the headingspinner
variant that subtracts the view angles itself.

It is drawn from cgame rather than as another widget for a reason beyond taste.
cgame's 2D goes through the one full screen window UIView3D::set2D sets up, and
that window is converged as a whole. A widget would arrive with its own window,
which is the first bug below.

Convergence: the correction belongs to the display, not to the window.

R_VRAdjust2DOrtho bent whatever ortho window it was handed, and in this engine
that window is usually one widget - UIWidget::set2D cuts a viewport and an ortho
window to each widget's own frame. The correction was therefore scaled to the
widget, and a 150 pixel compass in a 1680 pixel eye got about a twelfth of the
shift it needed while the objectives, drawn through the full screen window, got
all of it. Every element ended up with a disparity in proportion to its own
width, so each sat at a different apparent depth, and no vergence resolves that
set - which is what "the HUD will not converge" was.

It is R_VRAdjust2DRect now, applied to the viewport and scissor rectangle in
eye buffer pixels, which every 2D window shares. The scissor has to move with
it or a widget the shift has displaced is clipped away at where it used to be.
vr_hudOffset goes back to 1 in autoexec.cfg: 0 was set on a measurement of the
old bug, and it is the one value that cannot fuse at all, because the centre of
each eye's buffer is about seven degrees off its own axis in opposite
directions, so it asks the eyes to diverge by fourteen degrees.

Text: the font atlases had no texture.

Every string drew as a flat black rectangle - 0,0,0 with no glyph structure,
measured off an eye dump rather than a compositor screenshot. The atlas is a 32
bit TGA with a real alpha channel and the shader is correct, so neither of the
obvious causes held. The shader's own stage reported texnum 0, and GL_Bind binds
image->texnum straight, so it was binding texture zero, which samples opaque
black.

The image is alive and correctly named, so it was never freed - R_FreeImage and
R_DeleteTextures both memset, and the name survived. texnum was zero from
creation. R_LoadFontShader now notices and reloads, but it has to free the image
first: R_FindImageFileOld looks in the hash before it looks on disk, so asking
by name returns the very image that has no texture. Three of the four fonts come
back with a texture; verdana-14, the first one created, still comes back as zero
on a fresh load from disk, which means qglGenTextures is not writing to it and
the real bug is upstream in image creation. That is not fixed here, and
CG_HudDrawElements still draws its text as boxes because of it.

Also in here: R_DrawTrianglePic added to the cgame imports, which the UI has
always had as re.DrawTrianglePic and is the only way to draw anything rotated,
so the compass card can turn under a fixed needle the way hud_compass.urc does
it. The retail corner HUD is hidden from the "Hide the HUD when necessary" block
in UI_Update rather than from the explicit Display calls above it, because that
branch returns early and is not the path taken - when it is not, UpdateViews
walks the whole tree and draws every shown menu regardless, which is how
hud_health and hud_ammo stayed on screen through the first attempt.

Bars are R_DrawBox rather than a stretched gfx/2d/blank. That shader is declared
alphaGen oneMinusVertex, which inverts the alpha: the bars asked for at 1 came
out at 0 and the backdrop asked for at 0.35 came out at 0.65.

vr_hudGroupY is 0.73 and does not mean what it looks like. It places the cluster
in the flat frame, which is then scaled to vr_hudScale about the middle of the
display and lifted by the eye's vertical frustum asymmetry, 170 pixels of 1760
here - so 0.73 is a little below the middle of what is actually seen and 0.62
was a little above it. The reachable range is about 0.13 to 0.68 of the eye.

Not done: the damage direction ring, the objective as compassobjarrow rather
than a pip, and the compass worth having, which is one the player takes out of a
pocket and holds.
2026-08-02 23:16:00 -07:00
bearstonemandClaude Opus 5 711cad20e6 feat(vr): reach into the world - use, holsters, ladders and thrown grenades
Four interactions that all needed the same thing: the hands' positions and
velocities on the other side of the game module boundary. They share the
plumbing, so they share a commit.

use moves to B on the weapon hand, where the reference puts activate. The
objectives list keeps the left hand's button; it had been bound to both, which
was a button spent twice on one rarely opened screen. The trace also starts from
the head's real position now rather than the body's notional eye - the two come
apart exactly when leaning through a doorway to reach the thing on the far side.

Weapons live on the body, the way Half-Life: Alyx does it: pistol at the right
hip, grenades at the left, rifle and smg over the shoulders. Reaching back to
where a weapon came from puts it away, reaching anywhere else swaps - holstering
on any zone would have cost two gestures for every swap. Zones are measured from
the head and rotated by the head's heading, so they stay on the body rather than
wandering as the player turns.

Ladders are climbed by pulling on them. MOHAA moves a climbing player by the
root motion of the climb animation, with pmove skipped entirely, so this runs
after the animation rather than instead of it: the animation still plays and the
distance travelled is the distance the hand pulled. Both grips, averaged when
both are held, and the grips stop meaning reload and rifle-steady while on a
ladder.

Grenades leave along the arm. Which instant of a swing to read is the whole
problem and took several passes: averaging across the release blends the wind up
with the follow through; the peak of the whole swing is usually the *backswing*,
which threw grenades over the player's shoulder. What works is the natural
gesture's own shape - take the direction the hand had as it let go, then find
the fastest sample that agrees with it, which excludes the wind up by
construction. Strength is a fraction of the game's own throw so all of MOHAA's
grenade tuning survives.

The sideways damping is the one deliberate lie. An underhand swing crosses the
body, so the hand really is moving sideways at release - measured, lobs drifted
left by up to 0.73, more sideways than forward. Damped in proportion to how
gentle the throw is, so hard throws keep their true direction.

A weapon wheel is included and is not finished: its input works and a tap of the
same stick holsters, but the ring never appeared on screen and the drawing was
not chased down. It is harmless - a hold selects nothing and does nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 15:49:25 -07:00
bearstonemandClaude Opus 5 a8a1314c2d fix(vr): ask for an ES context for the fixed function renderer, and check it is current
Two problems the first device run found, one hiding the other.

GLimp_SetMode's fixedFunction branch offers exactly one context: desktop OpenGL
1.1. There is no such thing on Android, so window creation failed three times
over and R_Init gave up with "Couldn't get a visual". renderergl2 never met this
because it takes the other branch, which already knows how to ask for ES.

gl4es is what makes the request answerable, and it wants the opposite of what
the renderer believes it is getting: desktop GL 1.x presented upwards, OpenGL ES
underneath. So the fixed function branch now asks for ES 3.0 and then ES 2.0,
and the renderer is never told - it reads its version through gl4es, which
reports desktop GL, and takes the desktop fixed function path on the strength of
it.

That got the renderer up, and revealed the second problem: the OpenXR session
found no current EGL context. Which is where gl4es having its own opinion about
glGetString stops being convenient. The engine's proof that a context is live is
GL_VERSION coming back non-NULL, and gl4es answers VERSION, VENDOR and RENDERER
out of constants without asking the driver - so a context that was created but
never bound passes that test and is only noticed much later, somewhere else
entirely. GLimp_SetMode now asks SDL directly whether the context it just made
is current, restoring the check gl4es defeated.

The session no longer assumes one is bound either. Being current is per thread,
and a window that has not been shown yet has no surface to be current against,
so VR_CreateSession asks for the binding through GLimp_MakeCurrent rather than
requiring it to already be there, and reports the EGL handles when it cannot get
one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 22:02:44 -07:00
smallmodel 667c50f9b2 fix(cgame): draw svlag only if developer mode is enabled 2026-04-13 22:10:46 +02:00
.Crimewavez 969311274f fix(cgame): crosshair centering at hi-res UI scaling (#908) 2026-03-29 21:41:05 +02:00
smallmodel a09132b9fd fix(cgame): always use the same crosshair_friend value across base and expansions
This prevents expansions from inheriting the default crosshair texture on first launch, avoiding the crosshair turning green when hovering over a teammate.
2026-01-21 23:29:50 +01:00
smallmodel d7a2e5bc65 Clear the time message on liberation
There is no clock on liberation game mode.
2025-09-03 20:37:13 +02:00
smallmodel 19e12701f3 Fix HUD scaling for spectator text, and vote text on 4K 2025-01-21 20:15:43 +01:00
smallmodel 499fe44bde Call R_RegisterShaderNoMip for the crosshair
This prevents the crosshair texture from being altered by the texture quality settings
2024-12-02 19:00:43 +01:00
smallmodel aa74934ae0 Fix huddraw scaling with high resolutions 2024-11-30 23:21:20 +01:00
smallmodel 0534482c22 Fix a small mistake where it uses vidWidth rather than vidHeight 2024-11-30 23:08:23 +01:00
smallmodel 6fe1e86b31 Automatically scale UI elements for high resolutions
This fixes UI elements being tiny on high resolutions like 4K. Now most UI elements will scale automatically with resolutions above 1920x1080.
2024-11-30 22:40:00 +01:00
smallmodel 862af012cb Fix infinite loop while getting the number of lines in objectives 2024-11-19 20:26:23 +01:00
smallmodel 05e14f6364 Adjust the objectives menu accordingly depending on the game message box which depends on the compass scale 2024-11-19 19:41:46 +01:00
smallmodel f23dfa091e Fix wrong flag used for checking for PMF_NO_HUD 2024-11-02 13:48:03 +01:00
smallmodel 374b8b9ae7 Add fuse stopwatch 2024-10-20 18:52:50 +02:00
smallmodel f9d264058b Use safe version of sprintf and strcpy 2024-09-20 23:08:53 +02:00
smallmodel 08e09c3b4c Avoid setting variables with the same value
This prevents the console from being spammed with constant variable change when `developer` is set to 2
2024-09-18 20:55:02 +02:00
smallmodel 74ccb03e54 Reduced compilation warnings 2024-06-07 20:34:13 +02:00
smallmodel 5568d160ab Fixed uninitialized shader variable in CG_DrawCrosshair() 2023-11-13 22:18:38 +01:00
smallmodel 96748b3fbc Fixed vote's last text position 2023-11-07 23:06:11 +01:00
smallmodel f1325048e9 Fixed crosshair's endpos friend test 2023-11-07 23:05:54 +01:00
smallmodel deee21eb68 Fixed vote string alignment position 2023-11-07 23:02:07 +01:00
smallmodel 4766067edb Fixed crosshair incorrectly hiding 2023-11-07 22:54:05 +01:00
smallmodel 20c8c87e79 Draw vote and crosshair 2023-11-07 22:43:13 +01:00
smallmodel e1554efc08 Fixed paused icon location 2023-11-07 19:20:52 +01:00
smallmodel 503320d13f Added modelOnly parameter to CG_ProcessConfigString + added votes 2023-10-29 20:40:07 +01:00
smallmodel e634fb5022 Using objective flags enum 2023-08-14 02:34:06 +02:00
smallmodel 7258a2e972 Fixed CG_DrawObjectives stack overflow 2023-08-13 22:07:19 +02:00
smallmodel 3fd87f90a2 Fixed objectives not showing properly 2023-08-13 20:17:23 +02:00
smallmodel 415a5e60da Fixed uninitialized variables 2023-07-18 21:19:01 +02:00
smallmodel f930d39a42 Used clang-format on cgame module 2023-07-05 21:24:23 +02:00
OM 36dce22071 Moved cgi.protocol to a new variable called cg_protocol instead, due to issues like GetCGameAPI being loaded before having client imports (cgi) 2023-07-02 19:16:48 +02:00
OM cb95284d0c Draw spectator view depending on the protocol version 2023-07-01 21:18:58 +02:00
OM 19716b20c0 Fixed kar98 zoom overlay 2023-05-29 21:14:43 +02:00
OM 9a6e7f23f9 **CG_DrawStopwatch** Refactor 2023-05-22 12:30:20 +02:00
OM c4aca55b1a Minor fixes 2023-05-22 02:38:43 +02:00
OM ff587a8444 Health draw fix 2023-05-22 01:58:51 +02:00
OM c3e98ed681 Fixed **CG_DrawSpectatorView** for Spearhead and Breakthrough 2023-05-22 01:50:53 +02:00
L 7030c23994 Fixed compilation issues 2023-05-07 20:38:08 +02:00
L f30b1cb409 Implemented all 2D functions 2023-05-07 19:37:56 +02:00
L 161c5f9b84 Implemented CG_RefreshHudDrawElements
Added more stubs
2023-05-01 15:12:01 +02:00
L 4b020c54ee Added stub functions 2023-04-30 14:47:27 +02:00
L 29f328abf0 Added Ubertools CGAME module 2023-04-30 00:02:16 +02:00