Commit Graph
602 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 4f5b54c74c feat(vr): a hand on each controller, placed in the renderer's frame
The first person model already has the hands as separate surfaces - triggerhand,
lefthand, garandhand and viewsleeves on USarmyplyr.skd - so putting one on each
controller needs no mesh work at all. The weapon hand's copy drops the left hand
surface and a second copy is drawn on the off hand carrying only that, using the
same Surface_NameToNum and MDL_SURFACE_NODRAW the game already uses to swap
lefthand for garandhand on rifles.

Two things had to be right first, and both were wrong in ways that looked like
tuning problems rather than faults.

**The frame.** cg.refdef.vieworg is not the camera. R_VRComposeView adds the
head's play space offset to it, rotated into the body's frame, after cgame is
finished (tr_vr.c). So anything anchored on vieworg alone is left behind by
exactly the head's offset within the play space - and because the head swings
about the neck, every look around moved it, and a snap turn left it behind
entirely since a stick turn moves the body frame that a head relative offset
knows nothing about.

Both hands are now reported measured from the tracking origin, the frame
VR_PoseToView puts the eyes in, and composed the way the renderer composes the
camera:

    bodyAngles = (0, viewYaw - baseYaw, 0)
    handWorld  = vieworg + bodyAxis * trackingOffset

RTCWQuest reaches the same place by a different road - convertFromVR rotates a
head relative offset by viewangles[YAW] - hmdorientation[YAW] and the -64 plus
hmdposition[1] * worldScale rebase then replaces its height, which comes to the
same thing. Either route works. Taking half of each does not, and did not: a
head relative offset composed as though it were play space leaves the hand at
vieworg + R*(hand - head) while the camera is at vieworg + R*head, so the head's
movement is counted twice and every hand movement is amplified. That is what
"the right hand is accelerated" was, and it happened because VR_GetWeaponPose
was left reporting the old frame while its caller had moved to the new one - the
signature is identical either way, so nothing complained. The header now says so
at length.

**The anchor.** A hand drawn at the model origin sits wherever the animation put
it, which for a rifle is a long way out in front. The model is now moved so the
hand's own bone lands on the controller instead, inverting the composition the
engine itself uses in Entity::GetTagPositionAndOrientation. The off hand anchors
on Bip01 L Hand and the weapon hand on tag_weapon_right, because what the player
is holding there is the gun and the controller is its grip.

Every candidate anchor is measured and logged rather than trusted, which earned
itself immediately: tag_weapon_left was assumed to be an unused slot parked at
the origin and is nothing of the sort (23.5 units out), while the weapon hand's
lookup was returning -1 in silence and anchoring nothing. Both now report what
they found and how far out it is, and the early return says which precondition
failed.

Tracking is confirmed 1:1 on both controllers on the device. What is left is the
wrist bones' own rotation convention, which is a constant and lives in
vr_weaponAdjust and vr_offHandAdjust.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 23:45:57 -07:00
bearstonemandClaude Opus 5 48b5876e3f fix(vr): the menu is CA_CINEMATIC, so the start map never loaded
vr_startMap waits for the client to sit idle before loading, because a map
started from autoexec.cfg runs during Com_Init and the game's own startup tears
it straight back down again. It counted only CA_DISCONNECTED as idle.

MOHAA's main menu is drawn over a static pic, and the enum says what that means:

    CA_CINEMATIC   // playing a cinematic or a static pic, not connected to a server

So the client is CA_CINEMATIC at the menu and never CA_DISCONNECTED. idleSince
was cleared every frame the menu was up, the four second wait could never
accumulate, and the map simply never loaded. Eight seconds sitting at the menu
was plenty; the timer just kept resetting. Confirmed by the state it now prints:
9, which is CA_CINEMATIC.

The reason this took a round trip to find is worth more than the fix. The
vr_testStart branch three lines below prints either way, and says why:

    // Printed either way. A hook that silently does nothing is indistinguishable
    // from one that never ran, and telling those apart has cost enough already.

