Beast Fighter and Window Function, does it work on hardware?

Discussion of programming and development for the original Game Boy and Game Boy Color.
Post Reply
Alyosha_TAS
Posts: 173
Joined: Wed Jun 15, 2016 11:49 am

Beast Fighter and Window Function, does it work on hardware?

Post by Alyosha_TAS »

Hi all,

I am working on the Sachen game Beast Fighter and I notice the status bar at the bottom of the screen doesn't show up.

Image <-- Normal Frame
Image <-- The one loading frame where we can see the status bar.

The window is set to 0,0.

On the one frame where the rest of the screen if off during loading, you can see that the status bar shows up correctly. In this case the game turns the window on at line 0 and just runs to the end.

But, on normal frames after loading, it does this:

- LY = LYC interrupt at sacnline 114
- turn on the window
- turn off the window again at vblank.

My understanding is that when you first turn the window on it always begins at the location specified by the window coordinates, regardless of the current LY value. So is the correct behaviour to not draw the status bar as above? Some videos online never the less show the status bar, what is the correct behaviour here?

Thanks for any insight, it's either one way or the other but I don't know which is correct.
nitro2k01
Posts: 252
Joined: Sat Aug 28, 2010 9:01 am

Re: Beast Fighter and Window Function, does it work on hardw

Post by nitro2k01 »

