Skip to content

Re-integrate disc support, and add a configurable boot order#54

Open
BenHetherington wants to merge 26 commits intoOffBroadway:custom-loader-menufrom
BenHetherington:integrate-discs-into-menu
Open

Re-integrate disc support, and add a configurable boot order#54
BenHetherington wants to merge 26 commits intoOffBroadway:custom-loader-menufrom
BenHetherington:integrate-discs-into-menu

Conversation

@BenHetherington
Copy link

@BenHetherington BenHetherington commented Jul 23, 2025

This PR re-enables disc support in the menu, allows you to switch between the disc drive and FlippyDrive (using the L and R buttons on the 'Game Play' face of the cube), displays UI for switching between these two devices, and allows you to configure a preferred boot order in the .ini file.

As well as being able to choose devices manually, you can also play discs automatically on startup (without needing to hold a button), or fall back to the FlippyDrive if no disc is inserted. Or, if you don't have a disc drive installed, you can choose to disable disc functionality altogether.

To support this, this PR also:

  • Adds many more threaded disc-reading functions, and the ability to cancel (break) reads
  • Adds support for the 'Press Start' screen to display information for either the disc or the FlippyDrive-selected game, including disc-exclusive blobs (e.g. 'Reading disc…')
  • Moves bs2, audio, and drawing functions into their own files
  • Adds structs and hooks for 'element alphas', button descriptions, blobs, and adds a custom blob for new textures – needed to support the added UI for switching devices
  • Adds a navigation stack to the 'game play' menu, to simplify navigation (as the disc drive doesn't show the loader menu)
  • Corrects prev_menu_id to next_menu_id, and renames SOUND_SUBMENU_ENTER to SOUND_SUBMENU_CONFIRM
  • Explicitly builds with C23, to treat functions like void foo(); as having no parameters, regardless of GCC version

This is quite a bit bigger than my other PRs so far – sorry about that! More refactor-y changes will be split into their own commits, so you may prefer to review this commit-by-commit.

Note that, as ever, I've only been able to test this on PAL 1.0 (see comment), but I have tested with both PAL and NTSC-J discs.

Among other things, this ensures that function declarations like `void foo();` are treated as having no parameters, regardless of GCC version.
This creates a thread that handles disc access, including adapting to the user opening the lid, and either changing disc or having no disc inserted. This state then gets reported to the GameCube menu as per the stock IPL.

So far, it’ll just load enough of the disc to load the banner into the ‘game play’ menu.
I’ve made some temporary changes that essentially replace the FlippyDrive with the disc. This `#define` and these `#if`s should make it a bit clearer what bits of the code need tidying up (once I get to that stage!).
This replaces the FlippyDrive ‘loader’ menu with the standard ‘press start’ screen again, and displays the disc’s state, including any ‘insert a disc’ or ‘loading disc’ messages, and the loaded disc’s banner.
This should allow games to be started both from the ‘Press Start’ menu and just from starting up the GameCube, just using the existing booting code (so reading the disc’s DOL while the screen is blank).
This can happen if the disc cover is opened after pressing Start. The fade-in and the cubes already adapt to this, we just have to restart the BGM that we stopped.
Using L and R on the ‘game play’ screen, it’s now possible to switch between the disc drive and the FlippyDrive. There’s no visual feedback yet – that’s still yet to come.

To support this, all the `#if TEMP_TEST_DISC`s have been replaced with dynamic conditionals based on which device is active, with some simplifications where possible.
This should hopefully make it a bit more responsive to switch from the disc to the FlippyDrive, if the switch happens while a disc is being loaded.
This replaces a hardcoded time to wait for, instead inspecting the actual alpha values.

This delay is to allow the banner fade to complete before changing the banner pointer, as the banner would otherwise abruptly disappear when this switch happens.
This non-functional change moves these bs2-prefixed functions to a new file (without changing their contents).

As well as splitting this code out from `main.c`, it allows common constants and the device state to be made accessible from its header file.
Another non-functional change, this time making it easier to access these IPL functions from outside `menu.c`.
This adds the structs and functions used for getting and updating the alpha used by various elements, as well as wrapping the button description updates and drawing.
While on the cube’s ‘Game play’ menu (before pressing A to enter the menu), this displays a ‘L: Disc’ and ‘R: FlippyDrive’ UI, using icons to represent the two devices.

The selected device is highlighted, and this will update when a new one is selected (using L or R).

As not much gets drawn outside of the cube on this screen, the simplest way to do this was to draw it along with the button descriptions (making care to only show it while this screen is active). Additionally, this relies on the element alpha and blob systems, hence the added code for them.
These should all be non-functional changes:
- Moves the device selection input handling to `device_selector.c`
- Move unused variables out of `main.c`
- Make `top_level_banner_element_alpha` use our struct type, for clarity
This matches how other inputs behave while backing out from the ‘press start’ or FlippyDrive menus.
This should make things a bit clearer than a simple `bool`, especially once auto-device switching (on boot) gets implemented. As a nice bonus, it opens the door for this to be extended in future (e.g. for adding separate SD Card and network ‘devices’).
This allows the user to specify, for instance, that they’d like to check the disc drive first, and fall back to the FlippyDrive if no disc is inserted.

This will try each device in order, until it reaches the first successful one (or the boot animation finishes).
Remove some unneeded code when initialising the disc ‘Press Start’ menu, and remove some constants that are now in `bs2.h`.
This makes it a bit simpler to maintain the different menu flows for the disc drive and FlippyDrive modes.

As before, pressing B while on the ‘Press Start’ screen will return to the top-level gameplay menu if the disc drive is active, and back to the ‘loader’ menu if the FlippyDrive is active – just now with less device-specific code.
The disc/FlippyDrive/L/R icons now look significantly better, as they’re displayed with the correct colours. I think my I4-encoded icons are in linear colour space, and I previously called `setup_tex_draw()` with a flag to treat them as sRGB.

Other than that, this re-adds support for post-boot delays, moves `cube_menu_alpha` to a shared header, and removes some TODOs from disc-loading that aren’t going to be done, or have already been done.
Intended for those who don’t have an original disc drive installed, setting `allow_disc_drive` to `0` will disable the device selector (so discs can’t be selected), and will skip past discs in the automatic boot order.
@BenHetherington
Copy link
Author

In case you need to re-export the textures for whatever reason, these are SVGs of them:

SVG Notes
Disc An original icon (graphic design is my passion)
FlippyDrive Based on the icon used in Swiss (which is, in turn, based on the logo on the PCB), uses GAMECUBEN font
L Slightly stretched version of 'L' from League Gothic, a free font similar to Futura Condensed
R Slightly stretched version of 'R' from League Gothic, a free font similar to Futura Condensed

@BenHetherington
Copy link
Author

BenHetherington commented Jul 23, 2025

Also, while there's a lot here, there's still more that I've done or would like to do on top of this:

Most of the remaining TODOs I've left in this PR relate to these. However, I think they're definitely best left for future PRs 😄

This fixes a typo, where this setting was previously only read when `boot_order` was present.
Previously, on NTSC 1.0, the disc worker thread might briefly detect that the disc cover is open during startup. This would cause the automatic device switching logic to move onto the next boot device, or the GameCube to go to the menu.

We already have a delay after switching into bypass mode. Not my favourite kind of fix, but upping this delay from 10ms to 20ms seems to resolve the issue.
Apparently `bs2tick` may run before `pre_thread_init` does – so let’s protect against that.
@BenHetherington
Copy link
Author

I remembered that FORCE_IPL_LOAD is a thing 😆 That allowed me to do a cursory test of NTSC 1.0, NTSC 1.1, NTSC 1.2-001, NTSC 1.2-101, and PAL 1.2, in addition to PAL 1.0, and it seems like these all work. PAL 1.1 wouldn't output any video for me, but I've at least still confirmed it at least starts a disc OK.

This fixes an undetected error when calling `dvd_audio_config()`, due to ‘configuration out of permitted period’ (`0x052402`).

It seems like `dvd_audio_config()` needs to be run shortly after initialising the disc (i.e. reading the disc ID), before reading other data. So, this moves this call from `bs2start()` to the disc-reading thread, so it can be run before reading the disc’s banner.
Not sure how, but apparently this was missed before. Doesn’t hurt to check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant