sy2002 / QNICE-FPGA

QNICE-FPGA is a 16-bit computer system for recreational programming built as a fully-fledged System-on-a-Chip in portable VHDL.
http://qnice-fpga.com
Other
69 stars 15 forks source link

Add multicolour support in VGA: Hardware and Emu #17

Open MJoergen opened 4 years ago

MJoergen commented 4 years ago

Changes to programming model: The print character at VGA$CHAR will be extended to read/write a full 16-bit value instead of as today an 8-bit value. The lower 8 bits will remain the same as before, i.e. the ASCII character code. The upper 8 bits will be divided into two groups of 4 bits as follows:

The clear screen function will reset all characters to 0x20 (space) and will assign a default foreground and background colour to each character.

The cursor blink mode will swap foreground and background colour of the character.

Changes to VHDL code: The video_bram module will have 16-bit data bus instead of 8-bit. This will double the amount of video RAM needed, going from 32 Block RAMs to 64 Block RAMs. Minor changes in vga_textmode.vhd. Most of the changes will be in the vga80x40.vhd module.

Changes to application code: As written, all application code will break, because the value written to VGA$CHAR must now contain colour information as well in the upper 8 bits. One possible way to avoid this break, is to have different palettes for foreground and background. In other words, selecting both foreground and background colour as 0 would lead to the current behaviour of green on black.

sy2002 commented 4 years ago

@MJoergen Thank you: πŸ‘ This sounds awesome! πŸ˜ƒ It would be super-great, if you could implement this multicolor support in VGA! Additionally, it would be the cherry on the cake, if you could change the font ROM into a (preloaded) font RAM and add some register(s) to the VGA so that one can change the characters/font RAM. This would allow us to have (similar to a C64) character based graphics, which for example would allow me to program "Q-Chess" - a QNICE based visual chess program... ...something I planned to do since a while :-)

EDIT:

PS: It woul be cool, if we can avoid breaking existing application code by implementing your idea: two different palettes for foreground and background, where "0" selects green and black

PS2: It would be even cooler, if you added some more additional VGA registers to be able to modify the standard palette: so that we have 16 foreground and 16 background colors (default, let's search for some nice 16 bit default palettes somewhere in the net and take those): BUT, the programmer can use these additional VGA registers to define his own palette from the 3 8-bit RGB values

PS3: Just a side note: Please be aware that in vga80x40.vhd the HDMI data enable is necessary for the MEGA65 version of QNICE (please see also https://github.com/sy2002/QNICE-FPGA/blob/develop/doc/README.md#hdmi) .

sy2002 commented 4 years ago

@MJoergen As V1.6 might still take some weeks to complete, maybe you'd like to start with the VGA topic for V1.7? (But please including my above-mentioned comment :-). I think it is save to branch from dev-io-addr and do the VGA part there, because we will not touch the VGA part during the rest of the V1.6 release work.

EDIT: Depending on your preferred style of working, you might want to enhance the emulator's VGA capabilities first, before doing the hardware - and write some test programs in test_programs for it. Or you do it the other way round. Is enhancing the emulator something, you'd like to do, or is C and SDL not that much your thing? (Then, I could do it, but then I would suggest you do the hardware, first and I do the emulator later during V1.7)

MJoergen commented 4 years ago

I'm a bit hesitant to start on this issue right now, with all the loose branches. I'd prefer making a new branch out from the develop branch, when the current pending changes (dev-io-addr and dev-int) have been merged into develop.

Do you have an estimate for when you expect to update the develop branch (and remove dev-io-addr and dev-int)?

EDIT: I'm quite keen on updating the VGA hardware part, and I have further ideas as well. But I might just have a look at the emulator as well - I'm always keen to learn new stuff!

sy2002 commented 4 years ago

re Emulator and Hardware: Sounds good! Learning new stuff is fun! :-) Then I suggest that you do both: VGA Emulator Update plus VGA hardware, i.e. this issue is for the hardware part and for the emulator part. I renamed the issue accordingly.

re Timing estimate: I will be on a 2,5 weeks vacation starting on August, 21st and I strive to have merged back dev-int and dev-io-addr into develop until that point. I guess the release V1.6 will not be ready until then, because of the loose ends at the MEGA65 part, but at least we would have a good and semi-stable develop branch and the loose ends in the other branches would be gone. That could be a great starting point for your dev-color-VGA branch.

sy2002 commented 4 years ago

Off-topic: Hey Michael, when I wrote the above mentioned comment about Q-Chess, I was absolutely not aware, that you did your own mchess and mchess2 engines already πŸ‘ Today I stumbled over it. So here is a suggestion: In a a bit more distant future (winter, spring, summer next year) - for sure no hurry - you could port a heavily simplified version of mchess or mchess2 to QNICE. Or write a new one: "simple-mchess". Either using C (vbcc) or assembler. The latter one might be preferred as we do not have that much RAM as you know and it might also be a nice intellectual challenge to write a chess engine in pure assembler ;-) But hey - they were able to have chess engines on the C64 back in the days ;-) ... and I would then volunteer for the graphics part using sprites and/or character-based-graphics...

MJoergen commented 4 years ago

That's an awesome idea! Nice challenge indeed to write a chess engine in assembler. I haven't done that before :-)

sy2002 commented 4 years ago

Here are some more thoughts about color VGA: As we want to be able to do some nice graphics stuff, we need a fast way to access the color VGA's memory. I propose a set of registers in the VGA plus more smarts in the mmio_mux to enable the mapping of VGA memory into the address space of the CPU:

VGA$STATE           .EQU 0xFF30 ; VGA status register <== enhance existing register
    ; Bit 12: Enable/disable memory mapping: 0=default=disabled, 1=enabled
    ; .... other bits stay as they are today
VGA$MM_VGA          .EQU 0xFF39 ; Start address of memory map: VGAs memory
VGA$MM_CPU          .EQU 0xFF3A ; Start address of memory map: QNICEs memory
VGA$MM_SIZE         .EQU 0xFF3B ; Size of the region that shall be mapped

This is elegant and fast and does not need a MMU.

Michael, your thoughts?

MJoergen commented 4 years ago

Doesn't this collide with the more general MMU we are hoping to write one day ? I mean, this is essentially an MMU functionality, and when we get the "real" MMU then we should probably deprecate this VGA-MMU, so as not to have duplicate functionality.

Alternative: How about we postpone this idea until we start on the "real" MMU? I see your suggestion as an optimization, and I see nothing wrong with using the existing approach with VGA_CHAR to access video memory.

My current plan for multi color support will not significantly increase the usage of video memory. Instead, the value written to VGA_CHAR will contain BOTH color and character information, so the same number of writes as before.

bernd-ulmann commented 4 years ago

I agree with Michael - that is ideally implemented by means of a (simple) MMU. :-) I, too, would postpone this until we have decided on an MMU implementation. :-)

sy2002 commented 4 years ago

(For now) I am OK with it :-) I was just pondering about text based graphics by changing the font in realtime (as on C64) and using the VGA_CHAR is quite slow...

sy2002 commented 4 years ago

Michael, thank you for the great phone call today! And thank you for opening up the list of additional wishes :-) So here they are:

When it comes to the QNICE default palette, an inspiration might be taken from PCs VGA:

grafik

(taken from https://www.fountainware.com/EXPL/vga_color_palettes.htm)

*But for sure, when we google a bit, there might be even nicer ideas for a 16-color palette.**

As soon as you would like to brainstorm more about that: On Saturdays I am very flexible. The two of us can also make a GoToMeeting session in September (I am back on 10th)

MJoergen commented 4 years ago

List of changes to hardware

Font RAM and Palette RAM

I propose the following additional registers:

To access either the Font RAM or the Palette RAM, the CPU must first write the desired address and then either read or write the data. Both the Font RAM and the Palette RAM can be reset to the default Font and default Palette by setting bit 15 of the corresponding address register. This bit will automatically clear when the reset is complete.

sy2002 commented 4 years ago

Sounds perfect πŸ‘

MJoergen commented 4 years ago

Tested on hardware:

The command sequence:

M C FF3E 0010
M C FF3F 0444

changes the background colour to dark gray!

sy2002 commented 4 years ago

I am stunned :-) This is amazing, particularly because I thought this would be something until Christmas πŸŽ„ ... and now you did it already now ;-) Congratulations πŸŽ‰πŸΎπŸŽŠπŸŽˆ

What default palette did you choose?