vr_startMap printed only on success, so its silence could not be told from "ran
with an empty cvar". It now prints unconditionally and names the state that let
it through, so the next time this misbehaves the log says which.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 23:45:31 -07:00
bearstonemandClaude Opus 5 013b2f5bbf fix(vr): put in-game fullscreen menus on the panel, and load the test map late
Three things, all found by running it.

The mission briefing was drawn onto the player's face. VR_UseScreenLayer only
asked whether clc.state was CA_ACTIVE, so a fullscreen menu that comes up while
the player is still in the world skipped the quad layer and was drawn as screen
space 2D into both eye buffers - at the near plane, a hand's width away, with no
disparity to fuse and each eye warping it through its own asymmetric frustum.
That is exactly what the panel exists to prevent; nothing in-game was reaching
for it. It now checks UI_FullscreenMenuUp as well.

The log said so before the headset did: "view3d 0" with the eye passes still
running means the 3D scene is not being drawn at all, which only happens when a
fullscreen menu is covering it.

map in autoexec.cfg never had a chance. That file is exec'd during Com_Init and
the game's own startup - the intro stages, then the menu - runs afterwards and
tears down anything loaded there. vr_startMap now waits until the client is
sitting idle at the menu and loads it then. vr_testStart also prints
unconditionally: a hook that silently does nothing is indistinguishable from one
that never ran, and telling those apart has cost enough already.

vr_captureEye is a plain archived cvar rather than a VR_TuningCvar. Those force
their default at every start, which is right for a value still being argued with
and wrong for a switch - it made the config's own setting impossible to honour
and cost a device run to notice. The handoff warns about this exact trap.

vr_traceFrame is off in the shipped config: three lines a second rolls anything
that prints once out of logcat within a minute.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 19:46:46 -07:00
bearstonemandClaude Opus 5 ce91fd1bf7 feat(vr): per weapon alignment, and a way to test it without replaying the level
The view model is authored to sit at the camera with the arms reaching forward,
so anchoring its origin at the controller leaves that built-in offset in place
and the gun lands near the player's elbow. Rotation was already correct; only
the position was wrong, which is exactly what this fixes and exactly why no
amount of getting the hand pose right removes the need for it.

Same mechanism as the reference's vr_weapon_adjustment_<id> (rtcw
cg_weapons.c, VrInputWeaponAlign.c), as one tunable cvar:

    vr_weaponAdjust "scale,right,up,forward,pitch,yaw,roll"

Two details from theirs that are easy to get wrong and are kept here. The
rotation correction is composed in the weapon's own frame rather than added to
the angles, which is only right for one axis at a time. And the offset is
applied along the corrected axes, after the rotation - that ordering is why a
model can rotate correctly and still sit in the wrong place. It is a cvar so it
can be dialled in by pushing a config and relaunching, with no rebuild in the
loop.

CL_RunStartupCommand runs vr_testStart once, a second and a half after the
player is in the world. Setting up a weapon test otherwise means playing through
to wherever the game hands one over on every single build; there is no console
in a headset to type "give" into, and autoexec runs before there is a map, let
alone a player to give anything to. The delay is because CA_ACTIVE arrives
before the player has finished spawning and a give aimed at nothing is dropped.
It re-arms on every map load rather than firing only once per run.

The reference keeps an adjustment per weapon. This is a single global one until
the numbers for each are known - which is what the harness is for.

Not yet run: the headset dropped its connection before this could be installed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 08:39:04 -07:00
bearstonemandClaude Opus 5 046e2dd9a6 feat(vr): put the weapon in the player's hand, from the reference
Four pieces, each adapted from RTCWQuest rather than invented.

Aim. Weapon::GetMuzzlePosition derives a shot from player->m_vViewAng, which is
MOHAA's analogue of rtcw g_weapon.c:1904. It now takes the controller's pitch
and the yaw the hand leads the head by, added to the view yaw the game already
has - the controller's absolute yaw means nothing to the game, since the player
can snap turn on the stick and the play space has an arbitrary forward. Only the
trace moves; the camera stays on the head.

The angles reach fgame through gameImport_t rather than the usercmd, which has
no spare field - angles[3] is the view direction and buttons is packed. A
dedicated server answers false and keeps the aim it had.

