Commit Graph
60 Commits
Author SHA1 Message Date
bearstonemandClaude Opus 5 862d36a9ba chore(vr): take the diagnostics back out
Removes r_flatColor, r_traceSurf, r_forceGenericStage, r_noCull, r_noDepth,
r_noFog, r_invertCull, vr_debugPanel and its magenta panel clear, along with
R_TraceSurface, R_DriverGet, R_FlatColorPush/Pop and the GetFloatv/IsEnabled
entries added to qgl.h for them. Around 570 lines.

Everything they were built to find is fixed, and the fixes are all still here:
the cull face forced past gl4es's cache, RB_SurfaceFace's index type, the window
resize vid_restart, the frustum built from the runtime's tangents, the terrain
cone sized to the headset, and the VR layer's state calls routed through gl4es.
Verified rendering on the device after the strip, with no overrides at all.

vr_captureEye stays, defaulted off. It writes the eye buffer to a TGA and it is
the one probe that consistently earned its keep - a picture settled in one look
what rounds of description could not. Inert unless switched on.

misc/android/autoexec.cfg is down to that single line. Nothing in it is load
bearing any more.

Also records a third instance of the session's recurring mistake in the gl4es
doc: r_noDepth was declared, registered and tested for several device runs while
the edit meant to read it had silently failed to apply. Every result attributed
to it was a no-op, and it sat in the "known good" configuration taking credit for
what disabling culling was actually doing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 07:38:40 -07:00
bearstonemandClaude Opus 5 b49e34a9ed fix(vr): stop the window resize restart, and the indices the world was drawn with
Two bugs, both found on the device, both with the evidence recorded in
VR_RENDERER_HANDOFF.md sections 8 and 9.

The menu was a renderer restart. SDL reports a window resize; the handler
compares it against glconfig.vidWidth/Height, which in VR is the eye buffer and
never the Android surface, so it can never match. It set r_customwidth,
r_customheight and r_mode -1 - cvars the renderer then ignores, because the VR
resolution comes from GetVRRenderResolution - and scheduled a vid_restart that
destroyed and rebuilt the GL context and the OpenXR session under a running
frame loop. The panel drew a full 256/256 samples up to CL_Vid_Restart_f and
nothing ever after. VR_PORT_STATUS called that restart harmless; it was the
whole bug.

RB_SurfaceFace declared its output pointer as unsigned* and assigned
tess.indexes to it, which is glIndex_t* - unsigned short under gl4es. Every
index went in four bytes apart in a two byte array, so each triangle picked up
whichever vertex the zero high halves pointed at. That was the world smeared
into streaks that dragged its textures with it; models never come through that
function, which is why they were always correct. ProjectDlightTexture had the
same fault in hitIndexes. The compiler had been reporting it all along, under
sixty other warnings in that file.

Also: renderergl1 culled against the game's symmetric fov rather than the
runtime's asymmetric per-eye frustum; the VR layer set viewport, cull, depth,
blend, colour mask and scissor state natively while gl4es caches all of them and
drops the engine's next request for a value its stale copy already claims; and
GfxInfo_f reported a different draw route than R_DrawElements took.

The remaining diagnostics are CVAR_TEMP and default off. vr_captureEye is worth
keeping: it writes the eye buffer to a TGA, and one image settled questions that
six rounds of verbal description could not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 02:29:43 -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 6f34f4524c feat(vr): put the headset behind the fixed function renderer
Everything the VR work had built so far lived in renderergl2. This carries it
across to renderergl1, which is the renderer the port is moving to.

Most of it transfers unchanged: the head pose composed onto whatever camera the
game asked for (R_ApplyVRView, in RE_RenderScene so it follows cutscenes and
ladders as well as the player), the asymmetric per-eye frustum and vr_fovZoom in
R_SetupProjection, the eye render resolution asked for through
GetVRRenderResolution rather than r_mode, and the sprite paths that face the
viewer's position rather than the view plane.

Two places came out simpler than rend2. Everything 2D in this renderer goes
through Set2DWindow - RB_SetGL2D is a one line call to it - so the HUD's
convergence has a single place to be applied rather than two that had to be
kept in agreement. And RE_SetDefaultFramebuffer is nearly nothing: renderergl1
predates framebuffer objects, has none of its own and never touches the
binding, so redirecting an eye is one bind with no FBO_Bind to intercept and
nothing to restore.

glBindFramebuffer is resolved on first use rather than declared with the rest
of qgl, because renderergl1 has no extension probe of its own - it goes through
GLimp_GetProcAddress so it reaches gl4es like everything else the renderer
calls, and gl4es stays aware of which framebuffer is bound.

renderergl2 still builds and is unchanged in behaviour.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 21:38:59 -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
bearstonemandClaude Opus 5 f3ca623053 fix(renderer): let renderergl2 initialise on OpenGL ES contexts
GLimp_GetProcAddresses() failed on every OpenGL ES context, so the GL2
renderer could not start on any ES target. Two independent causes:

QGL_1_1_PROCS carried five entry points that exist in no version of
OpenGL ES - glCallList, glDrawPixels, glFogi, glLineStipple and
glPixelZoom. That list is shared by the desktop and ES paths, so
requiring them there failed the whole load. Upstream keeps ES-incompatible
functions in QGL_DESKTOP_1_1_PROCS; these are moved there to match. Only
renderergl1 calls them - every use in renderergl2 sits inside an
"#if 0 // FIXME: unimplemented (GL2)" - so nothing loses a function it
actually invokes.

The ES 3.0 context was also only ever requested under __EMSCRIPTEN__.
Everywhere else the highest ES context asked for was 2.0, and since EGL
returns a genuine ES 2.0 context when that is what was requested, ES 3
was never reached even on hardware that supports it. It is now requested
first on all platforms.