Regarding my comment from the other day, I guess some testing around the Monitor's scrolling makes sense because your page amount is smaller...

Your speed of progress is breathtaking πŸ˜€

MJoergen commented 4 years ago

Actually, I've preserved the 20 screen buffer. My previous comment about 9 screens was a calculation error. So there is 64k words of screen memory, just like before.

MJoergen commented 4 years ago

Notes about graphics mode

I propose two different graphics modes: Low-resolution and High-resolution.

Low-resolution

This will be 320x200 pixels, i.e. 64k pixels in total. Using the Display RAM of 64k words gives exactly one word (i.e. 16 bits) for each pixel. The low 12 bits could go straight to the RGB output, and the high 4 bits are leftover. They could e.g. be used for layering information (i.e. depth) when used together with sprites, see below. In the Low-resolution mode, the Font RAM and the Palette RAM are not used.

High-resolution

This will be 640x400 pixels. We now have just 4 bits per pixel, and this gives 16 different values. This value could then be used as index into the Palette RAM, giving a total of 16 colours for the entire screen.

When raster line interrupt is implemented, then the Palette RAM could potentially be updated for every raster line, giving many more colours on the screen. But still a maximum of 16 different colours on any raster line.

Memory Bandwidth consideration in graphics mode

In graphics mode (both high-resolution and low-resolution) I propose to add a new register to the VGA module:

VGA$ADDRESS   .EQU 0xFF39

To write to the Display RAM amounts to writing the address to the address register VGA$ADDRESS and then writing the value to the data register VGA$CHAR, but with the additional feature: Each write (and read) to the data register will automatically increment the value of the address register. This auto increment will make copying data to the Display RAM just as fast as a regular memcpy().

Basically, a loop around the instruction MOVE @R0++, @R1, where R1=VGA$CHAR can be used to copy large amounts of data into the Display RAM, provided the data is placed sequentially. With this auto-increment feature I think we can postpone the MMU, and can make great graphics very soon!

Optionally, we could re-use VGA$CR_X instead of using a new register. Furthermore, we could make the auto-increment configurable: For instance, the value in VGA$CR_Y can be the amount to auto-increment with. So a value of 0 disables auto-increment, while a value of 320 (or 640) can be used to draw vertical lines, and a value of 0xFFFF would do an auto-decrement. Perhaps this is not very useful, so the initial implementation could just hard-code the auto-increment value to 1.

Regarding auto-increment, we (probably) need to fix the Issue #55 , where memory accesses tend to last several (consecutive) clock cycles rather than just one clock cycle.

Finally, we need two bits in the VGA$STATE register to enable the two graphics modes.

Comments and suggestions are very much appreciated.

MJoergen commented 4 years ago

Notes about sprites

Here are some ideas I have about sprites.

Resolution and colour depth

I propose two different resolutions for each sprite: High-resolution and Low-resolution.

Low-resolution (4 colours)

In this mode, there are 2 bits per pixel, and the sprite is 8x8 pixels in size. The sprite bitmap takes up 8 words of memory.

Each pixel has a colour value of 2 bits, which gives an integer value 0 - 3. This value is used as an index into a Sprite Palette consisting of 4 RGB colours (4 words of memory).

High-resolution (2 colours)

In this mode, there is 1 bit per pixel, and the sprite is 16x16 pixels in size. The sprite bitmap takes up 16 words of memory.

Each pixel has a colour value of 1 bit, which gives an integer value 0 - 1. This value is used as an index into the Sprite Palette. Palette colours 2 and 3 are not used in this mode.

Transparency

Each sprite can have transparency enabled or disabled. If transparency is enabled, then Palette Index 0 is treated as a transparent colour.

Magnification

Each sprite can be magnified to twice the size in either X and/or Y direction.

Layering / depth

Each sprite has an associated depth that determines whether the sprite goes in front of or behind the text/graphics. For now I propose just a single bit indicating Front or Behind.

Number of sprites

There is the issue of memory bandwidth (i.e. whether we can read all the sprite information needed for a given raster line), and the amount of memory needed, but I'm pretty confident we can implement 256 sprites in total.

Memory usage

Each sprite needs 16 words for bitmap information as well as 8 words for configuration/position/palette. With 256 sprites this makes a total of 6k words, which should fit into 4 BRAM's in the FPGA.