If the WX, WY and window on flag conditions are all true at the same time, the PPU goes into window rendering mode. It then draws the window on each following line, starting at X position specified by WX, and the line counter is incremented for each consecutive line. (What I'm calling the line counter selects which line from the map is drawn for that LCD line.) However, if you set the window bit to 0, you can pause the rendering of the window. Once the bit is enabled again later in the same frame, rendering will resume at the same line counter value. Or put differently, this allows you to split an image into two parts, if you wanted.

If it turns off the window in the VBlank period, and doesn't touch WY during the frame, the PPU should never go into window rendering mode. If it does so at some point after line 0 has started (perhaps still in the VBlank interrupt handler) window rendering mode could be entered and that could be used to resume it later on in the frame.

So my follow-up question would be, could you log any writes to LCDC, WY and perhaps also WX and note at which line they each happen?
Shonumi
Posts: 342
Joined: Sun Jan 26, 2014 9:31 am

Re: Beast Fighter and Window Function, does it work on hardw

Post by Shonumi »

nitro2k01 wrote: If the WX, WY and window on flag conditions are all true at the same time, the PPU goes into window rendering mode. It then draws the window on each following line, starting at X position specified by WX, and the line counter is incremented for each consecutive line. (What I'm calling the line counter selects which line from the map is drawn for that LCD line.) However, if you set the window bit to 0, you can pause the rendering of the window. Once the bit is enabled again later in the same frame, rendering will resume at the same line counter value. Or put differently, this allows you to split an image into two parts, if you wanted.
Star Trek: 25th Anniversary does that iirc, when displaying messages or showing the map. Quite annoying behavior to figure out if you haven't heard anything about it beforehand.
Alyosha_TAS wrote: The window is set to 0,0.
Be careful with Window X. Though it's set to 0, it can still render. Even though Nintendo explicitly said values under 7 shouldn't be used, values of 0-6 apparently act as 0 anyway. For future reference (if you start emulating GBC stuff) Star Wars Episode I - Racer does uses this behavior briefly when drawing your pod in the garage. It puzzled me for a long time because I thought if window offsets were out of range (7 supposedly being the minimum x value) it wouldn't draw, but that's not the case.

It sounds like Beast Fighter ought to be changing WY during the LYC interrupt, similar to how Mega Man I - V handle their status bars via the window. They trigger an LYC interrupt on some line (128?) but the relevant window tiles are at the bottom portion, so WY is adjusted accordingly.
nitro2k01
Posts: 252
Joined: Sat Aug 28, 2010 9:01 am

Re: Beast Fighter and Window Function, does it work on hardw

Post by nitro2k01 »

Shonumi wrote:Even though Nintendo explicitly said values under 7 shouldn't be used, values of 0-6 apparently act as 0 anyway.
I've come across this by accident when developing a game, and at least on GBC it produced garbage tile data for the first few pixels of a line. I would need to research this more at some point.
Shonumi
Posts: 342
Joined: Sun Jan 26, 2014 9:31 am

Re: Beast Fighter and Window Function, does it work on hardw

Post by Shonumi »

Fwiw, I'm just assuming values of 1-6 of WX get translated to 0. I never got around to making a test ROM myself. I believe that garbage data is supposed to be drawn to the screen, but the window in SW EP1 - Racer is all black, so even when it ends up pulling "random" values, the BG/WIN data in VRAM is all the same, making it moot. I've had the game since I was a kid, so I can verify that it looks fine on real hardware. It's the only commercial game I know that does this with WX, and now that you mention it, looks like the devs came up with a workaround.
Alyosha_TAS
Posts: 173
Joined: Wed Jun 15, 2016 11:49 am

Re: Beast Fighter and Window Function, does it work on hardw

Post by Alyosha_TAS »

Thanks for the help so far.

I do still draw the window when WindowX is 0, so that part at least is not the issue. Actually the game never writes to WindowX or WindowY anyway.

(The LY=LYC interrupt happens on 104 not 114 like I wrote in the OP, my mistake.)
Here are all the writes to the PPU regs that happen in a frame:

Code: Select all

SL, Reg, (ID), value written
144 FF43 (SCX) 0x00
144 FF42 (SCY) 0x00
144 FF46 (DMA) 0xC0
146 FF40 (LCDC) 0xD3
104 FF40 (LCDC) 0xEB 
104 FF42 (SCY) 0x00
104 FF43 (SCX) 0x00 
So, it definitely turns off the window in vblank and doesn't turn it back on until LY=LYC interrupt. Maybe the writes to SCY and SCX at the interrupt are supposed to be writes to the window instead of scroll, but the whole interrupt routing is just this:

Code: Select all

====IRQ==== 
0048:  F3        DI                      A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1FD Cy:91196112 LY:104 zNHCie
0049:  CD AE 02  CALL #02AEh             A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1FD Cy:91196116 LY:104 zNHCie
02AE:  F5        PUSH AF                 A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1FB Cy:91196140 LY:104 zNHCie
02AF:  C5        PUSH BC                 A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F9 Cy:91196156 LY:104 zNHCie
02B0:  D5        PUSH DE                 A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F7 Cy:91196172 LY:104 zNHCie
02B1:  E5        PUSH HL                 A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F5 Cy:91196188 LY:104 zNHCie
02B2:  3E EB     LD   A,#EBh             A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F3 Cy:91196204 LY:104 zNHCie
02B4:  E0 40     LDH  (#FF40h),A         A:EB F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F3 Cy:91196212 LY:104 zNHCie
02B6:  FA 03 C2  LD   A,(#C203h)         A:EB F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F3 Cy:91196224 LY:104 zNHCie
02B9:  E0 42     LDH  (#FF42h),A         A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F3 Cy:91196240 LY:104 zNHCie
02BB:  3E 00     LD   A,#00h             A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F3 Cy:91196252 LY:104 zNHCie
02BD:  E0 43     LDH  (#FF43h),A         A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F3 Cy:91196260 LY:104 zNHCie
02BF:  E1        POP  HL                 A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F3 Cy:91196272 LY:104 zNHCie
02C0:  D1        POP  DE                 A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F5 Cy:91196284 LY:104 zNHCie
02C1:  C1        POP  BC                 A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F7 Cy:91196296 LY:104 zNHCie
02C2:  F1        POP  AF                 A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1F9 Cy:91196308 LY:104 zNHCie
02C3:  C9        RET                     A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1FB Cy:91196320 LY:104 zNHCie
004C:  FB        EI                      A:00 F:70 B:00 C:10 D:C0 E:A0 H:CF L:10 SP:C1FD Cy:91196336 LY:104 zNHCie
004D:  D9        RETI   
So yeah, seems like it shouldn't really be drawn. Any ideas?

EDIT: Also, If i don't draw the window at all the status bar displays just fine since it's also available in the BG. So, maybe it's really not drawing the window somehow afterall?

EDIT2: Does CGB boot up with WX and WY as 0xFF instead of 0x00? GB seems to boot to (0,0) according to Gekkio's tests, meaning the window would hide the status bar, but if CGB boots to (0xFF,0xFF) it would be really disabled and the the BG version of it would show through. Plausible?
nitro2k01
Posts: 252
Joined: Sat Aug 28, 2010 9:01 am

Re: Beast Fighter and Window Function, does it work on hardw

Post by nitro2k01 »

Do you have a link to a working dump and info about the mapper so I can test it on hardware?
Alyosha_TAS
Posts: 173
Joined: Wed Jun 15, 2016 11:49 am

Re: Beast Fighter and Window Function, does it work on hardw

Post by Alyosha_TAS »

The mapper is Sachen MMC2 as described here:

https://web.archive.org/web/20170803195 ... en_Mappers

I'm not sure what the policy is here regarding linking to ROM sites, but if you search for 'sachen beast fighter rom' it should be one of the first things that pops up.

The mapper does some tricky stuff to display 'sachen' instead of nintendo in the boot process. So alternatively it might be easier to make a test rom that tries to display a window without writing to window x,y and see if it behaves differently on GB and CGB.

Either way I'll be interested to see what the results are. Good Luck!
User avatar
tmk
Posts: 14
Joined: Tue Nov 28, 2017 2:40 pm
Contact:

Re: Beast Fighter and Window Function, does it work on hardw

Post by tmk »

It does work.
Image
I'd say that window bit is some code leftover since, as you've noticed, the status bar works anyway.
I don't know why window is not displayed but in CGB manual they state that:
Attempting to display multiple windows by switching the window ON and OFF during H-blanking may result in the lower window not being displayed.
Alyosha_TAS
Posts: 173
Joined: Wed Jun 15, 2016 11:49 am

Re: Beast Fighter and Window Function, does it work on hardw

Post by Alyosha_TAS »

Cool thanks for testing. So it definitely works on CGB. Do you also have an original gameboy (DMG) to test on? If it also works on a DMG model then I'm definitely not understanding why.
User avatar
tmk
Posts: 14
Joined: Tue Nov 28, 2017 2:40 pm
Contact:

Re: Beast Fighter and Window Function, does it work on hardw

Post by tmk »

Well, it also works on DMG - I've just tried it.
Alyosha_TAS
Posts: 173
Joined: Wed Jun 15, 2016 11:49 am

Re: Beast Fighter and Window Function, does it work on hardw

Post by Alyosha_TAS »

tmk wrote:Well, it also works on DMG - I've just tried it.
Dang, now I'm really stumped.

Thanks for testing though.

I guess I could have an error somewhere else that actually turns the window off, but it sure doesn't look like it. It turns it off once in VBlank and turns it on once in LY=LYC.

If anyone has any ideas I'm open to suggestions.
Post Reply