So, the kids out-grew their Nintendo WII and moved on to Xbox (or Netflix). What's an electronics-hoarder like myself supposed to do?
There is an old saying: "If you love it then you should have run DOOM on it", so I set out to do that, and more. And while I'm at it, why not take the scenic route?
NOTE: I will not cover how to jailbreak and install homebrew.
Choosing a Linux distribution
Looking at the raw computing power, the WII should have no problem running Linux:
- PowerPC CPU running at 729 MHz
- ATI Hollywood GPU running at 243 MHz
- 88 MB of memory (ouch!)
- WiFi 802.11b/g
- USB, Audio, Video, blah blah blah
There are a few linux distributions ported to the WII, and I went through a couple before choosing.
The 1st time I got the WII to boot was using WiiToo. It is a Gentoo based system, so it is very flexible.
However, I found that it requires quite a bit of work to update it on the little WII, both on my side (it's a very old version, dating back to 2009) and on Wii's side, since Gentoo is all about compiling-from-source.
So I moved on, looking for a binary-package-based distribution. and I found Whiite, which is a Debian 5 (Lenny) distribution. But soon I found, again, that it is hard to get a 2009-ish system up-to-date.
After taking a short break, I came back to the project and found Wii-Linux-NGX and I knew this was the one!
Based on Debian 8, updated in 2017 - finally, something to work with.
We will start with the base system, as detailed in Wii-Linux-NGX.
After we successfully boot, we will start the post-installation setup.
change default root password
$ passwd
configure Wifi
$ /root/whiite-ez-wifi-config
rename the network adapter device name
- edit /etc/network/interfaces
- wlan0 -> wlan1
we really need to enable swap, because compilation, which we will get to a little later, won't work with 88MB or RAM. also, we will use the actual /tmp partition on the sd-card.
enable swap (in /etc/fstab)
/dev/mmcblk0p3 swap swap defaults 0 0
disable tmpfs on /tmp by commenting the line /tmpfs . . . in /etc/fstab
and enable swap
$ swapon -a
next, enable remote ssh access, because working with a keyboard in front of the TV is sub-optimal.
we'll use RSA keys and not passwords. feel free to skip this part
-
allow root remote login with password
- edit /etc/ssh/sshd_config PermitRootLogin yes
$ service ssh restart
-
login remotely
- create /root/.ssh/authorized_keys
- copy RSA/DSA public keys to it
-
revert changes to /etc/ssh/sshd_config
$ service ssh restart
now we can log out, login remotely from a normal laptop, and move-on.
next step - update the system. a lot has changed since 2017.
for starters - the PPC repositories have been archived, so we need to point our system to the new location
PowerPC APT repositories have moved, so add the new locations to /etc/apt/sources.list
deb http://archive.debian.org/debian/ jessie main
deb http://ftp.ports.debian.org/debian-ports unstable main
deb http://ftp.ports.debian.org/debian-ports unreleased main
deb http://ftp.ports.debian.org/debian-ports experimental main
and engage
$ apt update
$ apt upgrade
next, install additional packages.
specifically, xorg and build tools, since we're going to have to compile stuff from source code
$ apt install libpng12-0 libstdc++6 libx11-6 zlib1g gcc patch autoconf automake libtool libsdl1.2-dev libsdl-sound1.2-dev libsdl-net1.2-dev make g++ xorg lightdm git
thinking ahead, we're going to have a few non-root users for running our software.
we will have a separate user for each software: DOSBox, ScummVM and DOOM.
since most of these are SDL based, we're going to have to grant these users low-level access to the keyboard, mouse, audio and video.
1st, allow console access to dedicated group
$ addgroup --system console
$ chgrp console /dev/console
$ chmod g+rw /dev/console
and add our dosbox user
$ useradd -m -U dosbox
$ usermod -a -G console dosbox
$ usermod -a -G tty dosbox
$ usermod -a -G video dosbox
$ usermod -a -G input dosbox
$ usermod -a -G audio dosbox
Building dosbox
building dosbox from source is pretty straightforward.
the only caveat is the build time on the WII hardware: ~1.5 hours.
it is also the reason we had to enable swap, or gcc would fail compiling some of the more complex source files.
$ wget https://netix.dl.sourceforge.net/project/dosbox/dosbox/0.74-3/dosbox-0.74-3.tar.gz
$ tar -xzf dosbox-0.74-3.tar.gz
$ cd dosbox-0.74-3
$ ./autogen
$ ./configure
$ make install
Building ScummVM
as with dosbox, this is pretty straightforward but takes (a little more than) a while.
$ wget https://www.scummvm.org/frs/scummvm/2.1.1/scummvm-2.1.1.tar.gz
$ LDFLAGS="-Wl,--no-keep-memory" ./configure
$ make install
Running DOOM
Now, of course I could just run DOOM via dosbox, but since the source code is available, I decided to compile and run it.
I started with the Linux SDL port of the doom code, but it turned out to have 2 major issues, and a minor one:
- it would not compile on a PPC CPU
- it was not full-screen
- it would not compile and run on a pure 64bit system
while #1 and #2 are crucial for our end goal, issue #3 was for debugging purposes only - it was easier developing the code on my laptop than on the WII, mainly due to compilation times.
the code changes can be seen in detail in the github repo, but I will explain the changes in high level.
adding PPC support
This was a small issue with the code when __BIG_ENDIAN__ precompiler directive is defined.
64bit support
This task turned out to be more than "just compile as 64bit".
The code was very old and new GCC versions throw warnings and errors about
- implicit int variables
- string literals being cast to pointers
the 64bit part was a simple matter of not assuming
sizeof(void*) == sizeof(int) == 4
full-screen
the SDL 1.2 port was running doom in its native, awesome 90's resolution of 320x200, but the WII's video is aimed at pre-HDMI televisions, so the native resolution is 576x516.
the code changes are localized to a single file i_sdl_video.c.
the original code in I_InitGraphics used
SDL_SetVideoMode(320, 200, 8, SDL_SWSURFACE)
to initialize the the display-buffer, and then pointed the doom code to draw directly into it
screens[0] = (byte*) (screen->pixels);
we will modify the code to use 2 separate buffers - the screen will be initialized to our native resolution, and another buffer for doom to draw into, which is 320x200.
1st, modify the video mode
screen = SDL_SetVideoMode(576, 516, 8, SDL_SWSURFACE);
...
virt_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, 320, 200, 8, 0, 0, 0, 0);
screens[0] = (byte*) (virt_screen->pixels);
now that we have both screens set up, we will need to modify the screen update routine I_FinishUpdate.
right before the original code, we will copy the image into the screen with scaling
scale(virt_screen, screen);
SDL_Flip(screen);
for the scaling algorithm, I decided to go with a very simple algorithm, for 2 reasons:
- speed
- consistency
I wanted the copying to be as computationally-simple as possible, and give consistent results (e.g. no "random" offsets).
the scaling math is pretty simple:
576 = (4*2+1)*64
516 ~= 500 = (3+2)*100
this means that horizontally, we will copy
4 times: 1 bytes --> 2 bytes, and another 1-->1
vertically, we will duplicate 1 line 3 times, then 1 line 2 times.
static const int xmap[] = {2, 2, 2, 2, 1};
static const int ymap[] = {3, 2};
// *i - axis index
// *d - axis destination
// *s - axis source
for(yi = yd = ys = 0; ys < 200; ++ys) {
for(xi = xd = xs = 0; xs < 320; ++xs) {
// duplicate source pixel into destination line
memset(PIXEL(dst, xd, yd), *PIXEL(src, xs, ys), xmap[xi]);
xd += xmap[xi];
// point to next destination pixel (after duplications)
xi = (xi + 1) % SIZEOF_ARRAY(xmap);
}
// duplicate line as many times as required
// -1 for the line we drew above
for (y = 1; y < ymap[yi]; ++y)
memcpy(PIXEL(dst, 0, yd+y), PIXEL(dst, 0, yd), 576);
// point to next line (after duplications)
yd += ymap[yi];
yi = (yi + 1) % SIZEOF_ARRAY(ymap);
}
in order to run doom you'll need to download the WAD files, and then
export DOOMWADDIR=~/doom.wad.directory/
./sdl_doom/linux/sdl_doom
and voila!
finishing touches
for each application, we will have a dedicated user that will auto-run the application when logging on.
in order to accomplish that, we will simply add the relevant lines to each user's ~/.bashrc , e.g.
dosbox
exit
the modified code is available here
SDL DOOM @ Debian/WII
Overview
Getting SDL-DOOM to run in full screen on Debian/WII/PowerPC
Acknowledgements
ID Software Linux Doom v1.10
AlexOberhofer DOOM-X11-64Bit
GeekChef.com More Doom obsession with Ubuntu PowerPC
License
see the DOOMLIC.TXT file for details
Top comments (1)
Good job!! You just miss to mention the Vintage Package Manager
github.com/francescobianco/vintage