Register Map for each sprite

reg 0 : X position
reg 1 : Y position
reg 2 : Control (see below)
reg 3 : Pointer to sprite bitmap
reg 4 : Palette colour 0
reg 5 : Palette colour 1
reg 6 : Palette colour 2
reg 7 : Palette colour 3

Control register decoding:
Bit 0 : Resolution (0 = High-resolution, 1 = Low-resolution)
Bit 1 : Transparency enabled
Bit 2 : Magnify X
Bit 3 : Magnify Y
Bit 4 : Mirror X
Bit 5 : Mirror Y
Bit 6 : Depth (0 = Front, 1 = Behind)

Comments and suggestions are very much appreciated.

bernd-ulmann commented 4 years ago

Just a quick note to let you know how impressed I am by your work and the sprite implementation! :-) I am sorry that I cannot contribute here anything since I have never even used sprites (apart from a few experiments on my ZX Spectrum in the 1980s :-) ). I am looking forward to see them in action and am curious what demo Mirko will write using them. :-)

sy2002 commented 4 years ago

Thank you for your great specification work. I think thanks to you, QNICE-FPGA will become a super fun to work with retro-graphics-machine :-)

Here are some thoughts:

Graphics Modes

Sprites

Default Palettes

Some hints a about the emulator

Independent of my comments about gfx and sprites, here are some hints about how the VGA emulator works today to help you find your way through the code when enhancing it to support the new hardware capabilities.

MJoergen commented 4 years ago

Thank you for your comments, I really appreciate that!

I have some additional feedback to your comments:

Thank you very much for your hints on the emulator! I've now got the VGA Multicolour text mode working in the emulator.

sy2002 commented 4 years ago

16-bit colour: I was only considering the Nexys4DDR, which only has 12 bits of colour, but I guess we should be prepared for other platforms that have more colour bits (MEGA65?)

Yes. The MEGA65 for example is having a VDAC and full 24bit RGB.

So what do you say to this idea: 1 bit for layering, and 15 bits for colour (only 12 bits shown on the Nexys4DDR board)?

Sounds great. πŸ‘

Smooth scrolling will be implemented in both text mode and graphics mode. I've called it "Pixel scrolling"

Cool - I guess I want to write a sidescroller Jump'n'Run πŸ˜ƒ

Double buffering. Wouldn't this require doubling the amount of Display RAM ?

Yes it would require double the RAM. For Artix 7 and newer no problem I guess. For older chips (in case I manage to get ISE up and running again): Maybe you can make a generic DOUBLE_VRAM : boolean somewhere where we can switch it on/off before synthesizing? Could be a constant that we nurture in env1_globals.vhd. Double Buffering is needed for flicker free animation, e.g. if we would do textmode graphics (using font as graphic elements).

Animated sprites: Good point, I hadn't thought about that. I've updated the Sprite Register Map to include "reg 3 : Pointer to sprite bitmap".

Thank you - this is a very important topic. So we should have enough sprite RAM to be able to have animated sequences such as these: https://moose-stache.itch.io/rpg-asset-pack (and others ;-) )

Larger sprites: Ok, could you give some suggestions (wish list) for sizes/dimensions of sprites?

IMHO 32x32 pixel with a lot of colors, such as 256 colors in a palette.

Palette: So far, I've just chosen eight pure RGB colours (e.g. 255, 255, 0) as well as eight lighter colours, e.g (255, 255, 128). I really have no idea what palette to choose, so feel free to come with something better (anything!). The default colours are defined in the file vhdl/vga/palette.txt.

My proposal would be this palette, as it is an "optimum 16 color palette in terms of expressiveness" πŸ˜„

http://alumni.media.mit.edu/~wad/color/palette.html

grafik

Selection Rationale

In order to maximize the use of the color palette for classification, I started by selecting the colors "by name" using the eleven colors that Boynton says are almost never confused: black, gray, white, red, blue, green, yellow, orange, brown, purple, and pink. To these, I added another gray (giving four achromatic colors). The remaining four colors I selected (still only by name) as follows:

Here are the values:

http://alumni.media.mit.edu/~wad/color/numbers.html

We might want to have the names in sysdef.asm for convenient usage.

For preserving the 100% retro feeling in Q-TRIS I would manually change one of the values to "100% green" as today :-)

