Jump to content
IGNORED

CV Basic: scrolling


Recommended Posts

Hmm, I don't think I would have enough RAM to accomplish what I am looking to do, that's why I was hoping to quickly copy characters from video ram to an adjacent character.   I was thinking maybe older Coleco games would have accomplished this using this method since ROM size was so limited.  (Pepper II, or Smurfs) , but I could see utilizing the RAM if the game is simple enough.

Link to comment
Share on other sites

I found that using a partial buffer I can copy the screen more quickly than copying and relocating one character at a time.  Grabbing groups of 6 rows of characters three times results in taking 6 frames to shift the screen over 8 frames (benchmarking via the frame counter) doing them one at a time. 

Would there possibly be a more efficient method than this?  Buffering more of the display didn't speed up anything, so for the sake of memory conservation, I felt this was a happy medium.

 

This is what I came up with.

 

            FOR #I=(32*4)+$1800 TO (32*16)+$1800 STEP 32*6
                FOR J=0 TO 32*6-1
                    VBUFFER(J) = VPEEK(#I+J)
                NEXT
                SCREEN VBUFFER,0,#I-($1800-1),31,6,32
            NEXT    

 

Link to comment
Share on other sites

Lately I RLE a compressed screen to RAM instead of VRAM.  I make my changes there then manipulate the Pattern Table through the VDP registers.

 

Point to the RAM Buffer then OUTI everything to VRAM Name Table during the NMI call.

 

Works great as long as you do the prep.

Edited by Captain Cozmos
Link to comment
Share on other sites

1 hour ago, skywaffle said:

I found that using a partial buffer I can copy the screen more quickly than copying and relocating one character at a time.  Grabbing groups of 6 rows of characters three times results in taking 6 frames to shift the screen over 8 frames (benchmarking via the frame counter) doing them one at a time. 

Would there possibly be a more efficient method than this?  Buffering more of the display didn't speed up anything, so for the sake of memory conservation, I felt this was a happy medium.

 

This is what I came up with.

 

            FOR #I=(32*4)+$1800 TO (32*16)+$1800 STEP 32*6
                FOR J=0 TO 32*6-1
                    VBUFFER(J) = VPEEK(#I+J)
                NEXT
                SCREEN VBUFFER,0,#I-($1800-1),31,6,32
            NEXT    

 

The loop would be much faster if you read from vram using INP() instead of vpeek().

Just read the first byte by setting the address in vpeek, use inp($BE) to read all the following data.

The vdp will increment the address at each read.

Link to comment
Share on other sites

FOR J=0 TO 32*6-1

    VBUFFER(J) = VPEEK(#I+J)

 NEXT

 

can be coded more efficiently as

 

VBUFFER(0) = VPEEK(#I)

FOR J=1 TO 32*6-1
     VBUFFER(J) = INP($BE)

NEXT

 

It is the best you can do before moving to asm

Edited by artrag
  • Like 1
Link to comment
Share on other sites

Thanks for the insight and example!  I was marvelling at what Konami was able to do with their MSX games, like Gradius/Nemesis 2 and 3 using the same VDP.   It made me wonder if something similar could be done on the Coleco since it's more or less the same hardware.

 

I do need to dig into Z80 ASM.  I had gotten pretty comfortable with 6800 ASM, but it seems like a whole different world on the Z80.

  • Like 1
Link to comment
Share on other sites

5 hours ago, skywaffle said:

Thanks for the insight and example!  I was marvelling at what Konami was able to do with their MSX games, like Gradius/Nemesis 2 and 3 using the same VDP.   It made me wonder if something similar could be done on the Coleco since it's more or less the same hardware.

 

I do need to dig into Z80 ASM.  I had gotten pretty comfortable with 6800 ASM, but it seems like a whole different world on the Z80.

With a bit more ram you can get the  same results you see on msx. The sgm module is the living proof of that.

Anyway there is already a lot that can be done on stock colecovision exploiting its vram.

E.g. in what cvbasic calls mode 2, you can have multiple tilesets and multiple PNTs and you can switch among them in few cycles 

 

Link to comment
Share on other sites

The following is what I came up with for scrolling the VRAM left for Scramble and it's using as few clock cycles as I could manage.  My screen has a static non-scrolling line at the top and bottom, so you may need to adjust the numbers and size of the buffer if you're going full-screen.  It breaks the copy into two phases to keep the RAM requirement reasonable while doing the fewest possible outs to the control port.  If you need more free RAM, make it three.  My case needed scroll_buffer to be 341 bytes.  Some may squawk that I shouldn't have two blocks doing the same operation and should keep the ROM size down, on principle, but in my case I literally could not sacrifice the couple hundred clock cycles.  This should leave you plenty of time for game logic, however in my case I'm also not calling the stock sound processing and am using my own because the stock routines, while very very handy, are VERY expensive cycle-wise.
 

    ld d,#31
    ld c, #0xBE ; port

    ld a,#0x21
    out (#0xBF),a
    ld a,#0x18
    out (#0xBF),a

    ld hl, #_scroll_buffer

    ld e,#11  ; 11 lines of 31  

    ld b,#31

00001$:
    ini           ; populate (hl) and increment hl, decrements b, sets z if b is 0   
    nop
    jp nz,00001$ ; char loop on b
    in a, (#0xBE) ;every 32nd character we read but do not put in hl
    dec e ; line loop 
    ld b,d
    jr nz, 00001$ ; line loop on e
            

    ld a,#0x20
    out (#0xBF),a
    ld a,#0x58
    out (#0xBF),a

    ld hl, #_scroll_buffer        

    ld e,#11
    ; b is 31

    xor a
00002$:    
    outi         ; read from (HL), writes to the (C) port, increment HL, decrement B, set Z if zero
    nop        
    jp nz,00002$ ; char loop on b
    out (#0xBE), a  ;every 31 we have to write 0 to port, a was set to 0 above        
    dec e ; line loop 
    ld b,d
    jr nz, 00002$ ; line loop on e

    ld a,#0x81
    out (#0xBF),a
    ld a,#0x19
    out (#0xBF),a

    ld hl, #_scroll_buffer

    ld e,#11  ; 11 lines of 31  

    ; b is 31

00003$:
    ini           ; populate (hl) and increment hl, decrements b, sets z if b is 0    
    nop
    jp nz,00003$ ; char loop on b
    in a, (#0xBE) ;every 32nd character we read but do not put in hl
    dec e ; line loop 
    ld b,d
    jr nz, 00003$ ; line loop on e

    ld a,#0x80
    out (#0xBF),a
    ld a,#0x59
    out (#0xBF),a
    
    ld hl, #_scroll_buffer    

    ld e,#11
    ; b is 31
    
    xor a
00004$:    
    outi           ; read from (HL), writes to the (C) port,  increment HL, decrement B, set Z if zero
    nop
    jp nz,00004$ ; char loop on b
    out (#0xBE), a  ;every 31 we have to write 0 to port, a was set to 0 above        
    dec e ; line loop 
    ld b,d
    jr nz, 00004$ ; line loop on e
 

Link to comment
Share on other sites

Your solution will exceed the Vblank time and will show frame tearing.

The best way is to allocate a whole game window in ram (if you can).

Even with 1KB of ram you can have video buffer of eg 32x20=640 bytes where the z80 can work and that can be transferred to vram in one frame without frame tearing.

 

If you need more ram for the game logic and you cannot allocate a whole frame buffer in ram, you can avoid frame tearing using two name tables. While you write to the first, you display the second. When you are ready, you switch the two pages without frame tearing and repeat the process.

 

 

 

 

Edited by artrag
Link to comment
Share on other sites

This is an example that shows how to use two PNTs to have scrolling without frame tearing.

Naturally the time spent to build in VRAM the hidden page can be more than one frame, but the final result is perfect (swapping pages takes almost no cycles).

The ram used by this approach is practically zero. 

The speed is limited by the time you need to 'compose' the next frame in the hidden page

 

maze_scroll (1).bas

  • Like 1
Link to comment
Share on other sites

I forgot a rather important detail when I provided my solution, sorry I wrote the code a year ago and what I presented is only part of my smooth-scrolling solution.  I'm flipping between screen 1 and 2 and the scroll of screen 1 is performed while screen 2 is active and then screen 2 is scrolled while screen 1 is active, so tearing isn't an issue.  In my case I couldn't sacrifice 768 bytes for a screen buffer so I'm drawing the landscape on the fly and scrolling the VRAM itself.  If I could have crammed the game in under 200ish bytes I probably could have opted for in-memory map but I'm a little skittish of the stack marching over my data 😄

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.
Note: Your post will require moderator approval before it will be visible.

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.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...