Building for the Wii

A C++ game made with Acron can run on the Nintendo Wii as homebrew: a program started from the Homebrew Channel, off an SD card or a USB drive, or in the Dolphin emulator. It renders with the Wii’s GX hardware, plays sound through libogc’s ASND mixer, and is played with Wii Remotes (with the Nunchuk, the Classic Controller and the IR pointer) and GameCube controllers.

The Wii SDK

A game is compiled against the Acron Wii SDK: the engine cross-compiled for the Wii as static libraries, single-threaded, with a CMake package. It contains:

include/acron/        the engine's headers
lib/                  the static libraries (libacron.a, libp3wiidisplay.a, ...)
lib/cmake/Acron/      the CMake package, with AcronWii.cmake
etc/                  the default configuration (.prc files)
starter/              a first game: a spinning cube and a line of text
VERSION               the engine release and commit it was built from

What you need besides it:

  • devkitPro, the homebrew toolchain, which is not part of the SDK (see Getting Started), with these packages:

    sudo dkp-pacman -S wii-dev ppc-zlib ppc-libpng ppc-freetype
    export DEVKITPRO=/opt/devkitpro DEVKITPPC=/opt/devkitpro/devkitPPC
    
  • CMake 3.13 or later (Ninja recommended), and for testing, Dolphin.

With acronmanager

Declare the game’s CMake build in pyproject.toml (see Building C++ Games for the Desktop), and the Wii build in [tool.acron.wii]:

[tool.acron.cmake]
target = "mygame"

[tool.acron.wii]
# sdk = "path/to/acron-wii-sdk-....tar.gz"  # a local SDK (default: the archive's latest)
build_dir = "build/wii"                    # the default
configure_args = []
# prepare = ["tools/data.sh"]              # run from the project root first
# app_name = "mygame"                      # apps/<name>/ (default: the one the build made)

acronmanager build --wii fetches the Wii SDK (once, into the shared cache), configures the project with devkitPro’s toolchain file ($DEVKITPRO/cmake/Wii.cmake; DEVKITPRO defaults to /opt/devkitpro), builds it and prints the path of the .dol. acronmanager dist --wii builds and zips the Homebrew Channel app, apps/<name>/, as the root of an SD card wants it, into dist/<name>-<version>-wii.zip (or copies the .dol when the game makes no such app). The Homebrew Channel’s icon comes from [tool.acron.app] (see App Icons and Store Art).

To run the game in Dolphin from acronmanager run, add a run target that builds it for the Wii and hands the .dol to a script that starts Dolphin:

[tool.acron.scripts]
wii = { cmake_target = "mygame", build_dir = "build/wii",
        configure_args = ["-DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Wii.cmake",
                          "-DCMAKE_PREFIX_PATH=/path/to/acron-wii-sdk"],
        env = { DEVKITPRO = "/opt/devkitpro", DEVKITPPC = "/opt/devkitpro/devkitPPC" },
        executable = "mygame.dol", runner = ["tools/run-dolphin.sh", "{executable}"] }

By hand

The starter in the SDK builds as it is, with devkitPro’s powerpc-eabi-cmake (which brings its toolchain):

cd starter
$DEVKITPRO/portlibs/wii/bin/powerpc-eabi-cmake -S . -B build -G Ninja \
    -DCMAKE_PREFIX_PATH=$PWD/..
cmake --build build

That makes build/starter.dol, which Dolphin opens (File > Open), and build/apps/starter/ (boot.dol, meta.xml, icon.png). Copy apps/ to the root of an SD card to start it from the Homebrew Channel, or pack it with cmake --build build --target starter_zip.

Building your game

find_package(Acron REQUIRED)

add_executable(mygame main.cxx)
acron_wii_executable(mygame)
acron_wii_homebrew_app(mygame NAME mygame TITLE "My Game" VERSION 1.0
                       AUTHOR "Me" DESCRIPTION "What it is"
                       ICON hbc/icon.png DATA data/models.mf)
acron_wii_executable(<target>)

Adds the engine’s headers, links the engine, FreeType, libpng, zlib and libogc in an order the linker resolves, and converts the program to <target>.dol.

acron_wii_homebrew_app(<target> ...)

Lays out apps/<NAME>/ in the build directory on every build: boot.dol; meta.xml, your own with META <file> or written from TITLE, VERSION, AUTHOR and DESCRIPTION; icon.png, the channel’s 128 × 48 icon (ICON, else ACRON_WII_ICON, which acronmanager sets to the wii/icon.png it makes from the game’s icon or its own wii_icon); and the DATA files and directories. The target <target>_zip packs it as <NAME>.zip.

Writing for the Wii

Starting up

Call init_libacron() before opening the framework. The GX renderer is the only display, so open_window() gives you the TV; see the starter’s main.cxx.

Input

window->enable_keyboard() turns controller buttons into events named after the GamepadButton they are (face_a, dpad_up, guide for Home, …). The console’s Reset and Power buttons send wii-reset and wii-power. Players 2 to 4 are further input devices; the IR pointer is the window’s pointer.

Graphics

Fixed-function only: there are no shaders. Up to two texture stages per geom, sphere-mapped texture coordinates, hardware lights, vertex colours. The picture is 4:3, or 16:9 when the Wii is set to widescreen (the lens aspect follows it); NTSC and PAL both work.

Memory

About 88 MB in all (24 MB of fast MEM1, 64 MB of MEM2). Keep textures small and power-of-two sized, and load scenes one at a time.

Assets

Models as .bam files (made on a desktop with the tools of the desktop SDK or the wheel: egg2bam, …), images as .png, sounds as .wav (Ogg Vorbis and FFmpeg are not built in). Put them in a multifile (.mf) next to boot.dol and mount it with the VirtualFileSystem. Paths on the card are sd:/apps/<name>/ (usb:/ on a USB drive).

What is not there

No threads and no networking, and no RmlUi (it needs shaders).

The log

SYS_STDIO_Report(true) sends printf output to Dolphin’s log (enable the OSReport log in Dolphin’s logger).