MJoergen commented 4 years ago

That's a nice palette. I've updated the design and emulator to use the new palette in 15-bit mode.

MJoergen commented 4 years ago

@sy2002 @bernd-ulmann : I'm looking into adding scan line interrupt, and I don't know how to implement that in the emulator. As far as I understand the emulator, a separate thread is displaying the entire screen at a time, at a roughly constant FPS.

With the 640x480x60 resolution, the scanline gets incremented at a frequency of 31.5 kHz, i.e. every 31 microseconds.

Ideally, I would like two registers:

But the question is whether the concept of "current scan line" even makes any sense in the context of the emulator, and if not, how to "emulate" that behaviour. I'm a bit low on good ideas right now ...

bernd-ulmann commented 4 years ago

That is a very good question. The VGA-emulation was done by Mirko, so we might have to ask him. :-) Issuing an interrupt in the emulator is simple as its basically just setting to global (argl) variables as in timer.c, but I do not know of a line-interrupt concept fits into the VGA implementation...

MJoergen commented 4 years ago

One more thing about sprites: We need collision detection as well.

I presume we want to have detection of both sprite-sprite collision as well as sprite-text collision. I'm not sure what a good register map interface would be.

Here is my initial suggestion for sprite collision detection register map.

The above register map will ignore three sprites colliding, as well as ignore multiple simultaneous collisions. In both cases, only a single collision is detected.

Perhaps we could include a collision mask bit for each sprite to indicate whether this particular sprite should be included in any sprite collisions.

Ideas and feedback are as always most welcome.

sy2002 commented 4 years ago

On the Emulator

I'm looking into adding scan line interrupt, and I don't know how to implement that in the emulator.

Indeed this is quite a challenge, because currently, the emulator is not cycle accurate when it comes to the CPU and it also does not have any concept of a scan line: The video memory is written "as you go" (when writing the registers) and then the whole memory is copied using streaming textures. I suggest, that you implement the scan line interrupt in hardware and add the larger task - something like "turn the emulator into a cycle accurate system including VGA" - to TODO.txt.

About the hardware implementation: I think your ideas about the registers FF3A for scan line to generate interrupt on and FF3B for current scan line being displayed by the VGA module are absolutely perfect.

On Sprite collisions

Thank you for bringing this up! You are right and this is an important topic. I am currently not fully aware, how you want to implement sprites. Are we working with a color palette / transparacy layers? How many colors (I opt for many ;-)).

Anyway: Your above-mentioned ideas a great. Here are some more thoughts.

I think, that we might want to consider the concept of sprite groups (just as the Amiga had it). Reason: It happens quite often, that you are using multiple (animated) sprites to form "the player's character" (e.g. a space-ship in a shoot-em-up). This is then considered as one sprite group. Some ideas from the Amiga here:

http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node015A.html

MJoergen commented 4 years ago

Pixel scrolling is now implemented in hardware (not yet emulator). Try out on hardware using the file vga_scroll.c.

Next thing up is the scan line interrupt!

MJoergen commented 4 years ago

256 sprites would be amazing! :-) IMHO 32x32 pixel with a lot of colors, such as 256 colors in a palette.

Ok, just a quick calculation on the memory requirements. Total number of bits needed would be: 256 (3232) * 8 = 2 Mbit.

This corresponds to 64 BRAMs.

I don't think we have that many free BRAMs remaining, I need to check. Anyway, if we add double-buffering of the DIsplay RAM, then we most surely don't have the memory needed.

So I think we should prioritize. Perhaps reduce number of sprites to 128 ?

sy2002 commented 4 years ago

So I think we should prioritize. Perhaps reduce number of sprites to 128 ?

I think 128 sprites or even 64 would be absolutely OK.

Can you make all these amounts (and maybe also other constants that are responsible for eating a lot of memory) configurable in env1_globals.vhd? My rationale behind it is, that we might want to keep supporting "smaller" FPGAs than the Artix-7. I plan for example to port QNICE-FPGA to the DE-10 board some day, because it is a cheap starter kit which might inrease our fan-base at universities and the likes.

EDIT: Thinking about all these constants and porting: We might need a general "system info" register somewhere, where the software can get info about all these constants (amount of register banks (256 by default) amount of sprites (128 by default) amount of pages in scroll back buffer (20 by default) and so on). I will make a new issue for that.

