Jump to content

VERA and number 48 ...


Recommended Posts

Hi,

Before you read further, please keep in mind that this post is not meant to pose any critic to Frank VdH or to the overall design of the CX16 regarding its graphics capabilities ...
However, allow me to reflect the followiing ...

Using vera in 640x400 graphics mode, there is a function in vera which I believe which could be further fine tuned ... It is the setting of the height and width of sprites ...

Sprites can be configured as 8, 16, 32 and 64 width and height by setting the respective bits in register 7 of the sprite attributes...

image.png.332f590b511e87d179310409d06860b3.png

I find the width and height of 64 however a bit too big of a gap.
Hopping from 8 to 16 is ok, from 16 to 32 is ok, but from 32 to 64 means that in terms of memory consumption there is a big increase ...

Let me illustrate:

  • 8 x 8 in 4bpp requires 32 bytes.
  • 16 x 16 in 4bpp requires 128 bytes.
  • 32 x 32 in 4bpp requires 512 bytes.
  • 64 x 64 in 4bpp requires 2048. In 8 bpp that would be a whopping 4096 bytes!

My question is, what if the vera would model the sprite painting with the following width registers: 16, 32, 48, 64, and discard the 8 pixel width and height setting.

That would mean, that the following mode would become available:

  • 48 x 48 in 4bpp requires 1152 bytes, in 8bpp that would be 2304 bytes.

 

Additionally:

  • A sprite width/height of 32 x 32 is too limiting, it does not draw sprites with sufficient size. It is a bit too small.
  • A sprite width/height of 64 x 64 is big, which is great, but it consumes too much memory. These kind of sprites would have a more limited animation count to save memory.
  • A sprite width/height of 48 x 48 would be a great size, as this would not consume too much memory, but would show sprites with sufficient pixel size.

Please see examples below:

1879682699_2022-10-03(1).thumb.png.f5e7f4eb6687c1c37fe2744568670d6c.png

Above is an example of a 48 x 48 sprite animation...

 

1535898409_2022-10-03(27).thumb.png.34c6cd4ee1b74b9665c2dd84bb49e629.png

Above is an animation of a 32 x 32 animation, great but a bit small. However, this size is perfect to flood the screen with enemies :-).
But the density to show sprite animations is limited and the width/height quickly becomes obvious to the player that 32x32 is the limit as all sprites will be in this size ...

 

269720725_2022-10-03(28).thumb.png.d4c818673b91b486d95184b02c0ad24b.png

Above shows 64 x 64 sprites animation, great for larger type of enemies, but consumes a lot of space.

 

The 48 x 48 sprite size seems to be the right fit, a 64 x 64 is needed, but consumes a lot of memory.


Drawing a 48 x 48 sprite animation results in a lot of vram memory being lost, due to having to draw this 48 x 48 sprite animation on 64 x 64 planes.

One could argue, that yes, we can do magic and start combining sprites to make larger pictures to draw a 48x48 bitmap, like drawing 9 16x16 sprites, or 1 sprite of 32x32 + 1 sprite of 16x32 + 1 sprite of 32x16 + 1 sprite of 16x16 ... But that would make things very, very complicated, and also notice by having to draw 9 or 4 sprites instead of one, there is a performance impact. Also notice, that if I would draw a 48x48 sprite out of 9 sprites of 16x16, that would mean 72 sprites to be drawn if i want to show 8 images of 48x48 pixels!

Any thoughts on this? @Wavicle?

Edited by svenvandevelde
Link to comment
Share on other sites

I can see where you are coming from, however:

On 10/3/2022 at 8:30 AM, svenvandevelde said:

and discard the 8 pixel width and height setting.

I use that size and it solved a VRAM shortage in Invaderz. I could squeeze just about everything in by using 8x8 for the phasers etc. Having to use 16x16 instead would be too much... Ok, maybe I could make it by analysing carefully again, but 8x8 has it's advantages. Especially if using 320x240 resolution. You would never use 64x64 there I think...

I would argue to drop 64x64 in favor of 48x48... but then maybe someone else already has a reasonable use case for that? Or drop 8x8 if in 640x400 resolution? Or use one of the unused bits in byte 1 to switch to a different size scheme?

  • Like 1
Link to comment
Share on other sites