Placement. The first person model is MOHAA's FPS view model, positioned by
CG_OffsetFirstPersonView against the camera and given the walk bob. Both are
wrong in a headset: the hand has its own position, and shaking the view model
when the camera is the player's head is a way to make people ill. It now goes
where the hand is - RTCWQuest's CG_CalculateVRWeaponPosition, including
dropping the origin to the feet and adding the measured head height back so the
weapon hangs at the height the player is really holding it, rather than off the
camera where crouching would drag it about.

Selection. Nothing was bound to it at all, and there is no button left - the
triggers fire, both face buttons on each hand are objectives and jump, and the
sticks and grips are duck and use. The reference does not spend a button either:
the dominant thumbstick up is weapprev and down is weapnext, gated on the
sideways component so it cannot be read as a turn and edge triggered so a held
stick does not run the inventory. This port's turn already ignores that stick's
Y axis, so nothing was displaced.

Two handed hold. Off hand grip squeezed with the hands close together points
the weapon along the line between them instead of along the weapon hand alone -
how a rifle is actually held, and steadier, because a wobble at one hand is
damped by the distance to the other. Roll is halved rather than taken from the
line, which carries none. The off hand grip was a duplicate of use; the weapon
hand's still opens doors.

The suggested binding array was 16 with 14 in use. Now 32.

Aim and placement are built but not yet confirmed on the device.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 08:10:24 -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
bearstonemandClaude Opus 5 7872929f32 feat(vr): head aim, stick locomotion and comfort options
The game now knows where the player is looking. Until now head tracking
only moved the camera the renderer drew from, so anything consulting the
player's view angles - objectives that ask them to look at something, aim,
hit detection - never saw it. CL_VRMove writes the head's heading and
pitch into cl.viewangles, which is what all of that reads.

Walking follows the off hand rather than the gaze, after the approach in
Team Beef's RTCWQuest. Tying travel to where the player is looking means
they cannot glance sideways without veering, which is what makes room
scale movement feel like being dragged; steering with the free hand lets
them look around and still walk a straight line. cl_vrWalkWithView
restores gaze-directed movement.

Turning snaps by default. A stick that rotates the world smoothly while
the inner ear insists otherwise is the usual way to make people ill, and
one flick gives one step rather than one per frame.

  cl_vrSnapAngle    45    degrees per flick
  cl_vrSmoothTurn   0     1 for smooth turning instead
  cl_vrTurnSpeed    90    degrees/second when smooth
  cl_vrDeadzone     0.2
  cl_vrWalkWithView 0     1 to walk where the player looks

All archived, so they are tunable on the headset rather than at build
time, which is what section 5 of the porting plan asks for.

Thumbsticks are bound on the Touch profile only: the simple controller
has none, and offering a binding a runtime does not recognise makes it
reject the whole set, which would cost the fallback its pointer too.

The dominant hand's aim angles are carried through vrInput_t but not yet
used. Aim is still on the head, which section 5 is right to call wrong
for a shooter - that belongs with weapon handling, and looking at things
had to work first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 17:21:14 -07:00
bearstonemandClaude Opus 5 5aff8d336a feat(vr): stereo rendering and 6DoF head tracking through OpenXR
Runs on a Meta Quest 3 in stereo at the headset's native 1680x1760 per
eye, with the world tracking head movement in six degrees of freedom.

The session binds to the EGL context SDL already created rather than a
private one, so there is a single GL context and the renderer needs no
thread or context juggling. Each eye is rendered into an OpenXR swapchain
image by substituting the framebuffer the renderer treats as the screen,
which leaves the whole render path untouched. Exactly two eye passes per
frame; there is deliberately no third pass to produce a flat image.

The session and its swapchains belong to the GL context they were made
with, so they are torn down and rebuilt around the renderer restarts the
engine performs.

Menus, the loading screen and cinematics go on a quad layer fixed in the
room, placed once in front of wherever the player is facing. Drawing
screen space content into both eyes instead gives it no stereo disparity
while each eye still warps it through its own asymmetric frustum, and the
result cannot be fused. The panel is drawn into one persistent buffer
that is then copied into the swapchain image: a swapchain rotates through
several images, and the engine's 2D path expects the screen to still hold
what it drew last frame.