sy2002 commented 4 years ago

@MJoergen about your above mentioned https://github.com/sy2002/QNICE-FPGA/issues/17#issuecomment-681738450 section "Register Map for each sprite": Can you add horizontal and vertical mirroring of the sprite? Reason: I just bought some sprite assets for a vertical space shooter, since I am contemplating to write a very simple space shooter as a demo for your new VGA capabilities. The movement of the ship is only available for "moving left", so it is up to the programmer (or the hardware) to do the mirroring:

Frame 1

grafik

Frame 2

grafik

Frame 3

grafik

Frames 1,2,3 are for moving the ship to the left. Horizontally mirroring them will allow movements to the right.

MJoergen commented 4 years ago

Can you add horizontal and vertical mirroring of the sprite?

Done!

MJoergen commented 4 years ago

Basic sprites are now implemented. Only thing left is to add the remaining functionality described in the sprite's CSR register. However, the topic of layering (background/foreground) is causing some problems in my thinking, particularly striking a compromise between features we want to support, and the resources (e.g. BRAM's in the FPGA) needed to implement them.

Consider a few different cases:

Case 1.

TEXT        (GREEN on BLACK)
SPRITE 0    (RED. configured as IN-FRONT-OF)

This will display a RED color, because the sprite is in front of the text.

Case 2.

SPRITE 0    (RED. configured as BEHIND)
TEXT        (GREEN on BLACK)

This will display GREEN text on RED background, because the sprite is behind the text but in front of the background.

The above two cases deal with the interaction between TEXT and SPRITE, and describes the basic motivation for this feature, where e..g a tree is rendered using text, and a sprite can move either in-font-of or behind the tree.

With multiple overlapping sprites things get more complicated:

Case 3.

TEXT        (GREEN on BLACK)
SPRITE 1    (BLUE. configured as IN-FRONT-OF)
SPRITE 0    (RED. configured as IN-FRONT-OF)

This will display a RED color, because sprite 0 is always in front of sprite 1.

Case 4.

SPRITE 1    (BLUE. configured as BEHIND)
TEXT        (GREEN on BLACK)
SPRITE 0    (RED. configured as IN-FRONT-OF)

This will again display a RED color, because sprite 0 is in-front-of the text.

Case 5.

SPRITE 1    (BLUE. configured as BEHIND)
SPRITE 0    (RED. configured as BEHIND)
TEXT        (GREEN on BLACK)

This will display GREEN text on RED background, again because sprite 0 is in front of sprite 1.

The tricky part is the following:

Case 6.

SPRITE 0    (RED. configured as BEHIND)
TEXT        (GREEN on BLACK)
SPRITE 1    (BLUE. configured as IN-FRONT-OF)

What will this display? I see at least two possible interpretations:

(a) Just BLUE color, because sprite 1 is in front of the text. (b) GREEN text on RED background, because sprite 0 takes precedence over sprite 1.

Option (a) sounds reasonable, but is expensive to implement (uses more BRAM). Option (b) is cheaper and easier to implement, but is perhaps not intuitive.

