-=:[ ChangeLog ]:=-
20261021
- bump version to 0.32.1
- build with GCC 15 and the MorphOS SDK 3.20 libnix/ixemul ABI
- rebuild zlib 1.2.3, libpng 1.2.59 and jpeg-6b from source
- replace libpng 1.2.8 with 1.2.59 (memory-corruption fixes)
- fix libpng error handling and IHDR validation in image.c
- fix TinyGL ARB extension wrappers for the current SDK
- fix MorphOS-specific input, audio and socket type mismatches
- add per-frame cap on unusable network packets and a
connection status message while the signon is stalled
- treat duplicate netchan packets distinctly from out-of-order
packets, and skip netgraph statistics when the netgraph is off
- use vertex arrays for alias model rendering, with the
multitexture fullbright path kept on the immediate path
- precompute and fold the alias model lighting math
- build surface display lists for world geometry, gated by
the gl_displaylists cvar
- remove the external MP3 player control (Amplifier backend)
- include a startup script and place the binaries in C/
- update README and CREDITS to 0.32.1
- add a per-frame world surface cap (r_worldpolybudget) as a
temporary guard for pathological maps; later removed once
the adaptive-detail work made it unnecessary
- add a per-surface flat fallback: when a world surface's
cluster is over budget, draw it from a solid-colour
display list (no lightmap, no multitexture) instead of
skipping it, so the level stays solid and no holes appear
- make the flat fallback persistent and one-way: once a
cluster has been reduced, it stays reduced for the session,
which removes the texture popping at short range
- replace the per-surface flat fallback with a per-cluster
box LOD: each cluster gets a cached box list coloured from
its surfaces' lightmaps. The box LOD was later removed
because it truncated the level too aggressively
- add a load-time density detector that flags maps whose
largest cluster is far above the median; the detector set
aggressive defaults so the budget could actually bite
- add a soft-knee thinning curve (gl_detail_knee,
gl_detail_sharpness) over the cluster's visible surface
count, replacing the hard knee; the curve was later
replaced by the differential controller
- add an alias cull (gl_alias_farclip, gl_alias_budget) that
skips non-exempt alias entities beyond a distance and
limits the number drawn per frame; players, projectiles
and the view weapon are exempt
- add a per-cluster differential controller for the world
pass: the world pass is measured each frame, the cheapest
world pass seen so far this map is the baseline, and the
difference drives the reduction. Views within the
differential threshold of the baseline are left alone, so
normal maps are not clipped on load. Views far above the
baseline have the clusters that contribute most to the
differential marked flat, one-way, until the differential
is back within threshold
- add a differential controller for the alias pass with the
same shape: gl_alias_farclip and gl_alias_budget are
reduced when the alias pass is over its differential
threshold, bounded by their floors
- add gl_detail_absolute_min_ms and gl_alias_absolute_min_ms
as an absolute floor: a view is only reduced if it is both
worse than the baseline by the differential threshold and
slow in absolute terms. This keeps normal maps that have
one moderately slow view from being touched
- remove the box LOD and the density detector; the
differential controller makes both unnecessary
- remove the per-frame world surface cap; the differential
controller bounds the world pass without a hard cap
- add gl_max_lists to bound the number of display lists
generated per map (VRAM guard on very large maps)
- set the default differential thresholds to 80 ms (world)
and 60 ms (alias), and the absolute floors to 100 ms
(world) and 80 ms (alias); these are the values that
leave normal maps untouched while still squashing the
pathological maps
- update the FuhQuake banner in the console to 0.32.1
-=:[ About ]:=-
FuhQuake 0.32.1 is a revival of the MorphOS port of FuhQuake
released by Mark Olsen in 2017. That port is over ten years
old and was built against a MorphOS SDK that no longer
matches the current one. The original port works well: the
engine runs, the maps load, and the client connects to
servers. This fork is therefore not a rewrite but a
continuation. It builds on the working 0.31 build, patches
the outstanding, known and long-standing bugs that the
original left in place, and performs a set of optimizations
on the client.
QuakeWorld itself is in preservation mode. The network
protocol and the map format have not changed in decades, and
the servers that are still running speak the same protocol
the 2017 client spoke. The 0.32.1 client connects to the
current servers and plays the current matches exactly as the
original did. What has changed is the platform underneath:
TinyGL, the MorphOS 3D API, has moved on, the SDK's compiler
and C library have moved on, and the security posture of the
bundled image libraries has moved on. The point of the
project is to bring the fork up to date with those, compile
it with the current SDK compiler, and produce a client that
is stable, fast and reliable by removing what is no longer
needed, reviewing the code, and refactoring it to current
standards where that is safe to do so.
The project is maintained by Wizardry and Steamworks. The
source, the detailed explanations of each change, and the
running notes on the revival are at:
https://grimore.org/amiga/morphos/reworking_the_fuhquake_quakeworld_game_client
-=:[ Rendering notes ]:=-
The rendering work in this release is aimed at maps that
render very slowly on TinyGL despite the rest of the map
being fast. On such maps the cost is not uniform: looking at
the floor is cheap, looking at a specific dense region is
very expensive. The client cannot make the expensive view as
cheap as the cheap view, but it can stop the expensive view
from dominating the session.
The approach is a per-cluster controller with a differential
trigger:
- World surfaces are grouped into clusters (cells of a grid
over the world bounds).
- The world pass time is measured each frame, and the
cheapest world pass seen so far this map is the baseline.
- The difference between the current world pass and the
baseline is the differential cost of the current view.
- If the differential is within gl_detail_diff_threshold, the
view is not pathological and the map is left alone. This is
why normal maps are not clipped on load: on the first frame
the baseline equals the current frame, the differential is
zero, and nothing happens.
- If the differential is over the threshold, the clusters in
the current view that contribute most to the differential
are marked over-budget and a fraction of their still-
unmarked surfaces is drawn from a solid-colour fallback
display list instead of the textured, lightmapped one.
- The marking is one-way: a cluster that has been reduced
stays reduced for the session, so revisiting the area does
not restore the geometry.
- The alias pass has the same shape: the alias pass time is
measured, and gl_alias_farclip and gl_alias_budget are
reduced when the alias pass is over its differential
threshold.
- An absolute floor (gl_detail_absolute_min_ms,
gl_alias_absolute_min_ms) prevents a view that is
moderately slow but not pathological from being reduced:
a view is only reduced if it is both worse than the
baseline by the differential threshold and slow in
absolute terms.
The result on a map with a singularity is that the
singularity is squashed on first sight and stays squashed,
while the rest of the map is untouched. On a normal map the
differential stays under the threshold and nothing is
reduced. The settings that produced this behaviour are the
defaults: gl_detail_diff_threshold 80,
gl_alias_diff_threshold 60, gl_detail_absolute_min_ms 100,
gl_alias_absolute_min_ms 80.
-=:[ Requirements ]:=-
- MorphOS with a current SDK runtime (the binaries are linked
against the SDK 3.20 libnix/ixemul ABI).
- TinyGL at the latest version available for MorphOS. The
client uses the current TinyGL rendering primitives, and an
older TinyGL will not render correctly.
- Some memory. The client has a fair amount of BSS usage.
- The Quake data files (an ID1 folder from the official
Quake 1 release).
-=:[ Installation ]:=-
The archive is a source tree with a ready-built client. You
do not need to compile anything to play.
1. Unpack the archive.
2. Copy the folder to wherever you want to keep the client.
The folder already contains the fuhquake-gl and
fuhquake-sw executables, the startup script, and the
configuration the client expects.
3. Copy the ID1 folder from your official Quake 1 files into
the same folder, next to fuhquake-gl and fuhquake-sw.
4. Run the startup script from the C folder.
After step 3 the source tree is no longer needed and can be
deleted. The C folder is self-contained.
-=:[ Usage ]:=-
The startup script FuhQuakeGL sets a sensible default
resolution and starts the GL client. Resolution and depth are
command line options; edit the script to change them. The
important ones:
-width GL: 640 SW: 320 display width
-height GL: 480 SW: 240 display height
-depth GL: 24 (GL only) display depth; Voodoo 3 users
should use 16
-window window mode instead of fullscreen
-gamma GL: 1 (GL only) display gamma; 0.5 is a good value
-mem PPC: 4 set to 64 on Apple MacMini PPC
The full set of console and command line options is the
upstream FuhQuake set; the upstream documentation applies to
the engine, not to the MorphOS-specific build. For minimal
eye candy, open the menu, choose options, FPS settings, high
quality. For more, highres textures are available from
http://facelift.quakedev.com/.
There is a list of servers included in servers.txt so you can
directly go into the multiplayer menu and select a server. We
only included some very active servers where you will more
than likely find someone at all times.
Cvars specific to this build that implement TinyGL display
lists and the adaptive rendering needed to display some maps:
-gl_displaylists 1 use display lists for world
geometry (default on; set to 0
to compare)
-gl_adaptive_detail 1 master switch for the world
adaptive detail controller
-gl_detail_cellsize 256 grid cell size in world units
-gl_detail_diff_threshold 80 world differential above which
the controller acts
-gl_detail_absolute_min_ms 100 world pass floor below which
the controller does not act
-gl_max_lists 4096 maximum display lists per map
-gl_alias_farclip 1024 alias cull distance
-gl_alias_budget 128 maximum non-exempt alias
entities per frame
-gl_alias_diff_threshold 60 alias differential above which
the controller acts
-gl_alias_absolute_min_ms 80 alias pass floor below which
the controller does not act
The defaults are tuned so that normal maps are not modified
and pathological maps are squashed on first sight. If a map
is still clipped, raise gl_detail_absolute_min_ms; if a
pathological map is not squashed enough, lower
gl_detail_diff_threshold.
-=:[ Further Documentation ]:=-
The project page contains the reasoning behind each change,
the compiler and SDK details, and the notes on the rendering
work:
https://grimore.org/amiga/morphos/reworking_the_fuhquake_quakeworld_game_client
The original FuhQuake engine documentation is at
http://www.fuhquake.net/doc-help.html and applies to the
engine itself.
-=:[ Copyright and Credits ]:=-
Id Software: Quake, released under the GPL.
A Nourai: FuhQuake.
Anton Gavrilov: ZQuake, the base for FuhQuake.
Mark Olsen: the original MorphOS port (0.31, build 675, 2017).
Wizardry and Steamworks <wizardry.steamworks@outlook.com>:
revival, code review, optimization and refactoring.
FuhQuake is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version
2 of the License, or (at your option) any later version. See
COPYING for details.
|