Verified on a Meta Quest 3 (Adreno 740): renderergl2 now comes up on an
ES 3.2 context and compiles all 115 GLSL shaders. Desktop builds of both
renderers are unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 15:19:10 -07:00
erysdren 9db02300dc Improve PVR image support 2025-12-07 15:38:12 +01:00
erysdren 7ee122f0b2 add support for loading PVR images
this is from Q3A for Dreamcast
2025-11-25 20:30:02 +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
Tim Angus ce9199ea1e Better warning fix (that doesn't crash) 2025-09-07 22:46:02 +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
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
Tim Angusandsmallmodel 8708953e96 Move puff.* to renderercommon
Co-authored-by: smallmodel <15067410+smallmodel@users.noreply.github.com>
2025-08-02 23:00:57 +02:00
Tim Angus b0ca50c4c5 Merge identical tr_subs.c into renderercommon 2025-08-02 22:58:22 +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 Angusandsmallmodel c9fcd723db Update integrated third-party libraries
Co-authored-by: smallmodel <15067410+smallmodel@users.noreply.github.com>
2025-07-14 21:44:52 +02:00
smallmodel a924fc252b Use the hardware cursor in windowed mode (#718)
In windowed mode, the mouse is no longer grabbed when one of the UI/console catcher is active. When a UI menu is active, the system's hardware cursor is shown, using the game's custom cursor texture, instead of simulating and rendering the cursor in-game.

* Add exports to load a raw image from the renderer
* Set the hardware cursor to the game's custom mouse cursor texture
* When mouse is not grabbed, the mouse gets updated with absolute mouse position, relative to the window position
2025-05-02 16:52:39 +02:00
Sébastien Noel b5e49df180 fix build with shared jpeg library (#701) 2025-03-19 14:46:12 +01:00
smallmodel 6d21d52d3e Define USE_INTERNAL_JPEG macro for renderer when using the internal JPEG 2024-12-20 23:31:03 +01:00
smallmodel 3d950764a2 Add minimal renderergl2 implementation
This implementation should just let the game run without crashing, the renderer doesn't show anything yet
2024-12-20 01:23:00 +01:00
smallmodel 390c1d3f3d Move tiki_mesh inclusion to renderercommon CMakeLists 2024-12-19 21:18:54 +01:00
smallmodel 38427fa3c5 Add support for compiling both opengl1 and opengl2 when they're built as shared libraries
renderercommon is now used, which will appropriately use opengl1 when building static libraries, or compile both opengl1/opengl2 modules when building shared libraries
2024-12-18 23:24:04 +01:00
smallmodel 28bdd1b2b3 Made the renderer modular and loadable
This removes coupling between the renderer and UI/client functions. An option USE_RENDERER_DLOPEN was added to specify whether a renderer module should be compiled and loaded, instead of integrating the renderer into the executable directly. This opens the door for a new renderer
2024-12-06 00:15:19 +01:00
smallmodel 4f699f3b58 Add support to compile renderergl2 (currently unimplemented) 2024-12-01 19:21:07 +01:00
smallmodel 7e6b0a1c2b Remove SMP and render thread code, as they're unused 2024-12-01 16:32:19 +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 5403577642 Fix the return value of FS_Seek
It returns a negative value on failure, so handle that properly
2024-09-25 21:04:55 +02:00
smallmodel 844a72e0f3 Add DrawPixels and PixelZoom 2024-09-15 01:11:52 +02:00
smallmodel cd9b1a741f Match CG_PermanentMark parameters
This fixes #355
2024-09-07 23:57:17 +02:00
smallmodel e806c1ddf1 Move MAX_MARK values to tr_types_new.h 2024-09-04 20:23:20 +02:00
smallmodel 0bbf39660e Added R_GetShaderName and R_GetModelName 2023-09-06 20:31:28 +02:00
smallmodel 6d2d35e82d Fixed compile errors on newer versions of clang 2023-09-05 19:39:57 +02:00
smallmodel 9315cfa488 Added mohaas/mohaab variables 2023-08-28 17:35:54 +02:00
smallmodel 0fea47bb69 Added Draw_StretchPic2 2023-08-15 22:44:37 +02:00
smallmodel 6f8fee47f2 Using const char* for LV_ConvertString 2023-07-30 11:38:18 +02:00
smallmodel cf61471b2d Added MAX_REAL_LIGHTS 2023-07-24 20:14:16 +02:00
smallmodel 2866bfdd04 Fix for DrawStretchRaw and const params 2023-07-17 20:44:09 +02:00
smallmodel 52f60e647d Implemented R_MarkFragmentsForInlineModel and R_BoxSurfacesForBModel_r 2023-07-17 20:09:00 +02:00
smallmodel 69c2ea4614 Using font system from SH/BT to support different code pages 2023-07-17 00:24:04 +02:00
smallmodel f66ce78a56 Using const for pointBuffer 2023-07-15 20:18:08 +02:00
OM 02993eaa9b Backported ioq3 features 2023-06-25 19:35:41 +02:00
OM 2b9241ee01 Increased **MAX_SPRITES** to 2048 2023-05-29 13:48:19 +02:00
OM 5575b68c94 Added CallList, Fog and LineStipple 2023-05-28 22:55:14 +02:00
OM 7b79877516 made renderer (original quake III) work with SDL 2023-05-27 22:23:03 +02:00
OM 4a582cfbb5 Updated 2023-05-27 21:39:56 +02:00
OM 8e1b2ea296 Updates 2023-05-27 21:02:16 +02:00
OM f1f9ed744d Updates 2023-05-27 16:19:31 +02:00
OM 3d223f5a5d Updates 2023-05-27 15:36:19 +02:00