It is currently Mon Dec 11, 2017 10:26 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 4 posts ] 
Author Message
PostPosted: Fri Sep 01, 2017 4:59 am 
Offline

Joined: Mon May 27, 2013 9:40 am
Posts: 362
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

_________________
http://www.mojontwins.com
Top
 Profile  
 
PostPosted: Fri Sep 01, 2017 6:00 am 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1865
Location: DIGDUG
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?

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Fri Sep 01, 2017 6:03 am 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19328
Location: NE Indiana, USA (NTSC)
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.


Top
 Profile  
 
PostPosted: Fri Sep 01, 2017 6:56 am 
Offline

Joined: Mon May 27, 2013 9:40 am
Posts: 362
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.

_________________
http://www.mojontwins.com


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group