Someone with more knowledge can correct me:

The sizes are so vera can pull data quickly, as it can mask or shift the address to look up the sprite data.

At 48bits the maths become more complicated as it would have to calculate the offset first which would reduce the number of sprites per line.

 

  • Like 2
Link to comment
Share on other sites

On 10/3/2022 at 11:00 AM, Yazwho said:

The sizes are so vera can pull data quickly, as it can mask or shift the address to look up the sprite data.

That's true. With 48 pixels you cannot use simple bit operations (or the hardware equivalent) to get to the next line of data. This could reduce the number of available sprites per scan line.

Also any logic switching between different sizes based on an additional bit in some register would have the same effect.

Link to comment
Share on other sites

I will think on this. I think calculating row address with 48 pixels isn't too bad. E.g.:

row = y_counter - sprite_y_start;
if (mode) begin
    // 8bpp
    line_addr = sprite_offset + (row << 6) - (row << 4); // row * 64 - row * 16
end
else begin
    // 4bpp
    line_addr = sprite_offset + (row << 5) - (row << 3); // row * 32 - row * 8
end

Something along those lines should work. I probably need to wake up a bit more and reality check this against the Verilog. Another concern is breaking any existing software that uses 64x64 sprites.

  • Like 2
Link to comment
Share on other sites

honestly, the correct solution is to use multiple sprites for one object. This is how it was done on classic systems.

Take this sprite of Samus from Super Metroid:
samus.gif.ef9743d5583fec7ff2a80fe626b4e63b.gif