After some more thinking, I start to wonder whether this situation (Case 6) is ever likely to occur. Essentially, this situation is trying to describe an impossible situation where sprite 0 is both in-front-of sprite 1 (because lower numbered sprites always have higher priority) AND is behind sprite 1 (because of the configuration in the sprite's CSR registers).

So one way around this paradox is this option: (c) Define all low-numbered sprites (e.g. 0-63) as being IN-FRONT-OF text, and all high-numbered sprites (e.g. 64-127) as being BEHIND text.

This introduces an artificial boundary at sprite number 64, and prevents having all 128 sprites in front of the text. To get around this limitation, we might propose this solution: (d) Same as option (c), but with a global boundary register, instead of hardcoding the value 64.

So this brings up the question of do we need such a boundary register? Or do we already have "enough" sprites?

Thoughts, comments, ides, suggestions, etc are - as always - highly appreciated.

sy2002 commented 4 years ago

Basic sprites are now implemented. Only thing left is to add the remaining functionality described in the sprite's CSR register.

What I have seen so far is absolutely great! So congrats for what has already being achieved! Two side questions as I am currently admitably only following the progress from a certain eagle's perspective (I did not try anything yet, by myself):

Feedback to the situation you describe:

Option (b) is cheaper and easier to implement, but is perhaps not intuitive.

I like option (b) a lot, as it will lead to a clean implementation that saves resources. This slight "non-intuitiveness" for the programmer is fully acceptable for me: We just need to document it somewhere and then all will be good. The overall idea of having the sprite number being an implicit prioritization is something that also my beloved retro-computers very often did exactly like this - so we are in good company! πŸ˜„

So my suggestion is clear: Go for the clean resource friedly option (b).

And: We do need to have 128 sprites because of animation: Consider we wanted a rotating globe in world.c: We already need 16 sprites per frame of the rotation... So already today, such a rotating "large sprite" could only have 8 animation frames and then we have zero sprites left.

MJoergen commented 4 years ago

Are we already able to animate sprites, i.e. change the "pointer" to a sprite in realtime, so that while a sprite moves, it is also animated?

Yes, that is already implemented. I don't have a demo of it though. Maybe I should do that .....

Do we also already have the 16x16 HiColor sprites?

No, that is not done yet.

So already today, such a rotating "large sprite" could only have 8 animation frames and then we have zero sprites left.

Even though it is expensive, software can update the sprite bitmap in real-time, i.e. copy the 256 words needed for a 32x32x4 sprite bitmap.

I'm still contemplating whether to implement the auto-increment feature. Let me explain: Currently, to access the Sprite RAM, software must first write the address to VGA$SPRITE_ADDR and then write the value to VGA$SPRITE_DATA. Transferring 256 words to sprite bitmap takes a long time using this method, so I am thinking about having the VGA$SPRITE_ADDR register auto-increment on every access (read or write) to the VGA$SPRITE_DATA register. This will greatly reduce the time needed to transfer a sprite bitmap. I don't want this to be configurable, as there is no need for the added complexity. Just always auto-increment. This is completely backwards compatible, since all the demo programs so far always write the address register before accessing the data register.

sy2002 commented 4 years ago

I'm still contemplating whether to implement the auto-increment feature.

Fully understood. Highly appreciated and I am a big fan of this idea because it boosts performance. You would need to well-document this and even have a small "best practices for sprite performance" section in our best practices programming guide.

MJoergen commented 4 years ago

As of today, (nearly) all sprite-related features are implemented in both hardware and emulator. Have a look at the following demos:

Features still not implemented are:

I've looked into sprite magnification, and within the current design adding this feature will cost an additional 16 BRAMs. This is due to how sprites are rendered within the VGA hardware module. So, is this feature very important? If not, I suggest we drop this feature.

I've also briefly looked into sprite collision, and this seems like quite a complicated feature. This will require some more thought.

Finally, there is a task of optimizing the emulator. Currently, no such effort has been made; the emulator re-draws the entire screen every time a sprite is updated.

sy2002 commented 4 years ago

Hi Michael - this is incredibly great news! I will be able to play with it and test it probably not before Saturday - but I am already today really looking forward to it! πŸš€ πŸ‘ πŸŽ† πŸ˜ƒ

I've looked into sprite magnification, and within the current design adding this feature will cost an additional 16 BRAMs.

Let's drop this feature. The price of 16 BRAMs is too high.

I've also briefly looked into sprite collision, and this seems like quite a complicated feature. This will require some more thought.

Don't worry. Take your time. We are not at all in a hurry and your speed is already now breathtaking :-)

Finally, there is a task of optimizing the emulator.

About Sprites: Yes, might make sense to optimize. And also about font gfx: Let's not forget issue #103.

I'm still contemplating whether to implement the auto-increment feature.

Did you implement it? I think it is an excellent idea.

MJoergen commented 4 years ago

Auto-increment is not yet implemented, but I will do it soon. However, if you use the library functions in sprite.c, you won't know the difference, other than better performance. My intention is that a user will only ever use the library functions, and not directly manipulate the hardware registers.

MJoergen commented 4 years ago

The auto-increment is implemented now.

MJoergen commented 4 years ago

The only thing left in this issue is to implement the bitmap graphics.

I'm assuming @sy2002 wants to do this at some time, so I've assigned it to him :-)

sy2002 commented 4 years ago

:-) Thank you. If you are OK with a timeline like "after Christmas", then this sounds great for me ;-)