Saturday, February 14, 2009

OpenSolaris, Qt and Game Development

Overview

A group of 3 other people and myself were charged with making a game for a class this trimester, which is essentially a Final Fantasy clone with a few quirks localized to our university. In thinking of a toolkit, I thought to myself "what event-driven toolkit provides a graphics system and paint system complete and robust enough to make this happen?" Naturally Qt came to mind. The professor suggested some Java toolkits, including SWT, but my experiences with SWT have not been at all good, so I decided to give Qt a shot. Another perk of Qt over SWT is how easy it is to learn and use, since my 3 team members are not familiar with it.

After a few days of playing with Qt tutorials on the Graphics framework and studying KDE games code, I had a small but working prototype of one of the modes of our game, where the character explores the scene of a level.




Things to notice that were easy to do:

- Creating a graphics item from a graphic file
- Moving it around
- Having it change form
- Collision detection with walls
- Dragging of the view to see different parts of the scene

Deployment

Before proceeding I had to make sure that the program would run on the target platform of the school servers: SunOS 5.10 (Solaris). Now Qt is a cross-platform toolkit, and binary builds of it are provided for Linux, OS X, and Windows, but not for Solaris (that I could find here).

Having recently installed VirtualBox after hearing lots of good things about it, I decided to give Solaris a spin as a virtual machine. There was a bit of confusion for me at the beginning with so many possible distros to choose from, but luckily since only 2 of them are supported by the KDE Solaris team, that narrowed it down. They prefer using SXCE, so I gave that a shot, but unfortunately some bug where X would show up but then freeze on the live dvd stopped me short (I figured it was an issue of running in a VM or something). Then I tried OpenSolaris 2008.11, which installed fine

Then the problem became that the instructions on the wiki for compiling using OpenSolaris were a bit lacking, a problem I have since mended with some updates based on my experience. After much strife with getting the environment set up just right, compiling was not a big deal, thanks to the awesome efforts of the KDE OpenSolaris team. I ran into some issue with a Qt example not compiling, and hacked it up to fix it, since it didn't much matter, and voila, Qt was on the system, and my previous example in the youtube video worked.

From here, I had a few options (as I saw it):
- build Qt as static, deploy a static binary
- build Qt as shared library, ask school admins to install Qt on servers
- build QtJambi, port to Java, deploy as jar

Since building Qt as static was not supported by the KDE Solaris team, I decided to give QtJambi a shot, and ported my example to Java. Unfortunately the QtJambi build specfile provided didn't work too well, and went into an infinite recursive make loop.

When at last I had almost given up, I discovered that the shared library approach doesn't actually require the system to have Qt installed on it, just that the necessary .so shared object files be deployed with the program itself, and to use a script to launch the program (a script which simply adds current directory to linker path).

A simple ldd resulted in this:


libc.so.1 => /usr/lib/libc.so.1
libQtGui.so.4 => /opt/foss/qt4/lib/libQtGui.so.4
libQtCore.so.4 => /opt/foss/qt4/lib/libQtCore.so.4
libCrun.so.1 => /usr/lib/libCrun.so.1
libm.so.2 => /usr/lib/libm.so.2
libglib-2.0.so.0 => /usr/lib/libglib-2.0.so.0
libpng12.so.0 => /usr/lib/libpng12.so.0
libSM.so.6 => /usr/lib/libSM.so.6
libICE.so.6 => /usr/lib/libICE.so.6
libz.so.1 => /usr/lib/libz.so.1
libXrender.so.1 => /usr/lib/libXrender.so.1
libXrandr.so.2 => /usr/lib/libXrandr.so.2
libXfixes.so.1 => /usr/lib/libXfixes.so.1
libXcursor.so.1 => /usr/lib/libXcursor.so.1
libXinerama.so.1 => /usr/lib/libXinerama.so.1
libfreetype.so.6 => /usr/lib/libfreetype.so.6
libfontconfig.so.1 => /usr/lib/libfontconfig.so.1
libXext.so.0 => /usr/lib/libXext.so.0
libX11.so.4 => /usr/lib/libX11.so.4
libgthread-2.0.so.0 => /usr/lib/libgthread-2.0.so.0
libnsl.so.1 => /lib/libnsl.so.1
libsocket.so.1 => /lib/libsocket.so.1
libexpat.so.1 => /usr/lib/libexpat.so.1
libXau.so.6 => /usr/X11/lib/libXau.so.6
libpthread.so.1 => /lib/libpthread.so.1
libmp.so.2 => /lib/libmp.so.2
libmd.so.1 => /lib/libmd.so.1
libscf.so.1 => /lib/libscf.so.1
libuutil.so.1 => /lib/libuutil.so.1
libgen.so.1 => /lib/libgen.so.1
libXevie.so.1 => /usr/X11/lib/libXevie.so.1
libXss.so.1 => /usr/X11/lib/libXss.so.1



Wow, that's a lot of shared objects! According to the Qt deployment guide though, all of the X libraries could and should be avoided to be packaged. I did end up adding other ones though, one by one, as I saw necessary until the program finally ran without a linker error. The bad news is this blew the total package up to 30 MB or so. Oh well, so be it, it ran!