It requires 36px to cover the full width of the character on screen. However, most of that extra 4px of width is blank, with only 10px height for back foot. This can be contained in an 8x16 sprite placed correctly in relation to the main 32x32 sprite. If I were to make a demo/game using artwork of this sort, I would simply make the actor/object control these sprites and define animation frames for each one.  In cases where the "extra bits" (like Samus's foot) move around relative to the main sprite, the engine would also need an x/y offsets table. In the Samus animation, the back foot is near the bottom of the sprite for one frame, and closer to the top on the next frame. This "foot sprite" would just be drawn at different relative locations to the main sprite during each frame of the animation cycle.

1268944635_SamusPieces.png.1570e1d91227178392831dbbcdd0efcd.png1091194834_SamusPieces2.png.e8aa00d7b87f4402afe8057b1ff9f02d.png


My Sonic demo faced a similar issue on the Sonic sprite, which is 40px tall. I used one 32x32 sprite for the main part of Sonic:
sonicmain.png.49dda40f9f35b23ba2d684f18f6bd2b3.png
and I use a separate sprite for the ears:
sonicears.png.3b0017f32e522d7cdfa0a0980425ae95.png
Interestingly, the ears only require 2 frames of animation (frames 3 and 4 are duplicates of 1 and 2). I didn't bother deleting frames 3 and 4 from the resource, as I've got plenty of VRAM for this simple demo, but the engine never uses those frames. I set up an animation frames table with the VRAM locations of the frames, and the engine cycles through these tables. So the main body's data is the VRAM address equivalents of: 0, 1, 2, 3 and the ear's data is 0, 1, 0, 1. This is also useful for "pingpong" animations where you only need pixel data for 3 frames of a walk/run cycle and you just display them as 0,1,2,1,0,1,2,1... no need to have frame 1 in VRAM twice.

This is part of the challenge of programming retro. It's nice when HW just does the work for you, but when it doesn't, that doesn't mean you're stuck. You just have to code a solution. This stuff I've explained here actually saves more memory too, as you only need exactly the pixel data for exactly the parts that go out-of-bounds. The lazy alternative would've been to use a 64x64 sprite, but yes, that would gobble up VRAM needlessly.

Hope this makes sense.

Edited by ZeroByte
Added illustration of Samus's foot sprite placement moving
  • Like 3
Link to comment
Share on other sites

On 10/3/2022 at 2:37 PM, Wavicle said:

I will think on this. I think calculating row address with 48 pixels isn't too bad. E.g.:

row = y_counter - sprite_y_start;
if (mode) begin
    // 8bpp
    line_addr = sprite_offset + (row << 6) - (row << 4); // row * 64 - row * 16
end
else begin
    // 4bpp
    line_addr = sprite_offset + (row << 5) - (row << 3); // row * 32 - row * 8
end

Something along those lines should work. I probably need to wake up a bit more and reality check this against the Verilog. Another concern is breaking any existing software that uses 64x64 sprites.

I suggest to model it that the high resolution 640 width supports 16, 32, 48, 64 resolutions.

And the lower resolution 320 supporting 8, 16, 32, 48?

 

lol

  • Like 2
Link to comment
Share on other sites

On 10/3/2022 at 2:29 PM, svenvandevelde said:

32 +16 = 48

Yes sure, but it's still an additional operation. Don't know how many resources on the FPGA are left - if there are any. But if it's possible to do, I'm all in for it 🙂!

Link to comment
Share on other sites

On 10/3/2022 at 4:41 PM, svenvandevelde said:

I suggest to model it that the high resolution 640 width supports 16, 32, 48, 64 resolutions.

And the lower resolution 320 supporting 8, 16, 32, 48?

Makes a lot of sense!

Link to comment
Share on other sites

64 x 64 is very useful though.

As would be 128 x 128 and 256 x 256 if there were 1bpp and 2bpp modes available.

 

On 10/3/2022 at 3:41 PM, svenvandevelde said:

And the lower resolution 320 supporting 8, 16, 32, 48?

Vera only has one resolution, 640x480, we use scaling to create 320x240 or indeed any other 'resolution' lower than 640x480.

Link to comment
Share on other sites

On 10/3/2022 at 5:15 PM, Yazwho said:

64 x 64 is very useful though.

As would be 128 x 128 and 256 x 256 if there were 1bpp and 2bpp modes available.

 

Vera only has one resolution, 640x480, we use scaling to create 320x240 or indeed any other 'resolution' lower than 640x480.

Do what i'm doing with vera and then you will see that it is not that simple. And 128x128 would be great, but impossible to manage at acceptable frame rates, as vera and cx16 don't have dma.

Link to comment
Share on other sites

Posted (edited)
On 10/3/2022 at 4:34 PM, ZeroByte said:

honestly, the correct solution is to use multiple sprites for one object. This is how it was done on classic systems.

Take this sprite of Samus from Super Metroid:
samus.gif.ef9743d5583fec7ff2a80fe626b4e63b.gif

It requires 36px to cover the full width of the character on screen. However, most of that extra 4px of width is blank, with only 10px height for back foot. This can be contained in an 8x16 sprite placed correctly in relation to the main 32x32 sprite. If I were to make a demo/game using artwork of this sort, I would simply make the actor/object control these sprites and define animation frames for each one.  In cases where the "extra bits" (like Samus's foot) move around relative to the main sprite, the engine would also need an x/y offsets table. In the Samus animation, the back foot is near the bottom of the sprite for one frame, and closer to the top on the next frame. This "foot sprite" would just be drawn at different relative locations to the main sprite during each frame of the animation cycle.

1268944635_SamusPieces.png.1570e1d91227178392831dbbcdd0efcd.png1091194834_SamusPieces2.png.e8aa00d7b87f4402afe8057b1ff9f02d.png


My Sonic demo faced a similar issue on the Sonic sprite, which is 40px tall. I used one 32x32 sprite for the main part of Sonic:
sonicmain.png.49dda40f9f35b23ba2d684f18f6bd2b3.png
and I use a separate sprite for the ears:
sonicears.png.3b0017f32e522d7cdfa0a0980425ae95.png
Interestingly, the ears only require 2 frames of animation (frames 3 and 4 are duplicates of 1 and 2). I didn't bother deleting frames 3 and 4 from the resource, as I've got plenty of VRAM for this simple demo, but the engine never uses those frames. I set up an animation frames table with the VRAM locations of the frames, and the engine cycles through these tables. So the main body's data is the VRAM address equivalents of: 0, 1, 2, 3 and the ear's data is 0, 1, 0, 1. This is also useful for "pingpong" animations where you only need pixel data for 3 frames of a walk/run cycle and you just display them as 0,1,2,1,0,1,2,1... no need to have frame 1 in VRAM twice.

This is part of the challenge of programming retro. It's nice when HW just does the work for you, but when it doesn't, that doesn't mean you're stuck. You just have to code a solution. This stuff I've explained here actually saves more memory too, as you only need exactly the pixel data for exactly the parts that go out-of-bounds. The lazy alternative would've been to use a 64x64 sprite, but yes, that would gobble up VRAM needlessly.

Hope this makes sense.

As I wrote earlier:

On 10/3/2022 at 8:30 AM, svenvandevelde said:

One could argue, that yes, we can do magic and start combining sprites to make larger pictures to draw a 48x48 bitmap, like drawing 9 16x16 sprites, or 1 sprite of 32x32 + 1 sprite of 16x32 + 1 sprite of 32x16 + 1 sprite of 16x16 ... But that would make things very, very complicated, and also notice by having to draw 9 or 4 sprites instead of one, there is a performance impact. Also notice, that if I would draw a 48x48 sprite out of 9 sprites of 16x16, that would mean 72 sprites to be drawn if i want to show 8 images of 48x48 pixels!

 

But thank you for the suggestion. Indeed, it is a good method to do and this would be a solution.

However, it would make things way more complicated. I've posted a video below that shows what is in the make. This is way past a demo.
It is an actual game, with lots of enemies and thus, sprites ... I want to render them as one object, but will combine the player sprite with additional modules picked up on the flight.
However, for the enemies, if i need to model those also, then i am looking at a project to be release in 2 years ...

Think the 48x48 is the viable option in my opinion, but only if doable technically. Actually, it would be great if vera would have some function to set the scales of sprites by the user.

Edited by svenvandevelde
Link to comment
Share on other sites

On 10/3/2022 at 6:06 PM, svenvandevelde said:

Do what i'm doing with vera and then you will see that it is not that simple.

You mean coordinating the moving of a lot of sprites on the screen on every frame -- say 1160 of them -- like this?

 

Edited by Yazwho
Link to comment
Share on other sites

Posted (edited)
On 10/3/2022 at 7:51 PM, Yazwho said:

You mean coordinating the moving of a lot of sprites on the screen at every frame -- say 1160 of them -- like this?

 

Nicely done! Great demo!
However, it is not what I was looking for. I also expressed myself a bit bluntly I see upon your feedback.
What I wanted to express is the vram memory consumption issue.

Pls check my video if you have the time to see the challenge ...
We are going waaaay beyond the scope of this post.

 

Edited by svenvandevelde
Link to comment
Share on other sites

If it's just a vram issue, then ZeroByte suggested a way around it.

At the end of the day there are lots of ways to mitigate the issue, but I dont think changing the machine is one of them. This is meant to be a limited machine afterall.

There are plenty of people on Discord who can offer suggestions, workarounds, or can just talk about things in a more conversational way than can be done here. Maybe thats worth a go?

 

Link to comment
Share on other sites

On 10/3/2022 at 8:13 PM, Yazwho said:

If it's just a vram issue, then ZeroByte suggested a way around it.

At the end of the day there are lots of ways to mitigate the issue, but I dont think changing the machine is one of them. This is meant to be a limited machine afterall.

There are plenty of people on Discord who can offer suggestions, workarounds, or can just talk about things in a more conversational way than can be done here. Maybe thats worth a go?

 

I have written in my original post exactly what ZeroByte has expressed, pls check the sentences below. Also i replied to the feedback of ZeroByte.

What i'm trying to say, is that a 64x64 sprite size is quite large, and there is no size in between. I am not trying to request to change the machine, and it is upon much more people to judge if chaning it would be an option or not.

Then why Wavicle is doing changes that are accepted by Frank? And why is Frank replying to my posts about transparency, that such would be possible to implement?

Because maybe, just maybe, there is a valid reasoning that may improve the machine, and that might result in a better system overall, over time.

If changing the machine is not an option, then fine, so be it. At least I've raised it and it is up for the community to consider.

Latest changes by @Wavicle were accepted by Frank though. Also, Frank replied to me that alpha channels in bitmap rendering would be an option according to him also.

Alpha Channel · Issue #3 · fvdhoef/vera-module (github.com)

Link to comment
Share on other sites

On 10/3/2022 at 8:20 PM, ZeroByte said:

I think the main issue at hand is that the engine uses a heap management approach to allocating VRAM which comes with benefits and drawbacks, as with all design decisions. That's what makes this an engaging hobby. 🙂

You read my mind. This is an interesting hobby and you have understood my approach perfectly. Now ... since we are here ...
Check on the video the 48x48 images. These are in vram on a 64x64 bitmap. Waste of memory? This is beyond the heap management approach :-).

I have considered also the approach to draw multiple sprites and have some sort of "sprite painter" algorithm, that would paint the image to 4 or 9 sprites or so. But the issue then is the overhead of moving the sprites, on top of all the other logic.

Just dunno what is the best. Also i am thinking of a heap compactor/defragmenter, and an approach to position the 64x64 bitmaps from the top of the heap to the botton, so that fragmentation only occurs in the lower parts.
The issue that i have is that i paint too many image animations that cannot be fit into the vera vram at the same time. Obvious solution is to limit the amount of animation frames which i am implementing now.
But if there would be a 48x48 size, then i would be able to fit almost the double of animation frames in vram. Bascially i use vram as a cache, which is dynamically updated upon demand.

Link to comment
Share on other sites

One more note, since the cx16 doesn't have dma, every memory movement is down to the processor. Moving memory is fast, but moving 4096 bytes every frame is not an option (so i cannot use 64x64 in 8bpp) for animations, bottom line.

Note that the video shows animations of two 64x64 sprites floating.

Link to comment
Share on other sites

On 10/3/2022 at 8:28 PM, ZeroByte said:

Alpha channels would be cool.

Yeah, but if you think about it, not an option really. Alpha channels in a 16 color palette are hard. I mean, it woudl only make sense in 8bpp, right?

And then you are full resolution of sprites with full bit depth. So a 64x64 sprite would be 4096 bytes.

That is one sprite image, to be clear. So 0x1000 hex. If I want to animate 16 of those sprites, i would need 0x10000 or 65536 bytes in vram lol. 
 

That being said, alpha channels would be great to have for fire effects, like bullets, lighting, lasers etc. For thos bitmaps, which are naturally of smaller size, this would be a great feature to have.

The CX16 indeed has its limitations and we live with it. It is just finding the borders of the machine and using them optimally. That is the challenge, and it has been a real journey so far for me ...

Link to comment
Share on other sites

FWIW, using multiple sprites is pretty low overhead in the way I did it for Sonic Demo:

.struct SPRITEREG
    addr        .word    1
    xpos        .word    1
    ypos        .word    1
    orient        .byte    1
    attr        .byte    1
.endstruct

sonic_spriteregs:    ; shadow registers for Sonic sprites (initial values)
        ;sonic's body
        .byte $10, $08, <sonic_x, >sonic_x, <(sonic_y+8), >(sonic_y+8), $0c, $a0

        ;sonic's ears
        .byte $00, $08, <sonic_x, >sonic_x, <sonic_y, >sonic_y, $0c, $20


sonic_frames:    ; VRAM locations for frames of Sonic's animation (SPREG format)
    .word $0810, $0820, $0830, $0840
    .word $0800, $0804, $0800 $0804

animate_sonic:
            lda sonicframe
            inc
            and #3  ; sonic frame = 0..3
            sta sonicframe
            asl  ; use frame as X index (*2 because data stored as words, not separate HiByte / LoByte tables)
            tax
            lda    sonic_frames,x  ; sonic body address LoByte
            sta sonic_spriteregs + SPRITEREG::addr
            lda sonic_frames + 8,x  ; sonic ears address LoByte
            sta sonic_spriteregs + 8 + SPRITEREG::addr
            lda sonic_frames+1,x  ; sonic body address HiByte
            sta sonic_spriteregs + 1 + SPRITEREG::addr
            lda sonic_frames+9,x  ; sonic ears address HiByte
            sta sonic_spriteregs + 9 + SPRITEREG::addr
            lda    dirty
            ora    #DIRTY_SPRITE
            sta dirty    ; flag sprite address as dirty so VBLANK IRQ will update VERA
            rts

A similar approach in C would use something akin to this:
uint16_t sonic_frames[2][4] = { {0x810, 0x820, 0x830, 0x840} , {0x800, 0x804, 0x800, 0x804} };

Again, not saying "do this, n00b" - just sharing what I've done in case anyone else finds it useful or informative.

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

Please review our Terms of Use