nesdev.com
http://forums.nesdev.com/

Proper X/Y split in neslib
http://forums.nesdev.com/viewtopic.php?f=2&t=16435
Page 1 of 1

Author:  na_th_an [ Fri Sep 01, 2017 4:59 am ]
Post subject:  Proper X/Y split in neslib

I've modified neslib to allow for proper X/Y split. It is obviously glitchy. For best results, you have to play with blank lines and the placement of your sprite 0 hit, so the last two writes in the modified split rutine go into HBLANK. In the proof of concept attached, this is not correctly timed and a visible glitch can be noticed.

I was thinking on a compo entry for this year which needs to alternate between horizontal and vertical scrolling levels. I thought about using vertical mirroring and hiding the screen updates behind the status bar (hud). The target mapper is CNROM.

Maybe this is useful for somebody - and I'm sure it can be improved, so I share it here.

This is my new split routine:
Code:
;;void __fastcall__ split(unsigned int x,unsigned int y);

_split:

   ; Extract SCROLL_Y1, SCROLL_X1, WRITE1 from parameters.

   sta <TEMP

   txa
   bne @1
   lda <TEMP
   cmp #240
   bcs @1
   sta <SCROLL_Y1
   lda #0
   sta <TEMP
   beq @2   ;bra

@1:
   sec
   lda <TEMP
   sbc #240
   sta <SCROLL_Y1
   lda #8               ;; Bit 3
   sta <TEMP
@2:

   jsr popax
   sta <SCROLL_X1
   txa
   and #$01
   asl a
   asl a                ;; Bit 2
   ora <TEMP               ;; From Y
   sta <WRITE1            ;; Store!

   ; Calculate WRITE2 = ((Y & $F8) << 2) | (X >> 3)

   lda <SCROLL_Y1
   and #$F8
   asl a
   asl a
   sta <TEMP             ;; TEMP = (Y & $F8) << 2
   lda <SCROLL_X1
   lsr a
   lsr a
   lsr a                ;; A = (X >> 3)
   ora <TEMP             ;; A = (X >> 3) | ((Y & $F8) << 2)
   sta <WRITE2            ;; Store!

   ; Wait for sprite 0 hit

@3:
   bit PPU_STATUS
   bvs @3
@4:
   bit PPU_STATUS
   bvc @4

   ; Set scroll value
   lda PPU_STATUS
   lda <WRITE1
   sta PPU_ADDR
   lda <SCROLL_Y1
   sta PPU_SCROLL
   lda <SCROLL_X1
   ldx <WRITE2
   sta PPU_SCROLL
   stx PPU_ADDR
   
   rts


Which needs a couple of extra variables in ZP not present in unmodified neslib. Add them to crt0.s:
Code:
SCROLL_Y1:          .res 1
WRITE1:            .res 1   
WRITE2:            .res 2      ; For extra X/Y split data.


Anyways, everything is in the zip (plus a .NES file).

Attachments:
poc.zip [63.66 KiB]
Downloaded 20 times

Author:  dougeff [ Fri Sep 01, 2017 6:00 am ]
Post subject:  Re: Proper X/Y split in neslib

Thanks for this.

I have 2 issues.

1. I feel like arbitrary / on-the-fly X/Y splits are not a good idea. People should probably precalculate 2005/2006 values and not make the CPU do it.

2. You are using shiru's Y scrolling system, which involves substraction (if Y scroll > 240 pixels). This works fine for 2 screen high games, but you mentioned vertical scrolling. How are you going to calculate Y positions in a map that extends over 2 screens high? Division by 240?

Author:  tepples [ Fri Sep 01, 2017 6:03 am ]
Post subject:  Re: Proper X/Y split in neslib

Probably the best way to handle maps taller than 240 pixels is to store the offset between the top of the map (in world coordinates) and the top of the 240- or 480-pixel plane explicitly, as tokumaru described.

Author:  na_th_an [ Fri Sep 01, 2017 6:56 am ]
Post subject:  Re: Proper X/Y split in neslib

dougeff wrote:
Thanks for this.

I have 2 issues.

1. I feel like arbitrary / on-the-fly X/Y splits are not a good idea. People should probably precalculate 2005/2006 values and not make the CPU do it.

2. You are using shiru's Y scrolling system, which involves substraction (if Y scroll > 240 pixels). This works fine for 2 screen high games, but you mentioned vertical scrolling. How are you going to calculate Y positions in a map that extends over 2 screens high? Division by 240?


I can do some simplifications for my game, as Y won't be ever > 240 and the scrolling will always be performed in the first 32 visible scans of nametable B. But for sharing, I chose to take a more general approach.

Anyways, in my engine I don't do division by 240. I just keep one set of "world" variables and one set of "screen" variables, which I keep always synchronized. The "world" variables are used to read the map data and fill a circular 16x16 tiles buffer (256x256 pixels), the "screen" variables are used to keep track on where on screen to write. Each time I advance my world coordinates I do so with my screen coordinates, substracting 240 if I go >= 240.

I think this is what tepples mentions.

Page 1 of 1 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/