And now...?

And now the real development can begin. There's only a few weeks to work on it, but that should be plenty. It won't be a terribly fantastic game as a result, but it was an interesting adventure, and more importantly proves the point that Qt is an awesome toolkit, and that there are quite a few options open for deployment.

Thanks to the KDE Solaris team for helping me with getting things building, I'd be nowhere without your help (in particular: szt, [ade], steleman, and trochej thanks a lot guys).

Tuesday, February 10, 2009

Karaoke with Windows (via VirtualBox)


Some time ago, a friend gave me this Chinese karaoke program called HomeKara2, which puts out a song-selection screen to one monitor, and the actual video with lyrics to another. I thought this was nifty, and tried to virtualize it with wine. First, to get Chinese working, I tried this "wineloc" project I used for my Japanese programs. No go. Also, the dual monitor output thing wasn't working. Bummer.

Recently I got hooked up with VirtualBox, a handy replacement for vmware for me, which I've been using for an OpenSolaris machine for developing a Qt game (that's a blog post to come). Somewhere along the line, I set up a Windows XP VM, just to test, and was surprised that it ran quite well, so I decided to put it to the test with HomeKara2.

I ran into some obstacles again, starting with that HomeKara2 has not a UTF-8 codepage, but some Chinese one. I decided to try the good 'ol Microsoft applocale program that changes codepages. This worked amazingly! Until the program crashed randomly and inexplicably at different times. Another problem was that the program uses an external MDB (Microsoft Access Database) file to keep track of the tables of artists, songs, etc, which is not readily editable or even viewable on Linux without extra tools. Last but not least, I had to figure out how to get multiple monitors set up within the virtual machine.

My solutions are out of order of how they happened, but in the order as previously mentioned

The applocale program is apparently quite unstable, and all I had to do to get HomeKara2 to run correctly without it, was to set the default codepage for non-utf8 codepage applications in Control Panel's regional language settings somewhere. This required a quick vm reboot, which was fine.

For the MDB issue, I sought out some freeware editors, which are in general wonderful, but realized that the Windows version of OpenOffice can connect to an MDB file and modify existing tables. A bit fat of a solution to install OpenOffice, but I can't doubt the ease of it.

The multiple monitors issue was a bit tough, but some googling around eventually brought up the right combination of answers. First, shut down the VM if it's running, and start up a terminal.

Note: replace VMNAME with the name for your VM

1. Use the VirtualBox GUI to enable VRDP (remote desktop) and change the port, in case Windows doesn't like you using its default RDP port, and take note of the port.

2. `VBoxManage modifyvm VMNAME -monitorcount 2` will set the number of monitors on the machine to 2.

3. `VBoxManage modifyvm VMNAME -vrdpmulticon on` will allow for multiple connections to the same RDP port. This allows you to connect twice, once for each monitor.

4. Start up your VM as normal, right-click the background wallpaper, click properties, goto settings tab, and select decent sizes for each of your monitors, checking the box for "extend my Windows desktop into this monitor" and apply.

5. Shut down your VM.

6. `VBoxHeadless -s VMNAME` will start your VM in a headless mode (like a daemon) which will listen on the port you specified for RDP connections.

7. Use an RDP program (I use KRDC on KDE), and set up an RDP connection to 'localhost' at your port, i.e. 'localhost:port'. When KRDC asks for extra options, put in '-d @1' and this will connect you to monitor 1 of the VM. Adjust resolution as necessary.

8. Repeat step 7, but change '-d @1' to '-d @2' to connect to the second monitor.

9. KRDC allows you to full-screen each desktop. In my setup, I use nvidia-settings to set up twinview, then put a KRDC instance on each desktop, and fullscreen.

10. Run HomeKara2, and behold the beauty of success.

Notes: be careful with sound forwarding on KRDC, as it might cause an echo. You can just choose to keep sound on "remote only" to fix this.

-- Interesting little other hack --

My friend gave me his music videos by putting them on my iPod, along with the program. I don't have much room left on my laptop's hard drive, so I did something somewhat hackish which actually worked.

1. I mounted the iPod with this long command:

`mount -t vfat -o rw,nosuid,nodev,uhelper=hal,shortname=mixed,uid=1000,utf8 /dev/sdb1 /media/ALEX_IPOD`

The real trick here was the shortname=mixed, which makes sure capitalization is done correctly, and the _long_ vfat names are used. Weird stuff can happen with the default mode on Kubuntu's mounter.

Beforehand, I had set /media/ALEX_IPOD as a shared folder for VirtualBox, so to keep consistency I mounted there again. I then changed the cdrom's drive letter to not D: and assigned D: to a particular folder on the iPod, so that the path lined up perfectly with the path listed in the MDB file for the videos. This worked quite well, so I was able to get away with not modifying the MDB file's path for videos, and with reading all videos directly off the iPod.

-- end hack --

So what did this all look like in the end?



Well OK, later on I fixed the resolutions so that each Windows "monitor" would take up my entire monitor, for both monitors, but this is my setup with my laptop screen and a classic CRT. Not bad for a day's work I'd say, and now I can set up haphazard karaoke when hanging out with friends and there's no place nearby. Nice!