QNICE-FPGA
QNICE-FPGA copied to clipboard
VGA: Add fractional pixel scaling
This issue is about enabling fractional scaling of the display. The idea is to allow easy implementation of almost-3D games like Wolfenstein or to make smooth 3D text scrolling like in the Star Wars intro! This is for you @sy2002 !!
The idea is to add two new registers that contain the ratio of the pixel width in the screen buffer versus the pixel width on the monitor display, i.e.
VGA$PIXEL_X_SCALE
VGA$PIXEL_Y_SCALE
Each register value contains the size of a screen buffer pixel in units of monitor display pixels, scaled by a constant value of 256. So the default value is 0x0100
, corresponding to a scaling factor of 1. The value 0x0080
would mean only half the screen buffer is used to fill the entire monitor display. In other words, this leads to a magnification by a factor of 2.
The implementation could be as easy as expanding the module vga_pixel_counters
and adding another set of pixel counter outputs. So one set gives the coordinates on the monitor display (and counts by 1 every clock cycle), and the other set gives the coordinates on the screen buffer (and counts by VGA_PIXEL_X_SCALE/256
every clock cycle). The outputs could be called
monitor_pixel_*
and buffer_pixel_*
, respectively. Then the monitor_pixel_*
signals are fed into the vga_sync
module, while the buffer_pixel_*
signals are fed into vga_text_mode
and vga_sprite
etc.
This issue includes writing a cool demo!
@MJoergen Great job! I could not resist to quickly trying your latest commit in branch dev-vga-fractional
on real hardware: As you wrote in your email, the whole thing was a bit slow and jerky. But then I removed the line that syncs with the 60 Hz of the screen:
//while ((y = MMIO(VGA_SCAN_LINE)) >= 480)
And then everything starts to look totally smooth and pretty. I made a small video. Download, unpack and look at this:
Now it is a bit too fast.
The solution: I think what we (reads "you?" :-)) might want to add to the monitor (misc library) and then also via qmon.h
to C is a simple and synchroneous delay
function in microseconds.
Simple and synchroneous means that we do not need the timer interrupt for that. Since we have switched on the cycle-counter be default, it is as easy as counting some cycles (and making sure that we cover wrap arounds). The counters are 48bit or so, so that wrap arounds would only happen every ~65 days if I calculated correctly ;-)
And then we could do a qmon_delay(100000)
(which is 0,1 seconds in microseconds) as the function would be defined like qmon_delay(unsigned long microseconds)
and then all would be good?
P.S. As your new fractional pixel scaling is not breaking anything, you might want to get rid of the branch and put everything in develop?
I'm updated the scrolling to make it more smooth, and I've merged into the develop branch.
Still missing is to update documentation.
It would be nice to make a port of the Wolfenstein game using this new fractional scaling, but I'll leave that to you @sy2002 :-D
Regarding the delay, that would be a nice function to have, but I don't see how it can be used in the little demo program. The point is that the demo program is running entirely synchronuous with the VGA scan line. It could be possible to rewrite the demo program using interrupts to control the VGA port, and then have a main loop with delays controlling the parameters for the interrupt. That would probably - in some sense at least - be more cleaner code.
@MJoergen I just quickly tried it on hardware: Great job! I love it! ❤️
-
To "unbloat" this issue: I moved making a delay function for the Monitor and for C to a new issue and assigned it to me.
-
A Wolfenstein-ish 3D labyrinth is for sure something that I want to do. So I created another issue and assigned it to me.
-
I guess you can close this issue as soon as you updated the documentation.
TODO:
- [ ] Update documentation
- [ ] Make another demo program, showing how to display a checker board in 3D perspective. Perhaps using interrupts?
Make another demo program, showing how to display a checker board in 3D perspective. Perhaps using interrupts?
WOW - that sounds great! Can't wait to see that! :-)