It was bound to happen eventually, but the input handling module is the first
part of the project to display different behavior across platforms. winit
provides a fairly solid basis for input handling, but Windows and Linux differ
in terms of what sort of event is delivered to the program.
Initially, I used
WindowEvents for everything. This works perfectly well for
keystrokes and mouse clicks, but mouse movement may still have acceleration
applied, which is undesirable for camera control.
winit also offers
DeviceEvents for this purpose. I tried just handling mouse movement with raw
input, keeping all other inputs in
WindowEvents, but it seems that handling
DeviceEvents on Linux causes the
WindowEvents to be eaten.
The next obvious solution is to simply handle everything with
but this presents additional problems. First, Windows doesn't seem to even
deliver keyboard input as a
DeviceEvent -- keyboard input still needs to be
polled as a
WindowEvent. It also means that window focus has to be handled
DeviceEvents are delivered regardless of whether the window
is focused or not.
To add to the complexity of this problem, apparently not all window managers
are well-behaved when it comes to determining focus. I run i3wm on my
Linux install, and it doesn't deliver
WindowEvent::Focused events when
toggling focus or switching workspaces. This will have to remain an unsolved
problem for the time being.
Among the most challenging design decisions in writing the rendering code has been the issue of
ownership. In order to avoid linking the rendering logic too closely with the data, most of the
rendering is done by separate
Renderer objects (i.e., to render an
AliasModel, one must first
The process of converting on-disk model data to renderable format is fairly complex. Brush models
are stored in a format designed for the Quake software renderer (which Michael Abrash explained
quite nicely), while alias models have texture oddities that make it difficult to render them
from a vertex buffer. In addition, all textures are composed of 8-bit indices into
and must be converted to RGB in order to upload them to the GPU. Richter interleaves the position
and texture coordinate data before upload.
The real challenge is in determining where to store the objects for resource creation (e.g.
gfx::Factory) and the resource handles (e.g.
gfx::handle::ShaderResourceView). Some of these
objects are model-specific -- a particular texture might belong to one model, and thus can be stored
in that model's
Renderer -- but others need to be more widely available.
The most obvious example of this is the vertex buffer used for rendering quads. This is conceptually
straightforward, but there are several layers of a renderer that might need this functionality.
ConsoleRenderer needs it in order to render the console background, but also needs a
GlyphRenderer to render console output -- and the
GlyphRenderer needs to be able to render
textured quads. The
ConsoleRenderer could own the
GlyphRenderer, but the
needs access to render ammo counts.
This leads to a rather complex network of
Rcs, where many different objects own the basic building
blocks that make up the rendering system. It isn't bad design per se, but it's a little difficult
to follow, and I'm hoping that once I have the renderer fully completed I can refine the architecture
to something more elegant.
The HUD now renders armor, health and current ammo counts in addition to the
per-ammo type display at the top. The latter uses conchars, which, as the
name suggests, are used for rendering text to the in-game console. Now that I
can load and display these I can start working on the console, which ought to
make debugging a great deal easier.
Unfortunately, the client is still plagued by a bug with position lerping that
causes the geometry to jitter back and forth. This is most likely caused by bad
time delta calculations in
Client::update_time() (Github), but I haven't
been able to pinpoint the exact problem -- only that the lerp factor seems to go
out of the expected range of
[0, 1) once per server frame. I'll keep an eye on
I've started rebuilding the site with Gutenberg
now that I actually have something to show for the past couple years (!) of
on-and-off work. I figure a dev blog will be good to have when I look back on
this project, even if I don't update it that often (the blog, not the project).
It'll probably take me a while to get the site in order since my HTML/CSS skills
are rusty, but the old site was impossible to maintain so this ought to make
As for the project itself, the client is coming along nicely -- I'm hoping to
reach a playable state by the end of the year, even if there are still some
graphical bugs. Now that the infrastructure is there for networking, input,
rendering, and sound, I can start work on the little things. The devil is in the
Defining the ultimate scope of the first alpha release is probably going to be
one of the biggest challenges. There are so many features I could add to the
engine, and I suspect many of them are far more complicated than they seem on
the surface. Failed past projects have taught me to be wary of feature creep,
so the alpha will most likely just be a working client and server -- no tools,
no installers, no plugin support or anything like that. With any luck I'll be