Head tracking:

- The per-eye asymmetric frustum from xrLocateViews feeds
  R_SetupProjection directly. A symmetric approximation misaligns the two
  images by a few degrees, which the eyes cannot fuse.
- The pose is applied in RE_RenderScene, so it follows every camera the
  game has - the player's, cutscenes, ladders, death animations - without
  each needing to know about VR.
- Orientation is carried as axes rather than pitch/yaw/roll, and composed
  with the game's heading as a rotation. Adding Euler angles only works
  while pitch and roll are near zero and turns every head movement into a
  twist once they are not.
- Position is measured from where the head was when tracking started, so
  the game keeps supplying eye height and the headset contributes only
  leaning, ducking and stepping. The initial heading is subtracted too,
  or the play space's arbitrary forward is added to the character's and
  the player spawns facing the wrong way.

The controllers point at the panel and click: the aim ray is intersected
with the quad and the hit becomes the engine's cursor position, so the
menus behave as they always did.

The renderer's own framebuffer objects stay off on Android. Each eye is
already a swapchain image, so routing through tr.renderFbo first would
cost a second full resolution pass and resolve per eye for nothing.

Known gaps: head orientation does not yet reach the player's view angles,
so the game does not know where the player is looking; and there is no
controller model or pointer ray.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 17:03:38 -07:00
smallmodel b1a45c0546 feat(client): add fps_location to set the location of the FPS counter on screen 2026-04-06 14:53:53 +02:00
smallmodel 8b9881736c feat(client): for fps, show the number of verts/tris when the option is set to 2 2026-04-06 13:46:38 +02:00
.Crimewavez 919206af63 fix(ui): use actual drawn width for horizontal statbar tile shader (#906) 2026-03-29 21:32:41 +02:00
smallmodel 68cca1c58b fix(ui): fix stat spinner flash lacking transparency (#898) 2026-03-01 22:58:07 +01:00
smallmodel 0c5f7db70d fix(client): make serverlist interaction the same when using key or buttons 2026-02-19 21:23:26 +01:00
smallmodel 69d2236d8b fix(client): fix reconnect command not working after disconnect (#883) 2026-02-13 00:12:49 +01:00
smallmodel 46798d46dc refactor(network): clarify net profiling struct and field names 2025-12-20 23:32:47 +01:00
smallmodel 55a990efa6 fix(client): use the correct packet list profiling when the client receives a connectionless packet 2025-12-20 22:37:58 +01:00
smallmodel 8169bd01a8 docs: fix version annotation 2025-11-24 00:48:41 +01:00
smallmodel 26508d26f0 docs: correctly annotate version changes in comments 2025-11-21 23:19:46 +01:00
smallmodel f666681035 feat(ui): properly support shaders with one-shot animated textures (#839)
The issue also occurs in the original game. One-shot animated shaders would always appear as already finished.
2025-11-20 20:57:37 +01:00
smallmodel 35f74db1d3 fix(ui): fix mapinfo files never being created (#835)
- .min files are now created for maps that don't have one.
- Saving .min files no longer results in a crash.
- The loading bar is now always cleared when no .min file is present.
2025-11-16 18:45:08 +01:00
Tim Angusandsmallmodel 2c9e500570 XDG home directory support
Co-authored-by: smallmodel <15067410+smallmodel@users.noreply.github.com>
2025-10-19 21:03:23 +02:00
Tim Angus bba5213d38 Extend size of serverInfo_t.hostName (handle longer server names) 2025-10-17 20:28:57 +02:00
smallmodel a07e642820 Slightly increase the brightness of chat messages 2025-10-05 00:39:30 +02:00
Tim Angus 1c27f3edd1 Make sound channel exhaustion warning a Com_DPrintf 2025-10-04 02:06:41 +02:00
Tim Angus 258c5f53f9 Wrap __attribute__s in macros 2025-09-07 20:19:05 +02:00
Tim Angus 6e57eb7d00 Fix various warnings 2025-09-07 19:45:51 +02:00
Tim Angusandsmallmodel e299031470 Reduce duplication in FS path search code
Co-authored-by: smallmodel <15067410+smallmodel@users.noreply.github.com>
2025-09-04 23:28:07 +02:00
smallmodel b038d5ca03 Fix dbg suffix 2025-08-30 20:47:39 +02:00
Tim Angus 4ef547cd86 Remove architecture from binary filenames 2025-08-29 22:51:27 +02:00
Youssef Saeedandsmallmodel f72cc9da77 Use false instead of NULL for boolean (#792)
This PR replaces `NULL` with `false` for a boolean member in an `extensions_table_t` initializer to fix C++ type-mismatch build error on modern C++ compilers.

Co-authored-by: smallmodel <15067410+smallmodel@users.noreply.github.com>
2025-08-28 23:47:57 +02:00
smallmodel ecf70528a7 Move all C++ core classes to the corepp directory 2025-08-24 16:51:11 +02:00
Simon McVittie fabc7c7c74 Remove unused matha.S
Before commit a7d33b1c "(bug #3639) BoxOnPlaneSide rewrite" there
was more code here, but since then the only thing left is the
Invert24To16 function, to which I couldn't find any references since
the beginning of ioquake3's git history.

Resolves: https://github.com/ioquake/ioq3/issues/774
Signed-off-by: Simon McVittie <smcv@debian.org>

client: Remove i386 GNU assembler version of S_WriteLinearBlastStereo16()

This was the last remaining GNU assembler code that was in its own
independent source file, as opposed to being embedded in C code with
GNU `__asm__ volatile` or MSVC `__asm` (which tends to be much easier
to deal with in a modern build system).

When the Quake 3 engine was originally written, this might have been
an "expensive" function when written in portable C, but after 25 years
of CPU development it's less likely to matter (and modern compilers
might produce faster results from the C code anyway).

Resolves: https://github.com/ioquake/ioq3/issues/778
Signed-off-by: Simon McVittie <smcv@debian.org>
2025-08-23 23:30:50 +02:00
smallmodel f885408059 Improve class and event printing with interface classes 2025-08-23 22:28:52 +02:00
smallmodel 282110239e Add USE_CODEC_MAD option 2025-08-13 23:20:04 +02:00
smallmodel 4cd6a51869 Expose the number of bots through minplayers variable
Clients will now show the number of bots (if there are any) in the server browser. Servers must be running a build since this commit
2025-08-11 23:08:04 +02:00
smallmodel 59329b4fb3 Mark member function overriding 2025-08-09 00:39:41 +02:00
Tim Angus 4083d1123f Map SDL gamepad buttons to keys explicitly 2025-08-08 22:58:03 +02:00
Tim Angus 659939352a Add USE_ARCHLESS_FILENAMES 2025-08-08 22:52:26 +02:00
smallmodelandTim Angus e556f58cc4 Reimplement CMake from upstream ioq3 (#781)
This reuse the CMake build system from ioq3, modified to make it work with the C++ code.

---------

Co-authored-by: Tim Angus <tim@ngus.net>
2025-08-08 01:03:07 +02:00
Tim Angusandsmallmodel e47790cd54 Move third party code to code/thirdparty
Co-authored-by: smallmodel <15067410+smallmodel@users.noreply.github.com>
2025-08-02 23:19:02 +02:00
smallmodel 1be22e9343 Use resetString for the fallback renderer 2025-08-02 22:53:13 +02:00
Pan7andsmallmodel 6d2d6e1429 Replace USE_LOCAL_HEADERS with USE_INTERNAL_*
Co-authored-by: smallmodel <15067410+smallmodel@users.noreply.github.com>
2025-08-01 23:02:06 +02:00
Tim Angus 076099d0ed Update OpenAL (headers) 2025-08-01 22:29:51 +02:00
smallmodel 84b1d3e8d1 Fix server items not drawn when using cl_browserdetailedcolors 2025-07-27 00:54:42 +02:00
smallmodel a3f520de8c Format most source files 2025-07-19 23:30:20 +02:00
smallmodel ba3ebed1c9 Stop cinematic when clearing the state 2025-07-07 21:48:29 +02:00
smallmodel bd93897286 Add PMF_NO_WEAPONBAR to hide the weapon bar using drawhud 2 2025-07-02 21:28:12 +02:00