Previous journal: | Next journal: |
---|---|
0063-2023-04-18.md | 0065-2023-04-23.md |
In recent work I've been able to FAKE this screenshot:
Raybox generates this by using a stubbed trace_buffer
which just loads the column height (and side)
data from a .hex
file. That file was earlier dumped from an actual render in raybox-app
.
Since then, I've implemented a stub/experiment for a tracer
, which so far just proves that it can do "work" during VBLANK, and do it with a variable
number of cycles, writing into the tracer_buffer
ready for rendering the next frame.
So in that experiment, and the overall version of the code it's in, we have the following:
We can see a map overlay, rendering the contents of the
map ROM
(loaded from map_16x16.hex
).
The scene itself is not yet using this map_rom
data. The right-hand two-thirds of the screen show
the same pre-generated height data, but left-hand one third shows new height data that the tracer
experiment wrote into the trace_buffer
. For each of 240 columns, it takes the fixed constant 240
and divides it by the column number, and it does this by simply counting the number of divisor
subtractions that reduce the dividend (i.e. the 240), keeping whatever's left as the remainder.
If that remainder is 0 (i.e. the numbers evenly divide), the side
value is 1 (i.e. bright blue),
otherwise it is 0 (dark blue).
This simply proves that the tracing can take a variable amount of time (even per column),
and it will write usable and consistent data into trace_buffer
. So long as it completes
before the next frame starts, we should be good.
- Might need to consider making cocotb or Verilog TB tests for individual modules
- Learn fixed point and implement/test
- Implement reciprocal
- Implement divider
- Write the actual tracer
- Come up with a better implementation for the trace buffer (big ring/shift memory or OpenRAM?)
- Work out how to implement the map ROM. Internal and external options (controllable by GPIO)?
- Implement input control
I'm going to try a top-down approach, and write the main code for the tracer first, then try stubbing the modules that it needs (namely maths stuff), then finally try implementing all those modules properly.
I might still need to get fixed point basics implemented first, because otherwise a lot of these modules (even stubs) to be implemented won't be very helpful in the long run.
A proper optimised version of this will precalculate as much as possible, and use constants if we can. For example, the rays-from-camera-horizon stuff could be worked out in advance.
- Will we need to use signed signals when we work with fixed point, in our specific application? Maybe.
- Interesting example of
always_comb
in "Catching the Overflow". Note how there are two assignments to signalz
, one inside anif
. How does SystemVerilog decide which wins? Is it always the last, or the one that's most specific? - To what extent is it necessary to use actual fixed-point everywhere, given certain certain things like player position could be in whatever units we like, so long as we scale everything else appropriately throughout the map. For instance, if we assume each map cell can be painted with a 64x64 texture, then map cells could just be on every multiple of 64. We can then use fixed-point, when needed, for much more precise ray tracing and sub-pixel stuff (if that's even truly necessary).