Trying to make yet another video mode...

Topics related to the API, programming discussions & questions, coding tips, bugs, etc. should go here.
User avatar
JRoatch
Posts: 108
Joined: Mon May 11, 2009 11:48 pm
Contact:

Trying to make yet another video mode...

Post by JRoatch »

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.
User avatar
uze6666
Site Admin
Posts: 4823
Joined: Tue Aug 12, 2008 9:13 pm
Location: Montreal, Canada
Contact:

Re: Trying to make yet another video mode...

Post by uze6666 »

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
User avatar
JRoatch
Posts: 108
Joined: Mon May 11, 2009 11:48 pm
Contact:

Re: Trying to make yet another video mode...

Post by JRoatch »

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.
imperfect illustration of an the ROM tile address change.
imperfect illustration of an the ROM tile address change.
untitled.png (19.84 KiB) Viewed 6491 times
P.S. I messed up on explaining the "bytes between tiles" in this picture.
User avatar
uze6666
Site Admin
Posts: 4823
Joined: Tue Aug 12, 2008 9:13 pm
Location: Montreal, Canada
Contact:

Re: Trying to make yet another video mode...

Post by uze6666 »

Sorry, I can't make sense of what the diagram is supposed to mean. :oops: 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
User avatar
JRoatch
Posts: 108
Joined: Mon May 11, 2009 11:48 pm
Contact:

Re: Trying to make yet another video mode...

Post by JRoatch »

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.
User avatar
JRoatch
Posts: 108
Joined: Mon May 11, 2009 11:48 pm
Contact:

Re: Trying to make yet another video mode...

Post by JRoatch »

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
User avatar
uze6666
Site Admin
Posts: 4823
Joined: Tue Aug 12, 2008 9:13 pm
Location: Montreal, Canada
Contact:

Re: Trying to make yet another video mode...

Post by uze6666 »

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
User avatar
JRoatch
Posts: 108
Joined: Mon May 11, 2009 11:48 pm
Contact:

Re: Trying to make yet another video mode...

Post by JRoatch »

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.

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
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.
User avatar
JRoatch
Posts: 108
Joined: Mon May 11, 2009 11:48 pm
Contact:

Re: Trying to make yet another video mode...

Post by JRoatch »

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.

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
User avatar
JRoatch
Posts: 108
Joined: Mon May 11, 2009 11:48 pm
Contact:

Re: Trying to make yet another video mode...

Post by JRoatch »

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.
Post Reply