Trying to make yet another video mode...
Trying to make yet another video mode...
It's been awhile, and I'm trying to get back into doing stuff with the uzebox again.
I have a certain video mode design in my head that I want to try out and see if it's doable.
The video mode goes something like this:
It's closest to video mode 3, because it's going to be a RAM and ROM tile setup with scrolling.
The difference is that it has at least 2 changeable ROM address bases. So that a good portion of the screen could be changed with a single variable change.
The second difference is the number of bytes between tile rows can also be changed. This wont change the number of pixels per tile which will still be fixed at 8 pixels per tile.
What these two changes will allow is a cheap, fake parallax scrolling effect.
I'm kind of stuck on how to attempt this. even though I know assembly mnemonics and how to count cpu cycles, I can't make sense of the core rendering function.
I have a certain video mode design in my head that I want to try out and see if it's doable.
The video mode goes something like this:
It's closest to video mode 3, because it's going to be a RAM and ROM tile setup with scrolling.
The difference is that it has at least 2 changeable ROM address bases. So that a good portion of the screen could be changed with a single variable change.
The second difference is the number of bytes between tile rows can also be changed. This wont change the number of pixels per tile which will still be fixed at 8 pixels per tile.
What these two changes will allow is a cheap, fake parallax scrolling effect.
I'm kind of stuck on how to attempt this. even though I know assembly mnemonics and how to count cpu cycles, I can't make sense of the core rendering function.
Re: Trying to make yet another video mode...
My initial mode3 supported split screens with each it's own tileset and X/Y scrolling (just like mode2). So yes it's doable. Everything fell apart when I added sprites. In mode2 sprites are processed line by line and overlayed over the background. Each backline can have a different offset, no issues here. Things get much more complicated with mode 3 since sprites are pre-blitted in ramtiles during vsync. Back then I could not get my head around a fast algorythm to blit over the junction of two sections with different scroll values. It also yielded all sort of weird behaviors (like repeat of sprites appearing in many sections at once) and I realized I would have too much of hard time to explain it. I though about limiting sprites to a single section, but then that would not have been very useful. In the end I just left out the feature.
So I think it's feasible. The "easiest" part is the rasterizer, the hardest is the blitter. I know the code is horribly complex...that's mainly why it didn't changed in years!
-Uze
So I think it's feasible. The "easiest" part is the rasterizer, the hardest is the blitter. I know the code is horribly complex...that's mainly why it didn't changed in years!
-Uze
Re: Trying to make yet another video mode...
I'm not concerned at all about the sprite bitter, that will be later. I'm just trying to change the way that the rasterizer addresses the ROM tiles.
In this illustration, the base address for the ROM tiles changed, but only for some of the tiles on screen. P.S. I messed up on explaining the "bytes between tiles" in this picture.
In this illustration, the base address for the ROM tiles changed, but only for some of the tiles on screen. P.S. I messed up on explaining the "bytes between tiles" in this picture.
Re: Trying to make yet another video mode...
Sorry, I can't make sense of what the diagram is supposed to mean. What are those "extra bytes between rows"? Rows of pixels, tiles? For me rows represent the Y axis, columns the X axis. On your diagram it seems the other way around? What's teh effect you are trying to achieve?
-Uze
-Uze
Re: Trying to make yet another video mode...
In this post "tiles" means the tile data that is eventually displayed to the screen, and "screenblock entries" (SE) means the part of the RAM that indexes the tiles.
The effect I want to get is the background effect you see in games like "Metal Storm" for the NES or "Wendy: Every Witch Way" for the Gameboy Color.
As I understand it, this is done in the NES by changing the tiles once, through nametable trickery, rather than changing all the screenblock entries individually. We currently can get the same effect by a writing to a RAM tile spread across the screenblock ("sprite curtain"), like in Lode Runner or BC Dash.
In this case I want to save the extra 64 bytes, plus CPU time, and get a parallax background with ROM tiles only. Now I figure I could do this if I was able to change the ROM tile base address for only some of tile indexes, much like how a index above RAM_TILES_COUNT counts for a different set of tiles then the usual ROM tiles.
Now once switchable base address is in place, I could get the scrolling effect by having 8 different ROM tiles (or more for larger patterns), but that would be a lot of ROM used up. So I found that less ROM can be used if the ROM tiles are actually larger then the 8 pixels that are displayed. This way a window of sorts can scroll across the ROM tile using only 2 tiles worth of ROM instead of 8 tiles.
I realize The diagram above is flawed, because there has to be both a distance between tile rows and a distance between the whole tile.
The effect I want to get is the background effect you see in games like "Metal Storm" for the NES or "Wendy: Every Witch Way" for the Gameboy Color.
As I understand it, this is done in the NES by changing the tiles once, through nametable trickery, rather than changing all the screenblock entries individually. We currently can get the same effect by a writing to a RAM tile spread across the screenblock ("sprite curtain"), like in Lode Runner or BC Dash.
In this case I want to save the extra 64 bytes, plus CPU time, and get a parallax background with ROM tiles only. Now I figure I could do this if I was able to change the ROM tile base address for only some of tile indexes, much like how a index above RAM_TILES_COUNT counts for a different set of tiles then the usual ROM tiles.
Now once switchable base address is in place, I could get the scrolling effect by having 8 different ROM tiles (or more for larger patterns), but that would be a lot of ROM used up. So I found that less ROM can be used if the ROM tiles are actually larger then the 8 pixels that are displayed. This way a window of sorts can scroll across the ROM tile using only 2 tiles worth of ROM instead of 8 tiles.
I realize The diagram above is flawed, because there has to be both a distance between tile rows and a distance between the whole tile.
Re: Trying to make yet another video mode...
I think I got my tile rendering code right. First I decided to take computation of tile address out of this loop and hopefully put it in the 380 + 32 cycles around it. The second thing I did was reduced the cycles per pixel from 6 to 5.5.
Code: Select all
;*************************************************************
;r16 = pixel to output.
;r17 = number of tiles left.
;r18 = next tile address (LSB)
;r19 = next tile address (MSB)
;Y = tile address buffer pointer
;Z = RAM or ROM tile pixels.
romloop:
lpm r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 0 - 5 cycles
dec r17 ;decrement tiles to draw on line
lpm r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 1 - 6 cycles
brmi end_romloop
;I will have to make sure that the
; first two pixels of the tile after
; the last tile is black
lpm r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 2 - 5 cycles
nop
lpm r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 3 - 6 cycles
ld r19,Y+ ;load next tile # from buffer (MSB)
lpm r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 4 - 5 cycles
cpi r19,0xf0 ; if address > 61440 then it's ram tile
lpm r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 5 - 6 cycles
ld r18,Y+ ;load next tile # from buffer (LSB)
lpm r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 6 - 5 cycles
lpm r16,Z+
movw ZL,r18 ;copy next tile address
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 7 - 6 cycles
brlo romloop
subi r19,0xf0 ;prepare address for ram tile.
ramloop:
nop
ld r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 0 - 5 cycles
dec r17 ;decrement tiles to draw on line
nop
ld r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 1 - 6 cycles
brmi end_ramloop
;I will have to make sure that the
; first two pixels of the tile after
; the last tile is black
nop
ld r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 2 - 5 cycles
ld r19,Y+ ;load next tile # from buffer (MSB)
;;;;nop
ld r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 3 - 6 cycles
ld r18,Y+ ;load next tile # from buffer (LSB)
nop
ld r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 4 - 5 cycles
cpi r19,0xf0 ; if address > 61440 then it's ram tile
nop
ld r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 5 - 6 cycles
brlo .+2 ;skip if next tile is in ROM
subi r19,0xf0 ; prepare address for ram tile.
nop
ld r16,Z+
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 6 - 5 cycles
nop
ld r16,Z+
movw ZL,r18 ;copy next tile address
out _SFR_IO_ADDR(DATA_PORT),r16 ;pixel 7 - 6 cycles
brlo romloop
rjmp ramloop
Re: Trying to make yet another video mode...
After seeing Metal Storm, I now get it. Some effect similar to beign able to scroll the content of individual tiles. Ramtiles are obviously the simplest way of doing this with the current mode 3. I'm curious to see how you will pull that one off since there pretty much no cycles left in the main rendering loop. Handling X/Y wrapping could be be another tricky part. Be wary of using different cycles count for pixels, it will most probably yield some weird stripes artifacts.
-Uze
-Uze
Re: Trying to make yet another video mode...
Well, I found that I can't stuff the address computation only in hblank. A simple increment loop like the one below takes 416 cycles for 32 tiles.
I'm going to have to take a step back and try plan B, which is stuffing 3 branches in the main tile loop. Branch 1 to stop the loop, branch 2 to switch between RAM and ROM, and branch 3 to switch between two different address bases. This will probably increase the pixel width to 8 cycles per pixel. Though I wonder if I could make a non-scrolling ROM tile only mode that's 256 pixels wide at 5.5 cycles per cycle (Edit: it's 100% possible, I'm going to try this now).
It might be easier to change the sprite renderer of mode 3 to treat some RAM tiles as background tiles.
Code: Select all
;increment words in ram by a consent (r16,r17) until the end of the array (0x87).
increment_tiles:
ld r19, Y
ld r18, Y+1
add r18, r16
adc r19, r17
st r19, Y+
st r18, Y+
cpi YL, 0x87
brlo increment_tiles
It might be easier to change the sprite renderer of mode 3 to treat some RAM tiles as background tiles.
Re: Trying to make yet another video mode...
demo attached
I basically reworked my tile rendering code a bit, and grafted it into Mode 5. The demo itself is a bunch of hacks to get the Mode5Demo working with this code. I don't want officially give it a mode number until I work a few more ideas.
I wanted to post this now to see if this gets stripe artifacts on other TVs, because even though I see them on my little LCD TV, it looks fine.
I basically reworked my tile rendering code a bit, and grafted it into Mode 5. The demo itself is a bunch of hacks to get the Mode5Demo working with this code. I don't want officially give it a mode number until I work a few more ideas.
I wanted to post this now to see if this gets stripe artifacts on other TVs, because even though I see them on my little LCD TV, it looks fine.
Code: Select all
;*************************************************
; Renders a line within the current tile row.
; Draws 32 tiles wide @ 5.5 clocks per pixel
;
; r22 = Y offset in tile row (0-7)
; r23 = tile width in bytes
; Y = VRAM adress to draw from (must not be modified)
;
; cycles = 1495
;*************************************************
render_tile_line:
lpm ;quick 16 (3*5+1) nop
lpm ;
lpm ;
lpm ;
lpm ;
nop ;
movw XL,YL ;copy current VRAM pointer to X
ldi r17,TILE_HEIGHT*TILE_WIDTH
;////////////////////////////////////////////
;Compute the adress of the first tile to draw
;////////////////////////////////////////////
lds r24,tile_table_lo
lds r25,tile_table_hi
mul r22,r23 ;compute Y offset in current tile row
add r24,r0 ;add to base tileset adress
adc r25,r1
ld r20,X+ ;load first tile index from VRAM
mul r20,r17 ;multiply tile index by tile size
add r0,r24 ;add tileset adress
adc r1,r25
movw ZL,r0 ;copy to Z, the only register that can read from flash
ldi r18,SCREEN_TILES_H ;load the number of horizontal tiles to draw
mode5_loop:
lpm r16,Z+ ;get pixel 0 from flash
out VIDEO_PORT,r16 ;output pixel 0 to the video DAC - 5 cpu
nop
lpm r16,Z+ ;get pixel 1 from flash
out VIDEO_PORT,r16 ;output pixel 1 to the video DAC - 6 cpu
ld r20,X+ ;load next tile index from VRAM
lpm r16,Z+ ;get pixel 2 from flash
out VIDEO_PORT,r16 ;output pixel 2 to the video DAC - 5 cpu
nop
lpm r16,Z+ ;get pixel 3 from flash
out VIDEO_PORT,r16 ;output pixel 3 to the video DAC - 6 cpu
mul r20,r17 ;multiply tile index by tile size
lpm r16,Z+ ;get pixel 4 from flash
out VIDEO_PORT,r16 ;output pixel 4 to the video DAC - 5 cpu
add r0,r24
lpm r16,Z+ ;get pixel 5 from flash
out VIDEO_PORT,r16 ;output pixel 5 to the video DAC - 6 cpu
adc r1,r25
dec r18 ;decrement horizontal tiles to draw
lpm r16,Z+ ;get pixel 6 from flash
out VIDEO_PORT,r16 ;output pixel 6 to the video DAC - 5 cpu
lpm r16,Z+ ;get pixel 7 from flash
movw ZL,r0 ;load the next tile's adress in Z
out VIDEO_PORT,r16 ;output pixel 7 to the video DAC - 6 cpu
brne mode5_loop
lpm ;3 nop
clr r16 ;set last pixel to zero (black)
out VIDEO_PORT,r16
lpm ;quick 16 (3*5+1) nop
lpm ;
lpm ;
lpm ;
lpm ;
nop ;
ret
- Attachments
-
- AnotherMode.hex
- (62.85 KiB) Downloaded 309 times
Re: Trying to make yet another video mode...
Triple post...
This what I'm going to try to code from now before Christmas; A video mode that can contain many sections, each of witch can have different line renderers, all of which can be configured from a small block of RAM. Once I'm done with this I'll have a better feel of the resources in uzebox, and can try something as fool hearty as reinventing a already good enough sprite engine.
The available line renderers would be a blank renderer for saving CPU, the renderers from Mode 1, 5, 6, 8, and that thing from the previous post. It might be able to have the renderers from Mode 4 and 9 but I'm not quite sure, and it cannot have the renderers from Mode 2, 3, or 7 because they use the hblank much differently.
To save on RAM, the sections would be defined by a some sort of simple bytecode language that's interpreted during hblank. This language would have to take into account things like incrementing rows for tiles, palleted colors, and line duplication for mode 8. A neat effect might be to change the fader per scanline for cheap multi colored text.
Also to save on ROM, these renderers can be left out by compiler switches.
This what I'm going to try to code from now before Christmas; A video mode that can contain many sections, each of witch can have different line renderers, all of which can be configured from a small block of RAM. Once I'm done with this I'll have a better feel of the resources in uzebox, and can try something as fool hearty as reinventing a already good enough sprite engine.
The available line renderers would be a blank renderer for saving CPU, the renderers from Mode 1, 5, 6, 8, and that thing from the previous post. It might be able to have the renderers from Mode 4 and 9 but I'm not quite sure, and it cannot have the renderers from Mode 2, 3, or 7 because they use the hblank much differently.
To save on RAM, the sections would be defined by a some sort of simple bytecode language that's interpreted during hblank. This language would have to take into account things like incrementing rows for tiles, palleted colors, and line duplication for mode 8. A neat effect might be to change the fader per scanline for cheap multi colored text.
Also to save on ROM, these renderers can be left out by compiler switches.