I'm not sure the regressive product is right (overall sign), but that's
actually partly a problem in the math itself (duals and the regressive
product still get poked at, so it may be just a matter of
interpretation).
I'm not sure anything other than == or != has much meaning on anything
but scalars and pseudo scalars, but all comparisons are supported as a
simple boolean test. Any missing components are assumed to be 0. If
nothing else, it makes unit tests easier to write.
It turns out the algebra types make expression dag creation much more
difficult resulting in missed optimizations (eg, recognizing `a × a`).
This fixes the dead cross products in `⋆(s.B × ⋆s.B)`
The switch to using expression dags instead of trees meant that the
statement generator could traverse sub-expressions multiple times. This
is inefficient but usually ok if there are no side effects. However,
side effects and branches (usually from ?:, due to labels) break: side
effects happen more than once, and labels get emitted multiple times
resulting in orphaned statement blocks (and, in the end, uninitialized
temporaries).
Just running through the list of expressions in a block expression
results in label expressions within the block getting printed by
expressions that reference them and thus don't receive the correct next
pointer and wind up pointing to themselves. Printing the labels first
ensures they have the correct next pointer. However, I suspect there are
other ways things will get tangled.
evdev can send multiple event packets for a single "event", but QF was
reading them one per frame, thus the feeling of buffered input at lower
frame rates (because they were buffered in the kernel). This also takes
care of most of the jerky motion with my 3d mouse, though there is still
a weird snap every second or so when rotating and translating at the
same time.
There's still a lot of work needed to separate out quake from
quakeforge, but this lets my test scene get a rather mangled scene
rendering (weird translucency: not sure what I've done wrong: probably
bad clear).
It turns out what I thought was a cascade selection bug was just very
bad choice of cascade steps: factors of 8 just don't work nicely. I'm
not sure that simple factors work all that well, either. I need to make
the cascade system configurable and probably support more cascades.
This puts pixels that have not been rendered at infinity. I was rather
surprised to see fog in my test scene, but it depended on my position
relative to the origin, so something was definitely off (the pixels were
at the origin).
I'm not sure why the final range was only a factor of 4 instead of 8.
There are still issues with range selection, but I'll look into them in
a bit (flying around my little test scene really shows the problems).
IN_UpdateAxis (for nice handling of axis updates, especially relative
motion for mice) and IN_Binding_HandleEvent because registering an event
handler blocks qwaq's internall call to IN_Binding_HandleEvent.
It turns out the parameter pointer save/restore I had done for detoured
functions is required for all nested calls. However, I had actually
completely forgotten about it. I updated the docs for that section.
I'm surprised it took almost two years to discover that I had no
quaternion multiplications in any test code, but getting an ICE for a
quaternion-vector product, and the Hadamard product for
quaternion-quaternion was a bit of a nasty surprise.
While it breaks my little toy game I've been working on (long overdue,
really) and my test scene, at least now qwaq is a little more
independent of quake.
With this, it is a little easier to make qwaq independent of quake. The
default dirconf is still meant for quake, and fs_dirconf can still be
used to override the configuration.
While every possible subsystem needs an initialization call, all that
does is add the actual initialization task to the render graph system.
This allows the render graph to be fully configurable, initializing only
those subsystems that the graph needs.
Scripted initialization is still separated from startup as render graph
creation needs various resources (eg, attachments) defined before
creating render and compute passes, but all those need to be created
before the subsystems can actually start up.
Finally. However, it has effect only when no render config is provided.
When a config is provided, things will break currently as nothing is
done yet, but getting a config in will take some work in qwaq and also
the render graph system as I want to make the startup functions
configurable.
The config is a pre-parsed property list. Currently unsupported by
anything but Vulkan (but only a warning is given, not a hard error at
this stage), and Vulkan doesn't use it yet.
Now, if either ormask is set or the first character of the string to be
printed is 1-3, the quake character set is used, otherwise utf-8 is
assumed. Other changes are for mapping untrusted strings.
Even the comment says it's 8.8, so no need for 32 bits for each value.
It seems to have made a very small improvement to my glsl stub test, but
it's probably just noise (< 0.5%). However, having it "officially" 16
bits means that cached values can be 16 bits thus reducing struct sizes
when I rework lightmap surface data (taking the cache from 16 to 8
bytes).
I had gotten confused about how dynamic lights were calculated and thus
used the wrong radius in the final intensity calculation. Takes care of
the scruffy corners often visible on the dynamic lights.
This gets dynamic lights working again (well, minus the bad updates, I
need to figure out what's up there, but they're nothing new). I guess I
checked only for things running, not that dynamic lights worked.
And clean up the resulting errors. While some were tricky, there weren't
all that many: just some attachment issues and the multi-stage image
copy for scraps.
Fixing scraps required a barrier between copies. It might be overkill,
but a transfer_dst to transfer_dst image barrier worked.
Fixing attachments was a bit trickier:
- depth needed early and late fragment tests to be treated as one stage
- all attachments that were read later needed storeOp = none (using the
extension)
- and then finalLayout needed to be correct to avoid ghost transitions
- as well, for some reason the deffered gbuffer subpass needed a depth
dependency on the translucent pass even though neither one writes to
the depth attachment (possibly a validation bug, needs more
investigation).
It's not perfect (double fog on translucent surfaces, the
scatter/absorption isn't right, and no local lighting on the fog
itself), but it at least seems to look ok.
I think has been one of the biggest roadblocks to breaking free of
quake, so having dual render paths and thus the different new scene load
sequence has proven to be unexpected helpful. There's a lot more to be
done to make the render graph actually usable by anyone but me, but just
making scene load configurable frees up a lot. I think there needs to be
renderer startup/shutdown configuration too, but this seems to be enough
for now.