(svn r10444) -Codechange: switch to c++ classes and inheritance for sound/music/video drivers, using self-registration based on the blitter-model.
authorpeter1138
Thu, 05 Jul 2007 12:23:54 +0000
changeset 7170 923946ec324f
parent 7169 314b046af3a1
child 7171 83e6861c8fe9
(svn r10444) -Codechange: switch to c++ classes and inheritance for sound/music/video drivers, using self-registration based on the blitter-model.
projects/openttd.vcproj
projects/openttd_vs80.vcproj
source.list
src/blitter/32bpp_anim.cpp
src/driver.cpp
src/driver.h
src/gfx.cpp
src/hal.h
src/music/bemidi.cpp
src/music/bemidi.h
src/music/dmusic.cpp
src/music/dmusic.h
src/music/extmidi.cpp
src/music/extmidi.h
src/music/libtimidity.cpp
src/music/libtimidity.h
src/music/music_driver.hpp
src/music/null_m.cpp
src/music/null_m.h
src/music/os2_m.cpp
src/music/os2_m.h
src/music/qtmidi.cpp
src/music/qtmidi.h
src/music/win32_m.cpp
src/music/win32_m.h
src/music_gui.cpp
src/openttd.cpp
src/sound/cocoa_s.cpp
src/sound/cocoa_s.h
src/sound/null_s.cpp
src/sound/null_s.h
src/sound/sdl_s.cpp
src/sound/sdl_s.h
src/sound/sound_driver.hpp
src/sound/win32_s.cpp
src/sound/win32_s.h
src/texteff.cpp
src/video/cocoa_v.h
src/video/cocoa_v.mm
src/video/dedicated_v.cpp
src/video/dedicated_v.h
src/video/null_v.cpp
src/video/null_v.h
src/video/sdl_v.cpp
src/video/sdl_v.h
src/video/video_driver.hpp
src/video/win32_v.cpp
src/video/win32_v.h
--- a/projects/openttd.vcproj	Thu Jul 05 06:35:09 2007 +0000
+++ b/projects/openttd.vcproj	Thu Jul 05 12:23:54 2007 +0000
@@ -471,9 +471,6 @@
 				RelativePath=".\..\src\gui.h">
 			</File>
 			<File
-				RelativePath=".\..\src\hal.h">
-			</File>
-			<File
 				RelativePath=".\..\src\heightmap.h">
 			</File>
 			<File
@@ -1038,6 +1035,19 @@
 			</File>
 		</Filter>
 		<Filter
+			Name="Drivers"
+			Filter="">
+			<File
+				RelativePath=".\..\src\music\music_driver.hpp">
+			</File>
+			<File
+				RelativePath=".\..\src\sound\sound_driver.hpp">
+			</File>
+			<File
+				RelativePath=".\..\src\video\video_driver.hpp">
+			</File>
+		</Filter>
+		<Filter
 			Name="Sprite loaders"
 			Filter="">
 			<File
--- a/projects/openttd_vs80.vcproj	Thu Jul 05 06:35:09 2007 +0000
+++ b/projects/openttd_vs80.vcproj	Thu Jul 05 12:23:54 2007 +0000
@@ -856,10 +856,6 @@
 				>
 			</File>
 			<File
-				RelativePath=".\..\src\hal.h"
-				>
-			</File>
-			<File
 				RelativePath=".\..\src\heightmap.h"
 				>
 			</File>
@@ -1605,6 +1601,22 @@
 			</File>
 		</Filter>
 		<Filter
+			Name="Drivers"
+			>
+			<File
+				RelativePath=".\..\src\music\music_driver.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\sound\sound_driver.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\video\video_driver.hpp"
+				>
+			</File>
+		</Filter>
+		<Filter
 			Name="Sprite loaders"
 			>
 			<File
--- a/source.list	Thu Jul 05 06:35:09 2007 +0000
+++ b/source.list	Thu Jul 05 12:23:54 2007 +0000
@@ -124,7 +124,6 @@
 gfxinit.h
 group.h
 gui.h
-hal.h
 heightmap.h
 helpers.hpp
 industry.h
@@ -317,6 +316,11 @@
 blitter/null.cpp
 blitter/null.hpp
 
+# Drivers
+music/music_driver.hpp
+sound/sound_driver.hpp
+video/video_driver.hpp
+
 # Sprite loaders
 spriteloader/grf.cpp
 spriteloader/grf.hpp
--- a/src/blitter/32bpp_anim.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/blitter/32bpp_anim.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -2,8 +2,8 @@
 #include "../zoom.hpp"
 #include "../gfx.h"
 #include "../debug.h"
-#include "../hal.h"
 #include "../table/sprites.h"
+#include "../video/video_driver.hpp"
 #include "32bpp_anim.hpp"
 
 static FBlitter_32bppAnim iFBlitter_32bppAnim;
@@ -269,7 +269,7 @@
 	}
 
 	/* Make sure the backend redraws the whole screen */
-	_video_driver->make_dirty(0, 0, _screen.width, _screen.height);
+	_video_driver->MakeDirty(0, 0, _screen.width, _screen.height);
 }
 
 Blitter::PaletteAnimation Blitter_32bppAnim::UsePaletteAnimation()
--- a/src/driver.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/driver.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -7,177 +7,15 @@
 #include "debug.h"
 #include "driver.h"
 #include "functions.h"
-#include "hal.h"
 #include "string.h"
 
-#include "music/bemidi.h"
-#include "music/dmusic.h"
-#include "music/extmidi.h"
-#include "music/null_m.h"
-#include "music/os2_m.h"
-#include "music/win32_m.h"
-#include "music/qtmidi.h"
-#include "music/libtimidity.h"
-
-#include "sound/null_s.h"
-#include "sound/sdl_s.h"
-#include "sound/cocoa_s.h"
-#include "sound/win32_s.h"
-
-#include "video/dedicated_v.h"
-#include "video/null_v.h"
-#include "video/sdl_v.h"
-#include "video/cocoa_v.h"
-#include "video/win32_v.h"
-
-struct DriverDesc {
-	const char* name;
-	const char* longname;
-	const HalCommonDriver* drv;
-};
-
-struct DriverClass {
-	const DriverDesc *descs;
-	const char *name;
-	const HalCommonDriver** drv;
-};
-
-
-#define M(x, y, z) { x, y, (const HalCommonDriver *)(void *)z }
-static const DriverDesc _music_driver_descs[] = {
-#ifdef __BEOS__
-	M("bemidi",  "BeOS MIDI Driver",        &_bemidi_music_driver),
-#endif
-#if defined(__OS2__) && !defined(__INNOTEK_LIBC__)
-	M("os2",     "OS/2 Music Driver",       &_os2_music_driver),
-#endif
-#ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT
-	M("dmusic",  "DirectMusic MIDI Driver", &_dmusic_midi_driver),
-#endif
-#if defined(WIN32) && !defined(WINCE)
-	M("win32",   "Win32 MIDI Driver",       &_win32_music_driver),
-#endif
-#if defined(__APPLE__) && !defined(DEDICATED)
-	M("qt",      "QuickTime MIDI Driver",   &_qtime_music_driver),
-#endif
-#ifdef UNIX
-#if defined(LIBTIMIDITY)
-	M("libtimidity", "LibTimidity MIDI Driver", &_libtimidity_music_driver),
-#endif /* LIBTIMIDITY */
-#if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(__OS2__) && !defined(PSP)
-	M("extmidi", "External MIDI Driver",    &_extmidi_music_driver),
-#endif
-#endif
-	M("null",    "Null Music Driver",       &_null_music_driver),
-	M(NULL, NULL, NULL)
-};
-
-static const DriverDesc _sound_driver_descs[] = {
-#if defined(WIN32) && !defined(WINCE)
-	M("win32", "Win32 WaveOut Driver", &_win32_sound_driver),
-#endif
-#ifdef WITH_SDL
-	M("sdl",   "SDL Sound Driver",     &_sdl_sound_driver),
-#endif
-#ifdef WITH_COCOA
-	M("cocoa", "Cocoa Sound Driver",   &_cocoa_sound_driver),
-#endif
-	M("null",  "Null Sound Driver",    &_null_sound_driver),
-	M(NULL, NULL, NULL)
-};
+#include "sound/sound_driver.hpp"
+#include "music/music_driver.hpp"
+#include "video/video_driver.hpp"
 
-static const DriverDesc _video_driver_descs[] = {
-#ifdef WIN32
-	M("win32",      "Win32 GDI Video Driver", &_win32_video_driver),
-#endif
-#ifdef WITH_SDL
-	M("sdl",        "SDL Video Driver",       &_sdl_video_driver),
-#endif
-#ifdef WITH_COCOA
-	M("cocoa",      "Cocoa Video Driver",       &_cocoa_video_driver),
-#endif
-	M("null",       "Null Video Driver",      &_null_video_driver),
-#ifdef ENABLE_NETWORK
-	M("dedicated",  "Dedicated Video Driver", &_dedicated_video_driver),
-#endif
-	M(NULL, NULL, NULL)
-};
-#undef M
-
-
-#define M(x, y, z) { x, y, (const HalCommonDriver **)(void *)z }
-static const DriverClass _driver_classes[] = {
-	M(_video_driver_descs, "video", &_video_driver),
-	M(_sound_driver_descs, "sound", &_sound_driver),
-	M(_music_driver_descs, "music", &_music_driver)
-};
-#undef M
-
-static const DriverDesc* GetDriverByName(const DriverDesc* dd, const char* name)
-{
-	for (; dd->name != NULL; dd++) {
-		if (strcmp(dd->name, name) == 0) return dd;
-	}
-	return NULL;
-}
-
-void LoadDriver(int driver, const char *name)
-{
-	const DriverClass *dc = &_driver_classes[driver];
-	const DriverDesc *dd;
-	const char *err;
-
-	if (*name == '\0') {
-		for (dd = dc->descs; dd->name != NULL; dd++) {
-			err = dd->drv->start(NULL);
-			if (err == NULL) break;
-			DEBUG(driver, 1, "Probing %s driver '%s' failed with error: %s",
-				dc->name, dd->name, err
-			);
-		}
-		if (dd->name == NULL) error("Couldn't find any suitable %s driver", dc->name);
-
-		DEBUG(driver, 1, "Successfully probed %s driver '%s'", dc->name, dd->name);
-
-		*dc->drv = dd->drv;
-	} else {
-		char* parm;
-		char buffer[256];
-		const char* parms[32];
-
-		/* Extract the driver name and put parameter list in parm */
-		ttd_strlcpy(buffer, name, sizeof(buffer));
-		parm = strchr(buffer, ':');
-		parms[0] = NULL;
-		if (parm != NULL) {
-			uint np = 0;
-			/* Tokenize the parm. */
-			do {
-				*parm++ = '\0';
-				if (np < lengthof(parms) - 1)
-					parms[np++] = parm;
-				while (*parm != '\0' && *parm != ',')
-					parm++;
-			} while (*parm == ',');
-			parms[np] = NULL;
-		}
-		dd = GetDriverByName(dc->descs, buffer);
-		if (dd == NULL)
-			error("No such %s driver: %s\n", dc->name, buffer);
-
-		if (*dc->drv != NULL) (*dc->drv)->stop();
-		*dc->drv = NULL;
-
-		err = dd->drv->start(parms);
-		if (err != NULL) {
-			error("Unable to load driver %s(%s). The error was: %s\n",
-				dd->name, dd->longname, err
-			);
-		}
-		*dc->drv = dd->drv;
-	}
-}
-
+SoundDriver *_sound_driver;
+MusicDriver *_music_driver;
+VideoDriver *_video_driver;
 
 static const char* GetDriverParam(const char* const* parm, const char* name)
 {
@@ -207,21 +45,3 @@
 	const char* p = GetDriverParam(parm, name);
 	return p != NULL ? atoi(p) : def;
 }
-
-
-char *GetDriverList(char* p, const char *last)
-{
-	const DriverClass* dc;
-
-	for (dc = _driver_classes; dc != endof(_driver_classes); dc++) {
-		const DriverDesc* dd;
-
-		p += snprintf(p, last - p, "List of %s drivers:\n", dc->name);
-		for (dd = dc->descs; dd->name != NULL; dd++) {
-			p += snprintf(p, last - p, "%10s: %s\n", dd->name, dd->longname);
-		}
-		p = strecpy(p, "\n", last);
-	}
-
-	return p;
-}
--- a/src/driver.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/driver.h	Thu Jul 05 12:23:54 2007 +0000
@@ -5,11 +5,207 @@
 #ifndef DRIVER_H
 #define DRIVER_H
 
-void LoadDriver(int driver, const char *name);
+#include "debug.h"
+#include "helpers.hpp"
+#include "string.h"
+#include <string>
+#include <map>
 
 bool GetDriverParamBool(const char* const* parm, const char* name);
 int GetDriverParamInt(const char* const* parm, const char* name, int def);
 
-char *GetDriverList(char *p, const char *last);
+class Driver {
+public:
+	virtual bool CanProbe() = 0;
+
+	virtual const char *Start(const char * const *parm) = 0;
+
+	virtual void Stop() = 0;
+
+	virtual ~Driver() { }
+
+	enum Type {
+		DT_BEGIN = 0,
+		DT_SOUND = 0,
+		DT_MUSIC,
+		DT_VIDEO,
+		DT_END,
+	};
+};
+
+DECLARE_POSTFIX_INCREMENT(Driver::Type);
+
+
+class DriverFactoryBase {
+private:
+	Driver::Type type;
+	char *name;
+	typedef std::map<std::string, DriverFactoryBase *> Drivers;
+
+	static Drivers &GetDrivers()
+	{
+		static Drivers &s_drivers = *new Drivers();
+		return s_drivers;
+	}
+
+	static Driver **GetActiveDriver(Driver::Type type)
+	{
+		static Driver *s_driver[3] = { NULL, NULL, NULL };
+		return &s_driver[type];
+	}
+
+	static const char *GetDriverTypeName(Driver::Type type)
+	{
+		static const char *driver_type_name[] = { "sound", "music", "video" };
+		return driver_type_name[type];
+	}
+
+protected:
+	/**
+	 * Register a driver internally, based on its name.
+	 * @param name the name of the driver.
+	 * @note an assert() will be trigger if 2 driver with the same name try to register.
+	 */
+	void RegisterDriver(const char *name, Driver::Type type)
+	{
+		/* Don't register nameless Drivers */
+		if (name == NULL) return;
+
+		this->name = strdup(name);
+		this->type = type;
+
+		/* Prefix the name with driver type to make it unique */
+		char buf[32];
+		strecpy(buf, GetDriverTypeName(type), lastof(buf));
+		strecpy(buf + 5, name, lastof(buf));
+
+		std::pair<Drivers::iterator, bool> P = GetDrivers().insert(Drivers::value_type(buf, this));
+		assert(P.second);
+	}
+
+public:
+	DriverFactoryBase() :
+		name(NULL)
+	{}
+
+	virtual ~DriverFactoryBase() { if (this->name != NULL) GetDrivers().erase(this->name); free(this->name); }
+
+	/**
+	 * Find the requested driver and return its class.
+	 * @param name the driver to select.
+	 * @post Sets the driver so GetCurrentDriver() returns it too.
+	 */
+	static Driver *SelectDriver(const char *name, Driver::Type type)
+	{
+		if (GetDrivers().size() == 0) return NULL;
+
+		if (*name == '\0') {
+			/* Probe for this driver */
+			Drivers::iterator it = GetDrivers().begin();
+			for (; it != GetDrivers().end(); ++it) {
+				DriverFactoryBase *d = (*it).second;
+
+				/* Check driver type */
+				if (d->type != type) continue;
+
+				Driver *newd = d->CreateInstance();
+				if (!newd->CanProbe()) {
+					DEBUG(driver, 1, "Skipping probe of driver '%s'", d->name);
+				} else {
+					const char *err = newd->Start(NULL);
+					if (err == NULL) {
+						DEBUG(driver, 1, "Successfully probed %s driver '%s'", GetDriverTypeName(type), d->name);
+						delete *GetActiveDriver(type);
+						*GetActiveDriver(type) = newd;
+						return newd;
+					}
+
+					DEBUG(driver, 1, "Probing %s driver '%s' failed with error: %s", GetDriverTypeName(type), d->name, err);
+				}
+
+				delete newd;
+			}
+			error("Couldn't find any suitable %s driver", GetDriverTypeName(type));
+		} else {
+			char *parm;
+			char buffer[256];
+			const char *parms[32];
+
+			/* Extract the driver name and put parameter list in parm */
+			strecpy(buffer, name, lastof(buffer));
+			parm = strchr(buffer, ':');
+			parms[0] = NULL;
+			if (parm != NULL) {
+				uint np = 0;
+				/* Tokenize the parm. */
+				do {
+					*parm++ = '\0';
+					if (np < lengthof(parms) - 1)
+						parms[np++] = parm;
+					while (*parm != '\0' && *parm != ',')
+						parm++;
+				} while (*parm == ',');
+				parms[np] = NULL;
+			}
+
+			/* Find this driver */
+			Drivers::iterator it = GetDrivers().begin();
+			for (; it != GetDrivers().end(); ++it) {
+				DriverFactoryBase *d = (*it).second;
+
+				/* Check driver type */
+				if (d->type != type) continue;
+
+				/* Check driver name */
+				if (strcasecmp(buffer, d->name) != 0) continue;
+
+				/* Found our driver, let's try it */
+				Driver *newd = d->CreateInstance();
+
+				const char *err = newd->Start(parms);
+				if (err != NULL) {
+					delete newd;
+					error("Unable to load driver '%s'. The error was: %s", d->name, err);
+				}
+
+				DEBUG(driver, 1, "Successfully loaded %s driver '%s'", GetDriverTypeName(type), d->name);
+				delete *GetActiveDriver(type);
+				*GetActiveDriver(type) = newd;
+				return newd;
+			}
+			error("No such %s driver: %s\n", GetDriverTypeName(type), buffer);
+		}
+	}
+
+	/**
+	 * Build a human readable list of available drivers, grouped by type.
+	 */
+	static char *GetDriversInfo(char *p, const char *last)
+	{
+		for (Driver::Type type = Driver::DT_BEGIN; type != Driver::DT_END; type++) {
+			p += snprintf(p, last - p, "List of %s drivers:\n", GetDriverTypeName(type));
+
+			Drivers::iterator it = GetDrivers().begin();
+			for (; it != GetDrivers().end(); it++) {
+				DriverFactoryBase *d = (*it).second;
+				if (d->type == type) p += snprintf(p, last - p, "%18s: %s\n", d->name, d->GetDescription());
+			}
+
+			p += snprintf(p, last - p, "\n");
+		}
+
+		return p;
+	}
+
+	/**
+	 * Get a nice description of the driver-class.
+	 */
+	virtual const char *GetDescription() = 0;
+
+	/**
+	 * Create an instance of this driver-class.
+	 */
+	virtual Driver *CreateInstance() = 0;
+};
 
 #endif /* DRIVER_H */
--- a/src/gfx.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/gfx.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -12,7 +12,6 @@
 #include "gfx.h"
 #include "table/palettes.h"
 #include "table/sprites.h"
-#include "hal.h"
 #include "variables.h"
 #include "table/control_codes.h"
 #include "fontcache.h"
@@ -21,6 +20,7 @@
 #include "zoom.hpp"
 #include "texteff.hpp"
 #include "blitter/factory.hpp"
+#include "video/video_driver.hpp"
 
 byte _dirkeys;        ///< 1 = left, 2 = up, 4 = right, 8 = down
 bool _fullscreen;
@@ -66,7 +66,7 @@
 
 	blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo);
 	/* This part of the screen is now dirty. */
-	_video_driver->make_dirty(left, top, width, height);
+	_video_driver->MakeDirty(left, top, width, height);
 }
 
 
@@ -834,7 +834,7 @@
 		Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
 		_cursor.visible = false;
 		blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, _cursor.draw_pos.x, _cursor.draw_pos.y), _cursor_backup, _cursor.draw_size.x, _cursor.draw_size.y);
-		_video_driver->make_dirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y);
+		_video_driver->MakeDirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y);
 	}
 }
 
@@ -886,7 +886,7 @@
 	_cur_dpi = &_screen;
 	DrawSprite(_cursor.sprite, _cursor.pal, _cursor.pos.x, _cursor.pos.y);
 
-	_video_driver->make_dirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y);
+	_video_driver->MakeDirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y);
 
 	_cursor.visible = true;
 	_cursor.dirty = false;
@@ -907,7 +907,7 @@
 
 	DrawOverlappedWindowForAll(left, top, right, bottom);
 
-	_video_driver->make_dirty(left, top, right - left, bottom - top);
+	_video_driver->MakeDirty(left, top, right - left, bottom - top);
 }
 
 void DrawDirtyBlocks()
@@ -1151,12 +1151,12 @@
 {
 	return
 		(_screen.width == w && _screen.height == h) ||
-		_video_driver->change_resolution(w, h);
+		_video_driver->ChangeResolution(w, h);
 }
 
 void ToggleFullScreen(bool fs)
 {
-	_video_driver->toggle_fullscreen(fs);
+	_video_driver->ToggleFullscreen(fs);
 	if (_fullscreen != fs && _num_resolutions == 0) {
 		DEBUG(driver, 0, "Could not find a suitable fullscreen resolution");
 	}
--- a/src/hal.h	Thu Jul 05 06:35:09 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/* $Id$ */
-
-/** @file hal.h Hardware Abstraction Layer declarations */
-
-#ifndef HAL_H
-#define HAL_H
-
-struct HalCommonDriver {
-	const char *(*start)(const char * const *parm);
-	void (*stop)();
-};
-
-struct HalVideoDriver {
-	const char *(*start)(const char * const *parm);
-	void (*stop)();
-	void (*make_dirty)(int left, int top, int width, int height);
-	void (*main_loop)();
-	bool (*change_resolution)(int w, int h);
-	void (*toggle_fullscreen)(bool fullscreen);
-};
-
-struct HalSoundDriver {
-	const char *(*start)(const char * const *parm);
-	void (*stop)();
-};
-
-struct HalMusicDriver {
-	const char *(*start)(const char * const *parm);
-	void (*stop)();
-
-	void (*play_song)(const char *filename);
-	void (*stop_song)();
-	bool (*is_song_playing)();
-	void (*set_volume)(byte vol);
-};
-
-extern HalMusicDriver *_music_driver;
-extern HalSoundDriver *_sound_driver;
-extern HalVideoDriver *_video_driver;
-
-enum DriverType {
-	VIDEO_DRIVER = 0,
-	SOUND_DRIVER = 1,
-	MUSIC_DRIVER = 2,
-};
-
-#endif /* HAL_H */
--- a/src/music/bemidi.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/bemidi.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -11,17 +11,19 @@
 
 static BMidiSynthFile midiSynthFile;
 
-static const char *bemidi_start(const char * const *parm)
+static FMusicDriver_BeMidi iFMusicDriver_BeMidi;
+
+const char *MusicDriver_BeMidi::Start(const char * const *parm)
 {
 	return NULL;
 }
 
-static void bemidi_stop()
+void MusicDriver_BeMidi::Stop()
 {
 	midiSynthFile.UnloadFile();
 }
 
-static void bemidi_play_song(const char *filename)
+void MusicDriver_BeMidi::PlaySong(const char *filename)
 {
 	bemidi_stop();
 	entry_ref midiRef;
@@ -30,26 +32,17 @@
 	midiSynthFile.Start();
 }
 
-static void bemidi_stop_song()
+void MusicDriver_BeMidi::StopSong()
 {
 	midiSynthFile.UnloadFile();
 }
 
-static bool bemidi_is_playing()
+bool MusicDriver_BeMidi::IsSongPlaying()
 {
 	return !midiSynthFile.IsFinished();
 }
 
-static void bemidi_set_volume(byte vol)
+void MusicDriver_BeMidi::SetVolume(byte vol)
 {
 	fprintf(stderr, "BeMidi: Set volume not implemented\n");
 }
-
-const HalMusicDriver _bemidi_music_driver = {
-	bemidi_start,
-	bemidi_stop,
-	bemidi_play_song,
-	bemidi_stop_song,
-	bemidi_is_playing,
-	bemidi_set_volume,
-};
--- a/src/music/bemidi.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/bemidi.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef MUSIC_BEMIDI_H
 #define MUSIC_BEMIDI_H
 
-#include "../hal.h"
+#include "music_driver.hpp"
 
-extern const HalMusicDriver _bemidi_music_driver;
+class MusicDriver_BeMidi: public MusicDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void PlaySong(const char *filename);
+
+	/* virtual */ void StopSong();
+
+	/* virtual */ bool IsSongPlaying();
+
+	/* virtual */ void SetVolume(byte vol);
+};
+
+class FMusicDriver_BeMidi: public MusicDriverFactory<FMusicDriver_BeMidi> {
+public:
+	/* virtual */ const char *GetName() { return "bemidi"; }
+	/* virtual */ const char *GetDescription() { return "BeOS MIDI Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new MusicDriver_BeMidi(); }
+};
 
 #endif /* MUSIC_BEMIDI_H */
--- a/src/music/dmusic.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/dmusic.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -47,7 +47,7 @@
 static ProcPtrs proc;
 
 
-static const char* DMusicMidiStart(const char* const* parm)
+const char *MusicDriver_DMusic::Start(const char * const *parm)
 {
 	if (performance != NULL) return NULL;
 
@@ -109,7 +109,7 @@
 }
 
 
-static void DMusicMidiStop()
+void MusicDriver_DMusic::Stop()
 {
 	seeking = false;
 
@@ -136,7 +136,7 @@
 }
 
 
-static void DMusicMidiPlaySong(const char* filename)
+void MusicDriver_DMusic::PlaySong(const char* filename)
 {
 	/* set up the loader object info */
 	DMUS_OBJECTDESC obj_desc;
@@ -188,7 +188,7 @@
 }
 
 
-static void DMusicMidiStopSong()
+void MusicDriver_DMusic::StopSong()
 {
 	if (FAILED(performance->Stop(segment, NULL, 0, 0))) {
 		DEBUG(driver, 0, "DirectMusic: StopSegment failed");
@@ -197,7 +197,7 @@
 }
 
 
-static bool DMusicMidiIsSongPlaying()
+bool MusicDriver_DMusic::IsSongPlaying()
 {
 	/* Not the nicest code, but there is a short delay before playing actually
 	 * starts. OpenTTD makes no provision for this. */
@@ -210,20 +210,11 @@
 }
 
 
-static void DMusicMidiSetVolume(byte vol)
+void MusicDriver_DMusic::SetVolume(byte vol)
 {
 	long db = vol * 2000 / 127 - 2000; ///< 0 - 127 -> -2000 - 0
 	performance->SetGlobalParam(GUID_PerfMasterVolume, &db, sizeof(db));
 }
 
 
-const HalMusicDriver _dmusic_midi_driver = {
-	DMusicMidiStart,
-	DMusicMidiStop,
-	DMusicMidiPlaySong,
-	DMusicMidiStopSong,
-	DMusicMidiIsSongPlaying,
-	DMusicMidiSetVolume,
-};
-
 #endif /* WIN32_ENABLE_DIRECTMUSIC_SUPPORT */
--- a/src/music/dmusic.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/dmusic.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef MUSIC_DMUSIC_H
 #define MUSIC_DMUSIC_H
 
-#include "../hal.h"
+#include "music_driver.hpp"
 
-extern const HalMusicDriver _dmusic_midi_driver;
+class MusicDriver_DMusic: public MusicDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void PlaySong(const char *filename);
+
+	/* virtual */ void StopSong();
+
+	/* virtual */ bool IsSongPlaying();
+
+	/* virtual */ void SetVolume(byte vol);
+};
+
+class FMusicDriver_DMusic: public MusicDriverFactory<FMusicDriver_DMusic> {
+public:
+	/* virtual */ const char *GetName() { return "dmusic"; }
+	/* virtual */ const char *GetDescription() { return "DirectMusic MIDI Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new MusicDriver_DMusic(); }
+};
 
 #endif /* MUSIC_DMUSIC_H */
--- a/src/music/extmidi.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/extmidi.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -24,32 +24,34 @@
 static void DoPlay();
 static void DoStop();
 
-static const char* ExtMidiStart(const char* const * parm)
+static FMusicDriver_ExtMidi iFMusicDriver_ExtMidi;
+
+const char* MusicDriver_ExtMidi::Start(const char* const * parm)
 {
 	_midi.song[0] = '\0';
 	_midi.pid = -1;
 	return NULL;
 }
 
-static void ExtMidiStop()
+void MusicDriver_ExtMidi::Stop()
 {
 	_midi.song[0] = '\0';
 	DoStop();
 }
 
-static void ExtMidiPlaySong(const char* filename)
+void MusicDriver_ExtMidi::PlaySong(const char* filename)
 {
 	ttd_strlcpy(_midi.song, filename, lengthof(_midi.song));
 	DoStop();
 }
 
-static void ExtMidiStopSong()
+void MusicDriver_ExtMidi::StopSong()
 {
 	_midi.song[0] = '\0';
 	DoStop();
 }
 
-static bool ExtMidiIsPlaying()
+bool MusicDriver_ExtMidi::IsSongPlaying()
 {
 	if (_midi.pid != -1 && waitpid(_midi.pid, NULL, WNOHANG) == _midi.pid)
 		_midi.pid = -1;
@@ -57,7 +59,7 @@
 	return _midi.pid != -1;
 }
 
-static void ExtMidiSetVolume(byte vol)
+void MusicDriver_ExtMidi::SetVolume(byte vol)
 {
 	DEBUG(driver, 1, "extmidi: set volume not implemented");
 }
@@ -96,13 +98,4 @@
 	if (_midi.pid != -1) kill(_midi.pid, SIGTERM);
 }
 
-const HalMusicDriver _extmidi_music_driver = {
-	ExtMidiStart,
-	ExtMidiStop,
-	ExtMidiPlaySong,
-	ExtMidiStopSong,
-	ExtMidiIsPlaying,
-	ExtMidiSetVolume,
-};
-
 #endif /* __MORPHOS__ */
--- a/src/music/extmidi.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/extmidi.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef MUSIC_EXTERNAL_H
 #define MUSIC_EXTERNAL_H
 
-#include "../hal.h"
+#include "music_driver.hpp"
 
-extern const HalMusicDriver _extmidi_music_driver;
+class MusicDriver_ExtMidi: public MusicDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void PlaySong(const char *filename);
+
+	/* virtual */ void StopSong();
+
+	/* virtual */ bool IsSongPlaying();
+
+	/* virtual */ void SetVolume(byte vol);
+};
+
+class FMusicDriver_ExtMidi: public MusicDriverFactory<FMusicDriver_ExtMidi> {
+public:
+	/* virtual */ const char *GetName() { return "extmidi"; }
+	/* virtual */ const char *GetDescription() { return "External MIDI Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new MusicDriver_ExtMidi(); }
+};
 
 #endif /* MUSIC_EXTERNAL_H */
--- a/src/music/libtimidity.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/libtimidity.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -44,7 +44,9 @@
 }
 #endif /* PSP */
 
-static const char *LibtimidityMidiStart(const char *const *param)
+static FMusicDriver_LibTimidity iFMusicDriver_LibTimidity;
+
+const char *MusicDriver_LibTimidity::Start(const char *const *param)
 {
 	_midi.status = MIDI_STOPPED;
 
@@ -53,8 +55,7 @@
 		 *  If it was not forced via param, try to load it without a
 		 *  configuration. Who knows that works. */
 		if (param != NULL || mid_init_no_config() < 0) {
-			DEBUG(driver, 0, "error initializing timidity");
-			return NULL;
+			return "error initializing timidity";
 		}
 	}
 	DEBUG(driver, 1, "successfully initialised timidity");
@@ -77,7 +78,7 @@
 	return NULL;
 }
 
-static void LibtimidityMidiStop()
+void MusicDriver_LibTimidity::Stop()
 {
 	if (_midi.status == MIDI_PLAYING) {
 		_midi.status = MIDI_STOPPED;
@@ -86,7 +87,7 @@
 	mid_exit();
 }
 
-static void LibtimidityMidiPlaySong(const char *filename)
+void MusicDriver_LibTimidity::PlaySong(const char *filename)
 {
 	_midi.stream = mid_istream_open_file(filename);
 	if (_midi.stream == NULL) {
@@ -107,13 +108,13 @@
 	_midi.status = MIDI_PLAYING;
 }
 
-static void LibtimidityMidiStopSong()
+void MusicDriver_LibTimidity::StopSong()
 {
 	_midi.status = MIDI_STOPPED;
 	mid_song_free(_midi.song);
 }
 
-static bool LibtimidityMidiIsPlaying()
+bool MusicDriver_LibTimidity::IsSongPlaying()
 {
 	if (_midi.status == MIDI_PLAYING) {
 		_midi.song_position = mid_song_get_time(_midi.song);
@@ -126,18 +127,8 @@
 	return (_midi.status == MIDI_PLAYING);
 }
 
-static void LibtimidityMidiSetVolume(byte vol)
+void MusicDriver_LibTimidity::SetVolume(byte vol)
 {
 	if (_midi.song != NULL)
 		mid_song_set_volume(_midi.song, vol);
 }
-
-const HalMusicDriver _libtimidity_music_driver = {
-	LibtimidityMidiStart,
-	LibtimidityMidiStop,
-	LibtimidityMidiPlaySong,
-	LibtimidityMidiStopSong,
-	LibtimidityMidiIsPlaying,
-	LibtimidityMidiSetVolume,
-};
-
--- a/src/music/libtimidity.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/libtimidity.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef MUSIC_LIBTIMIDITY_H
 #define MUSIC_LIBTIMIDITY_H
 
-#include "../hal.h"
+#include "music_driver.hpp"
 
-extern const HalMusicDriver _libtimidity_music_driver;
+class MusicDriver_LibTimidity: public MusicDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void PlaySong(const char *filename);
+
+	/* virtual */ void StopSong();
+
+	/* virtual */ bool IsSongPlaying();
+
+	/* virtual */ void SetVolume(byte vol);
+};
+
+class FMusicDriver_LibTimidity: public MusicDriverFactory<FMusicDriver_LibTimidity> {
+public:
+	/* virtual */ const char *GetName() { return "libtimidity"; }
+	/* virtual */ const char *GetDescription() { return "LibTimidity MIDI Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new MusicDriver_LibTimidity(); }
+};
 
 #endif /* MUSIC_LIBTIMIDITY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/music/music_driver.hpp	Thu Jul 05 12:23:54 2007 +0000
@@ -0,0 +1,35 @@
+/* $Id$ */
+
+#ifndef MUSIC_MUSIC_DRIVER_HPP
+#define MUSIC_MUSIC_DRIVER_HPP
+
+#include "../driver.h"
+
+class MusicDriver: public Driver {
+public:
+	virtual void PlaySong(const char *filename) = 0;
+
+	virtual void StopSong() = 0;
+
+	virtual bool IsSongPlaying() = 0;
+
+	virtual void SetVolume(byte vol) = 0;
+};
+
+class MusicDriverFactoryBase: public DriverFactoryBase {
+};
+
+template <class T>
+class MusicDriverFactory: public MusicDriverFactoryBase {
+public:
+	MusicDriverFactory() { this->RegisterDriver(((T *)this)->GetName(), Driver::DT_MUSIC); }
+
+	/**
+	 * Get the long, human readable, name for the Driver-class.
+	 */
+	const char *GetName();
+};
+
+extern MusicDriver *_music_driver;
+
+#endif /* MUSIC_MUSIC_DRIVER_HPP */
--- a/src/music/null_m.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/null_m.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -3,18 +3,5 @@
 #include "../stdafx.h"
 #include "null_m.h"
 
-static const char* NullMidiStart(const char* const* parm) { return NULL; }
-static void NullMidiStop() {}
-static void NullMidiPlaySong(const char *filename) {}
-static void NullMidiStopSong() {}
-static bool NullMidiIsSongPlaying() { return true; }
-static void NullMidiSetVolume(byte vol) {}
+static FMusicDriver_Null iFMusicDriver_Null;
 
-const HalMusicDriver _null_music_driver = {
-	NullMidiStart,
-	NullMidiStop,
-	NullMidiPlaySong,
-	NullMidiStopSong,
-	NullMidiIsSongPlaying,
-	NullMidiSetVolume,
-};
--- a/src/music/null_m.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/null_m.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef MUSIC_NULL_H
 #define MUSIC_NULL_H
 
-#include "../hal.h"
+#include "music_driver.hpp"
 
-extern const HalMusicDriver _null_music_driver;
+class MusicDriver_Null: public MusicDriver {
+public:
+	/* virtual */ bool CanProbe() { return false; }
+
+	/* virtual */ const char *Start(const char * const *param) { return NULL; }
+
+	/* virtual */ void Stop() { }
+
+	/* virtual */ void PlaySong(const char *filename) { }
+
+	/* virtual */ void StopSong() { }
+
+	/* virtual */ bool IsSongPlaying() { return true; }
+
+	/* virtual */ void SetVolume(byte vol) { }
+};
+
+class FMusicDriver_Null: public MusicDriverFactory<FMusicDriver_Null> {
+public:
+	/* virtual */ const char *GetName() { return "null"; }
+	/* virtual */ const char *GetDescription() { return "Null Music Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new MusicDriver_Null(); }
+};
 
 #endif /* MUSIC_NULL_H */
--- a/src/music/os2_m.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/os2_m.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -30,7 +30,9 @@
 	return mciSendString(buf, NULL, 0, NULL, 0);
 }
 
-static void OS2MidiPlaySong(const char *filename)
+static FMusicDriver_OS2 iFMusicDriver_OS2;
+
+void MusicDriver_OS2::PlaySong(const char *filename)
 {
 	MidiSendCommand("close all");
 
@@ -40,38 +42,29 @@
 	MidiSendCommand("play song from 0");
 }
 
-static void OS2MidiStopSong()
+void MusicDriver_OS2::StopSong()
 {
 	MidiSendCommand("close all");
 }
 
-static void OS2MidiSetVolume(byte vol)
+void MusicDriver_OS2::SetVolume(byte vol)
 {
 	MidiSendCommand("set song audio volume %d", ((vol/127)*100));
 }
 
-static bool OS2MidiIsSongPlaying()
+bool MusicDriver_OS2::IsSongPlaying()
 {
 	char buf[16];
 	mciSendString("status song mode", buf, sizeof(buf), NULL, 0);
 	return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
 }
 
-static const char *OS2MidiStart(const char * const *parm)
+const char *MusicDriver_OS2::Start(const char * const *parm)
 {
 	return 0;
 }
 
-static void OS2MidiStop()
+void MusicDriver_OS2::Stop()
 {
 	MidiSendCommand("close all");
 }
-
-const HalMusicDriver _os2_music_driver = {
-	OS2MidiStart,
-	OS2MidiStop,
-	OS2MidiPlaySong,
-	OS2MidiStopSong,
-	OS2MidiIsSongPlaying,
-	OS2MidiSetVolume,
-};
--- a/src/music/os2_m.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/os2_m.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef MUSIC_OS2_H
 #define MUSIC_OS2_H
 
-#include "../hal.h"
+#include "music_driver.hpp"
 
-extern const HalMusicDriver _os2_music_driver;
+class MusicDriver_OS2: public MusicDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void PlaySong(const char *filename);
+
+	/* virtual */ void StopSong();
+
+	/* virtual */ bool IsSongPlaying();
+
+	/* virtual */ void SetVolume(byte vol);
+};
+
+class FMusicDriver_OS2: public MusicDriverFactory<FMusicDriver_OS2> {
+public:
+	/* virtual */ const char *GetName() { return "os2"; }
+	/* virtual */ const char *GetDescription() { return "OS/2 Music Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new MusicDriver_OS2(); }
+};
 
 #endif /* MUSIC_OS2_H */
--- a/src/music/qtmidi.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/qtmidi.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -47,6 +47,8 @@
 // we need to include debug.h after CoreServices because defining DEBUG will break CoreServices in OSX 10.2
 #include "../debug.h"
 
+static FMusicDriver_QtMidi iFMusicDriver_QtMidi;
+
 
 enum {
 	midiType = 'Midi' /**< OSType code for MIDI songs. */
@@ -207,9 +209,6 @@
 #define VOLUME  ((short)((0x00FF & _quicktime_volume) << 1))
 
 
-static void StopSong();
-
-
 /**
  * Initialized the MIDI player, including QuickTime initialization.
  *
@@ -217,7 +216,7 @@
  * @c Gestalt() and @c EnterMovies(). Needs changes in
  * #InitQuickTimeIfNeeded.
  */
-static const char* StartDriver(const char * const *parm)
+const char *MusicDriver_QtMidi::Start(const char * const *parm)
 {
 	InitQuickTimeIfNeeded();
 	return (_quicktime_started) ? NULL : "can't initialize QuickTime";
@@ -230,7 +229,7 @@
  * This function is called at regular intervals from OpenTTD's main loop, so
  * we call @c MoviesTask() from here to let QuickTime do its work.
  */
-static bool SongIsPlaying()
+bool MusicDriver_QtMidi::IsSongPlaying()
 {
 	if (!_quicktime_started) return true;
 
@@ -258,7 +257,7 @@
  * Stops playing and frees any used resources before returning. As it
  * deinitilizes QuickTime, the #_quicktime_started flag is set to @c false.
  */
-static void StopDriver()
+void MusicDriver_QtMidi::Stop()
 {
 	if (!_quicktime_started) return;
 
@@ -284,7 +283,7 @@
  *
  * @param filename Path to a MIDI file.
  */
-static void PlaySong(const char *filename)
+void MusicDriver_QtMidi::PlaySong(const char *filename)
 {
 	if (!_quicktime_started) return;
 
@@ -312,7 +311,7 @@
 /**
  * Stops playing the current song, if the player is active.
  */
-static void StopSong()
+void MusicDriver_QtMidi::StopSong()
 {
 	if (!_quicktime_started) return;
 
@@ -340,7 +339,7 @@
  *
  * @param vol The desired volume, range of the value is @c 0-127
  */
-static void SetVolume(byte vol)
+void MusicDriver_QtMidi::SetVolume(byte vol)
 {
 	if (!_quicktime_started) return;
 
@@ -357,15 +356,3 @@
 	}
 }
 
-
-/**
- * Table of callbacks that implement the QuickTime MIDI player.
- */
-const HalMusicDriver _qtime_music_driver = {
-	StartDriver,
-	StopDriver,
-	PlaySong,
-	StopSong,
-	SongIsPlaying,
-	SetVolume,
-};
--- a/src/music/qtmidi.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/qtmidi.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef MUSIC_MACOSX_QUICKTIME_H
 #define MUSIC_MACOSX_QUICKTIME_H
 
-#include "../hal.h"
+#include "music_driver.hpp"
 
-extern const HalMusicDriver _qtime_music_driver;
+class MusicDriver_QtMidi: public MusicDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void PlaySong(const char *filename);
+
+	/* virtual */ void StopSong();
+
+	/* virtual */ bool IsSongPlaying();
+
+	/* virtual */ void SetVolume(byte vol);
+};
+
+class FMusicDriver_QtMidi: public MusicDriverFactory<FMusicDriver_QtMidi> {
+public:
+	/* virtual */ const char *GetName() { return "qt"; }
+	/* virtual */ const char *GetDescription() { return "QuickTime MIDI Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new MusicDriver_QtMidi(); }
+};
 
 #endif /* MUSIC_MACOSX_QUICKTIME_H */
--- a/src/music/win32_m.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/win32_m.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -15,7 +15,9 @@
 	char start_song[260];
 } _midi;
 
-static void Win32MidiPlaySong(const char *filename)
+static FMusicDriver_Win32 iFMusicDriver_Win32;
+
+void MusicDriver_Win32::PlaySong(const char *filename)
 {
 	strcpy(_midi.start_song, filename);
 	_midi.playing = true;
@@ -23,7 +25,7 @@
 	SetEvent(_midi.wait_obj);
 }
 
-static void Win32MidiStopSong()
+void MusicDriver_Win32::StopSong()
 {
 	if (_midi.playing) {
 		_midi.stop_song = true;
@@ -32,12 +34,12 @@
 	}
 }
 
-static bool Win32MidiIsSongPlaying()
+bool MusicDriver_Win32::IsSongPlaying()
 {
 	return _midi.playing;
 }
 
-static void Win32MidiSetVolume(byte vol)
+void MusicDriver_Win32::SetVolume(byte vol)
 {
 	_midi.new_vol = vol;
 	SetEvent(_midi.wait_obj);
@@ -118,7 +120,7 @@
 	return 0;
 }
 
-static const char *Win32MidiStart(const char * const *parm)
+const char *MusicDriver_Win32::Start(const char * const *parm)
 {
 	MIDIOUTCAPS midicaps;
 	DWORD threadId;
@@ -146,17 +148,8 @@
 	return NULL;
 }
 
-static void Win32MidiStop()
+void MusicDriver_Win32::Stop()
 {
 	_midi.terminate = true;
 	SetEvent(_midi.wait_obj);
 }
-
-const HalMusicDriver _win32_music_driver = {
-	Win32MidiStart,
-	Win32MidiStop,
-	Win32MidiPlaySong,
-	Win32MidiStopSong,
-	Win32MidiIsSongPlaying,
-	Win32MidiSetVolume,
-};
--- a/src/music/win32_m.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music/win32_m.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef MUSIC_WIN32_H
 #define MUSIC_WIN32_H
 
-#include "../hal.h"
+#include "music_driver.hpp"
 
-extern const HalMusicDriver _win32_music_driver;
+class MusicDriver_Win32: public MusicDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void PlaySong(const char *filename);
+
+	/* virtual */ void StopSong();
+
+	/* virtual */ bool IsSongPlaying();
+
+	/* virtual */ void SetVolume(byte vol);
+};
+
+class FMusicDriver_Win32: public MusicDriverFactory<FMusicDriver_Win32> {
+public:
+	/* virtual */ const char *GetName() { return "win32"; }
+	/* virtual */ const char *GetDescription() { return "Win32 Music Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new MusicDriver_Win32(); }
+};
 
 #endif /* MUSIC_WIN32_H */
--- a/src/music_gui.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/music_gui.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -11,10 +11,10 @@
 #include "window.h"
 #include "gfx.h"
 #include "sound.h"
-#include "hal.h"
 #include "macros.h"
 #include "variables.h"
 #include "music.h"
+#include "music/music_driver.hpp"
 
 static byte _music_wnd_cursong;
 static bool _song_is_active;
@@ -86,7 +86,7 @@
 
 static void MusicVolumeChanged(byte new_vol)
 {
-	_music_driver->set_volume(new_vol);
+	_music_driver->SetVolume(new_vol);
 }
 
 static void DoPlaySong()
@@ -94,12 +94,12 @@
 	char filename[MAX_PATH];
 	FioFindFullPath(filename, lengthof(filename), GM_DIR,
 			origin_songs_specs[_music_wnd_cursong - 1].filename);
-	_music_driver->play_song(filename);
+	_music_driver->PlaySong(filename);
 }
 
 static void DoStopMusic()
 {
-	_music_driver->stop_song();
+	_music_driver->StopSong();
 }
 
 static void SelectSongToPlay()
@@ -178,7 +178,7 @@
 
 	if (!_song_is_active) return;
 
-	if (!_music_driver->is_song_playing()) {
+	if (!_music_driver->IsSongPlaying()) {
 		if (_game_mode != GM_MENU) {
 			StopMusic();
 			SkipToNextSong();
--- a/src/openttd.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/openttd.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -41,7 +41,6 @@
 #include "sound.h"
 #include "economy.h"
 #include "fileio.h"
-#include "hal.h"
 #include "airport.h"
 #include "aircraft.h"
 #include "console.h"
@@ -65,6 +64,9 @@
 #include "player_face.h"
 #include "group.h"
 #include "blitter/factory.hpp"
+#include "sound/sound_driver.hpp"
+#include "music/music_driver.hpp"
+#include "video/video_driver.hpp"
 
 #include "bridge_map.h"
 #include "clear_map.h"
@@ -103,7 +105,7 @@
 	va_end(va);
 
 	ShowOSErrorBox(buf);
-	if (_video_driver != NULL) _video_driver->stop();
+	if (_video_driver != NULL) _video_driver->Stop();
 
 	assert(0);
 	exit(1);
@@ -186,7 +188,8 @@
 		lastof(buf)
 	);
 
-	p = GetDriverList(p, lastof(buf));
+	/* List the drivers */
+	p = VideoDriverFactoryBase::GetDriversInfo(p, lastof(buf));
 
 	/* List the blitters */
 	p = BlitterFactoryBase::GetBlittersInfo(p, lastof(buf));
@@ -342,7 +345,7 @@
 	MarkWholeScreenDirty();
 
 	/* Play main theme */
-	if (_music_driver->is_song_playing()) ResetMusic();
+	if (_music_driver->IsSongPlaying()) ResetMusic();
 }
 
 #if defined(UNIX) && !defined(__MORPHOS__)
@@ -514,16 +517,36 @@
 	DEBUG(misc, 1, "Loading blitter '%s'...", blitter);
 	if (BlitterFactoryBase::SelectBlitter(blitter) == NULL)
 		error("Failed to select requested blitter '%s'; does it exist?", blitter);
+
 	DEBUG(driver, 1, "Loading drivers...");
-	LoadDriver(SOUND_DRIVER, _ini_sounddriver);
-	LoadDriver(MUSIC_DRIVER, _ini_musicdriver);
-	LoadDriver(VIDEO_DRIVER, _ini_videodriver); // load video last, to prevent an empty window while sound and music loads
+
+	_sound_driver = (SoundDriver*)SoundDriverFactoryBase::SelectDriver(_ini_sounddriver, Driver::DT_SOUND);
+	if (_sound_driver == NULL) {
+		StrEmpty(_ini_sounddriver) ?
+			error("Failed to autoprobe sound driver") :
+			error("Failed to select requested sound driver '%s'", _ini_sounddriver);
+	}
+
+	_music_driver = (MusicDriver*)MusicDriverFactoryBase::SelectDriver(_ini_musicdriver, Driver::DT_MUSIC);
+	if (_music_driver == NULL) {
+		StrEmpty(_ini_musicdriver) ?
+			error("Failed to autoprobe music driver") :
+			error("Failed to select requested music driver '%s'", _ini_musicdriver);
+	}
+
+	_video_driver = (VideoDriver*)VideoDriverFactoryBase::SelectDriver(_ini_videodriver, Driver::DT_VIDEO);
+	if (_video_driver == NULL) {
+		StrEmpty(_ini_videodriver) ?
+			error("Failed to autoprobe video driver") :
+			error("Failed to select requested video driver '%s'", _ini_videodriver);
+	}
+
 	_savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING;
 	/* Initialize the zoom level of the screen to normal */
 	_screen.zoom = ZOOM_LVL_NORMAL;
 
 	/* restore saved music volume */
-	_music_driver->set_volume(msf.music_vol);
+	_music_driver->SetVolume(msf.music_vol);
 
 	NetworkStartUp(); // initialize network-core
 
@@ -594,16 +617,16 @@
 	}
 #endif /* ENABLE_NETWORK */
 
-	_video_driver->main_loop();
+	_video_driver->MainLoop();
 
 	WaitTillSaved();
 	IConsoleFree();
 
 	if (_network_available) NetworkShutDown(); // Shut down the network and close any open connections
 
-	_video_driver->stop();
-	_music_driver->stop();
-	_sound_driver->stop();
+	_video_driver->Stop();
+	_music_driver->Stop();
+	_sound_driver->Stop();
 
 	/* only save config if we have to */
 	if (save_config) {
@@ -2097,8 +2120,3 @@
 	/* redraw the whole screen */
 	MarkWholeScreenDirty();
 }
-
-HalMusicDriver *_music_driver;
-HalSoundDriver *_sound_driver;
-HalVideoDriver *_video_driver;
-
--- a/src/sound/cocoa_s.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/sound/cocoa_s.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -36,6 +36,7 @@
 #undef Point
 #undef Rect
 
+static FSoundDriver_Cocoa iFSoundDriver_Cocoa;
 
 static AudioUnit _outputAudioUnit;
 
@@ -48,7 +49,7 @@
 }
 
 
-static const char *CocoaSoundStart(const char * const *parm)
+const char *SoundDriver_Cocoa::Start(const char * const *parm)
 {
 	Component comp;
 	ComponentDescription desc;
@@ -116,7 +117,7 @@
 }
 
 
-static void CocoaSoundStop()
+void SoundDriver_Cocoa::Stop()
 {
 	struct AudioUnitInputCallback callback;
 
@@ -140,10 +141,4 @@
 	}
 }
 
-
-const HalSoundDriver _cocoa_sound_driver = {
-	CocoaSoundStart,
-	CocoaSoundStop,
-};
-
 #endif /* WITH_COCOA */
--- a/src/sound/cocoa_s.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/sound/cocoa_s.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,22 @@
 #ifndef SOUND_COCOA_H
 #define SOUND_COCOA_H
 
-#include "../hal.h"
+#include "sound_driver.hpp"
 
-extern const HalSoundDriver _cocoa_sound_driver;
+class SoundDriver_Cocoa: public SoundDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+};
+
+class FSoundDriver_Cocoa: public SoundDriverFactory<FSoundDriver_Cocoa> {
+public:
+	/* virtual */ const char *GetName() { return "cocoa"; }
+	/* virtual */ const char *GetDescription() { return "Cocoa Sound Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new SoundDriver_Cocoa(); }
+};
 
 #endif /* SOUND_COCOA_H */
--- a/src/sound/null_s.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/sound/null_s.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -3,10 +3,4 @@
 #include "../stdafx.h"
 #include "null_s.h"
 
-static const char *NullSoundStart(const char * const *parm) { return NULL; }
-static void NullSoundStop() {}
-
-const HalSoundDriver _null_sound_driver = {
-	NullSoundStart,
-	NullSoundStop,
-};
+static FSoundDriver_Null iFSoundDriver_Null;
--- a/src/sound/null_s.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/sound/null_s.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,22 @@
 #ifndef SOUND_NULL_H
 #define SOUND_NULL_H
 
-#include "../hal.h"
+#include "sound_driver.hpp"
 
-extern const HalSoundDriver _null_sound_driver;
+class SoundDriver_Null: public SoundDriver {
+public:
+	/* virtual */ bool CanProbe() { return false; }
+
+	/* virtual */ const char *Start(const char * const *param) { return NULL; }
+
+	/* virtual */ void Stop() { }
+};
+
+class FSoundDriver_Null: public SoundDriverFactory<FSoundDriver_Null> {
+public:
+	/* virtual */ const char *GetName() { return "null"; }
+	/* virtual */ const char *GetDescription() { return "Null Sound Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new SoundDriver_Null(); }
+};
 
 #endif /* SOUND_NULL_H */
--- a/src/sound/sdl_s.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/sound/sdl_s.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -10,12 +10,14 @@
 #include "sdl_s.h"
 #include <SDL.h>
 
+static FSoundDriver_SDL iFSoundDriver_SDL;
+
 static void CDECL fill_sound_buffer(void *userdata, Uint8 *stream, int len)
 {
 	MxMixSamples(stream, len / 4);
 }
 
-static const char *SdlSoundStart(const char * const *parm)
+const char *SoundDriver_SDL::Start(const char * const *parm)
 {
 	SDL_AudioSpec spec;
 
@@ -32,15 +34,10 @@
 	return NULL;
 }
 
-static void SdlSoundStop()
+void SoundDriver_SDL::Stop()
 {
 	SDL_CALL SDL_CloseAudio();
 	SdlClose(SDL_INIT_AUDIO);
 }
 
-const HalSoundDriver _sdl_sound_driver = {
-	SdlSoundStart,
-	SdlSoundStop,
-};
-
 #endif /* WITH_SDL */
--- a/src/sound/sdl_s.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/sound/sdl_s.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,22 @@
 #ifndef SOUND_SDL_H
 #define SOUND_SDL_H
 
-#include "../hal.h"
+#include "sound_driver.hpp"
 
-extern const HalSoundDriver _sdl_sound_driver;
+class SoundDriver_SDL: public SoundDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+};
+
+class FSoundDriver_SDL: public SoundDriverFactory<FSoundDriver_SDL> {
+public:
+	/* virtual */ const char *GetName() { return "sdl"; }
+	/* virtual */ const char *GetDescription() { return "SDL Sound Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new SoundDriver_SDL(); }
+};
 
 #endif /* SOUND_SDL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sound/sound_driver.hpp	Thu Jul 05 12:23:54 2007 +0000
@@ -0,0 +1,27 @@
+/* $Id$ */
+
+#ifndef SOUND_SOUND_DRIVER_HPP
+#define SOUND_SOUND_DRIVER_HPP
+
+#include "../driver.h"
+
+class SoundDriver: public Driver {
+};
+
+class SoundDriverFactoryBase: public DriverFactoryBase {
+};
+
+template <class T>
+class SoundDriverFactory: public SoundDriverFactoryBase {
+public:
+	SoundDriverFactory() { this->RegisterDriver(((T *)this)->GetName(), Driver::DT_SOUND); }
+
+	/**
+	 * Get the long, human readable, name for the Driver-class.
+	 */
+	const char *GetName();
+};
+
+extern SoundDriver *_sound_driver;
+
+#endif /* SOUND_SOUND_DRIVER_HPP */
--- a/src/sound/win32_s.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/sound/win32_s.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -10,6 +10,8 @@
 #include <windows.h>
 #include <mmsystem.h>
 
+static FSoundDriver_Win32 iFSoundDriver_Win32;
+
 static HWAVEOUT _waveout;
 static WAVEHDR _wave_hdr[2];
 static int _bufsize;
@@ -48,7 +50,7 @@
 	}
 }
 
-static const char *Win32SoundStart(const char* const* parm)
+const char *SoundDriver_Win32::Start(const char* const* parm)
 {
 	WAVEFORMATEX wfex;
 	wfex.wFormatTag = WAVE_FORMAT_PCM;
@@ -69,7 +71,7 @@
 	return NULL;
 }
 
-static void Win32SoundStop()
+void SoundDriver_Win32::Stop()
 {
 	HWAVEOUT waveout = _waveout;
 
@@ -79,8 +81,3 @@
 	waveOutUnprepareHeader(waveout, &_wave_hdr[1], sizeof(WAVEHDR));
 	waveOutClose(waveout);
 }
-
-const HalSoundDriver _win32_sound_driver = {
-	Win32SoundStart,
-	Win32SoundStop,
-};
--- a/src/sound/win32_s.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/sound/win32_s.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,22 @@
 #ifndef SOUND_WIN32_H
 #define SOUND_WIN32_H
 
-#include "../hal.h"
+#include "sound_driver.hpp"
 
-extern const HalSoundDriver _win32_sound_driver;
+class SoundDriver_Win32: public SoundDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+};
+
+class FSoundDriver_Win32: public SoundDriverFactory<FSoundDriver_Win32> {
+public:
+	/* virtual */ const char *GetName() { return "win32"; }
+	/* virtual */ const char *GetDescription() { return "Win32 Sound Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new SoundDriver_Win32(); }
+};
 
 #endif /* SOUND_WIN32_H */
--- a/src/texteff.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/texteff.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -11,7 +11,6 @@
 #include "landscape.h"
 #include "viewport.h"
 #include "saveload.h"
-#include "hal.h"
 #include "console.h"
 #include "string.h"
 #include "variables.h"
@@ -20,6 +19,7 @@
 #include <stdarg.h> /* va_list */
 #include "date.h"
 #include "texteff.hpp"
+#include "video/video_driver.hpp"
 
 enum {
 	MAX_TEXTMESSAGE_LENGTH = 200,
@@ -168,7 +168,7 @@
 		/* Put our 'shot' back to the screen */
 		blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _textmessage_backup, width, height);
 		/* And make sure it is updated next time */
-		_video_driver->make_dirty(x, y, width, height);
+		_video_driver->MakeDirty(x, y, width, height);
 
 		_textmessage_dirty = true;
 	}
@@ -248,7 +248,7 @@
 	}
 
 	/* Make sure the data is updated next flush */
-	_video_driver->make_dirty(x, y, width, height);
+	_video_driver->MakeDirty(x, y, width, height);
 
 	_textmessage_visible = true;
 	_textmessage_dirty = false;
--- a/src/video/cocoa_v.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/video/cocoa_v.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,11 +3,30 @@
 #ifndef VIDEO_COCOA_H
 #define VIDEO_COCOA_H
 
-#include "../hal.h"
+#include "video_driver.hpp"
 
-#include "../openttd.h"
-#include "../gfx.h"
+class VideoDriver_Cocoa: public VideoDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
 
-extern const HalVideoDriver _cocoa_video_driver;
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void MakeDirty(int left, int top, int width, int height);
+
+	/* virtual */ void MainLoop();
+
+	/* virtual */ bool ChangeResolution(int w, int h);
+
+	/* virtual */ void ToggleFullscreen(bool fullscreen);
+};
+
+class FVideoDriver_Cocoa: public VideoDriverFactory<FVideoDriver_Cocoa> {
+public:
+	/* virtual */ const char *GetName() { return "cocoa"; }
+	/* virtual */ const char *GetDescription() { return "Cocoa Video Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new VideoDriver_Cocoa(); }
+};
 
 #endif /* VIDEO_COCOA_H */
--- a/src/video/cocoa_v.mm	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/video/cocoa_v.mm	Thu Jul 05 12:23:54 2007 +0000
@@ -65,10 +65,12 @@
 
 
 #include "../stdafx.h"
+#include "../openttd.h"
 #include "../debug.h"
 #include "../macros.h"
 #include "../os/macosx/splash.h"
 #include "../variables.h"
+#include "../gfx.h"
 #include "cocoa_v.h"
 #include "cocoa_keys.h"
 #include "../blitter/factory.hpp"
@@ -131,14 +133,13 @@
 static void QZ_WarpCursor(int x, int y);
 static void QZ_ShowMouse();
 static void QZ_HideMouse();
-static void CocoaVideoFullScreen(bool full_screen);
 
 
 static NSAutoreleasePool *_ottd_autorelease_pool;
 static OTTDMain *_ottd_main;
 
 
-static struct CocoaVideoData {
+static struct VideoDriver_Cocoa::Data {
 	bool isset;
 	bool issetting;
 
@@ -366,7 +367,7 @@
 		case QZ_RETURN:
 		case QZ_f:
 			if (down && (_cocoa_video_data.current_mods & NSCommandKeyMask)) {
-				CocoaVideoFullScreen(!_fullscreen);
+				_video_driver->ToggleFullscreen(!_fullscreen);
 			}
 			break;
 	}
@@ -1319,9 +1320,9 @@
 	return 0;
 }
 
-static const char* QZ_SetVideoFullScreen(int width, int height)
+static const char* QZ_SetVideoToggleFullscreen(int width, int height)
 {
-	const char* errstr = "QZ_SetVideoFullScreen error";
+	const char* errstr = "QZ_SetVideoToggleFullscreen error";
 	int exact_match;
 	CFNumberRef number;
 	int bpp;
@@ -1707,7 +1708,7 @@
 	_cocoa_video_data.issetting = true;
 	if (fullscreen) {
 		/* Setup full screen video */
-		ret = QZ_SetVideoFullScreen(width, height);
+		ret = QZ_SetVideoToggleFullscreen(width, height);
 	} else {
 		/* Setup windowed video */
 		ret = QZ_SetVideoWindowed(width, height);
@@ -1970,7 +1971,9 @@
  *                             Video driver interface                         *
  ******************************************************************************/
 
-static void CocoaVideoStop()
+static FVideoDriver_Cocoa iFVideoDriver_Cocoa;
+
+void VideoDriver_Cocoa::Stop()
 {
 	if (!_cocoa_video_started) return;
 
@@ -1981,7 +1984,7 @@
 	_cocoa_video_started = false;
 }
 
-static const char *CocoaVideoStart(const char * const *parm)
+const char *VideoDriver_Cocoa::Start(const char * const *parm)
 {
 	const char *ret;
 
@@ -1998,12 +2001,12 @@
 	QZ_VideoInit();
 
 	ret = QZ_SetVideoMode(_cur_resolution[0], _cur_resolution[1], _fullscreen);
-	if (ret != NULL) CocoaVideoStop();
+	if (ret != NULL) VideoDriver_Cocoa::Stop();
 
 	return ret;
 }
 
-static void CocoaVideoMakeDirty(int left, int top, int width, int height)
+void VideoDriver_Cocoa::MakeDirty(int left, int top, int width, int height)
 {
 	if (_cocoa_video_data.num_dirty_rects < MAX_DIRTY_RECTS) {
 		_cocoa_video_data.dirty_rects[_cocoa_video_data.num_dirty_rects].left = left;
@@ -2014,41 +2017,32 @@
 	_cocoa_video_data.num_dirty_rects++;
 }
 
-static void CocoaVideoMainLoop()
+void VideoDriver_Cocoa::MainLoop()
 {
 	/* Start the main event loop */
 	[NSApp run];
 }
 
-static bool CocoaVideoChangeRes(int w, int h)
+bool VideoDriver_Cocoa::ChangeResolution(int w, int h)
 {
 	const char *ret = QZ_SetVideoModeAndRestoreOnFailure((uint)w, (uint)h, _cocoa_video_data.fullscreen);
 	if (ret != NULL) {
-		DEBUG(driver, 0, "cocoa_v: CocoaVideoChangeRes failed with message: %s", ret);
+		DEBUG(driver, 0, "cocoa_v: VideoDriver_Cocoa::ChangeResolution failed with message: %s", ret);
 	}
 
 	return ret == NULL;
 }
 
-static void CocoaVideoFullScreen(bool full_screen)
+void VideoDriver_Cocoa::ToggleFullscreen(bool full_screen)
 {
 	const char *ret = QZ_SetVideoModeAndRestoreOnFailure(_cocoa_video_data.width, _cocoa_video_data.height, full_screen);
 	if (ret != NULL) {
-		DEBUG(driver, 0, "cocoa_v: CocoaVideoFullScreen failed with message: %s", ret);
+		DEBUG(driver, 0, "cocoa_v: VideoDriver_Cocoa::ToggleFullscreen failed with message: %s", ret);
 	}
 
 	_fullscreen = _cocoa_video_data.fullscreen;
 }
 
-const HalVideoDriver _cocoa_video_driver = {
-	CocoaVideoStart,
-	CocoaVideoStop,
-	CocoaVideoMakeDirty,
-	CocoaVideoMainLoop,
-	CocoaVideoChangeRes,
-	CocoaVideoFullScreen,
-};
-
 
 /* This is needed since sometimes assert is called before the videodriver is initialized */
 void CocoaDialog(const char* title, const char* message, const char* buttonLabel)
@@ -2058,14 +2052,14 @@
 	_cocoa_video_dialog = true;
 
 	wasstarted = _cocoa_video_started;
-	if (!_cocoa_video_started && CocoaVideoStart(NULL) != NULL) {
+	if (!_cocoa_video_started && VideoDriver_Cocoa::Start(NULL) != NULL) {
 		fprintf(stderr, "%s: %s\n", title, message);
 		return;
 	}
 
 	NSRunAlertPanel([NSString stringWithCString: title], [NSString stringWithCString: message], [NSString stringWithCString: buttonLabel], nil, nil);
 
-	if (!wasstarted) CocoaVideoStop();
+	if (!wasstarted) VideoDriver_Cocoa::Stop();
 
 	_cocoa_video_dialog = false;
 }
--- a/src/video/dedicated_v.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/video/dedicated_v.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -119,8 +119,10 @@
 extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm, Subdirectory subdir);
 extern void SwitchMode(int new_mode);
 
+static FVideoDriver_Dedicated iFVideoDriver_Dedicated;
 
-static const char *DedicatedVideoStart(const char * const *parm)
+
+const char *VideoDriver_Dedicated::Start(const char * const *parm)
 {
 	int bpp = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth();
 	if (bpp == 0) _dedicated_video_mem = NULL;
@@ -147,7 +149,7 @@
 	return NULL;
 }
 
-static void DedicatedVideoStop()
+void VideoDriver_Dedicated::Stop()
 {
 #ifdef WIN32
 	CloseWindowsConsoleThread();
@@ -155,9 +157,9 @@
 	free(_dedicated_video_mem);
 }
 
-static void DedicatedVideoMakeDirty(int left, int top, int width, int height) {}
-static bool DedicatedVideoChangeRes(int w, int h) { return false; }
-static void DedicatedVideoFullScreen(bool fs) {}
+void VideoDriver_Dedicated::MakeDirty(int left, int top, int width, int height) {}
+bool VideoDriver_Dedicated::ChangeResolution(int w, int h) { return false; }
+void VideoDriver_Dedicated::ToggleFullscreen(bool fs) {}
 
 #if defined(UNIX) || defined(__OS2__) || defined(PSP)
 static bool InputWaiting()
@@ -232,7 +234,7 @@
 	IConsoleCmdExec(input_line); // execute command
 }
 
-static void DedicatedVideoMainLoop()
+void VideoDriver_Dedicated::MainLoop()
 {
 	uint32 cur_ticks = GetTime();
 	uint32 next_tick = cur_ticks + 30;
@@ -295,13 +297,4 @@
 	}
 }
 
-const HalVideoDriver _dedicated_video_driver = {
-	DedicatedVideoStart,
-	DedicatedVideoStop,
-	DedicatedVideoMakeDirty,
-	DedicatedVideoMainLoop,
-	DedicatedVideoChangeRes,
-	DedicatedVideoFullScreen,
-};
-
 #endif /* ENABLE_NETWORK */
--- a/src/video/dedicated_v.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/video/dedicated_v.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef VIDEO_DEDICATED_H
 #define VIDEO_DEDICATED_H
 
-#include "../hal.h"
+#include "video_driver.hpp"
 
-extern const HalVideoDriver _dedicated_video_driver;
+class VideoDriver_Dedicated: public VideoDriver {
+public:
+	/* virtual */ bool CanProbe() { return false; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void MakeDirty(int left, int top, int width, int height);
+
+	/* virtual */ void MainLoop();
+
+	/* virtual */ bool ChangeResolution(int w, int h);
+
+	/* virtual */ void ToggleFullscreen(bool fullscreen);
+};
+
+class FVideoDriver_Dedicated: public VideoDriverFactory<FVideoDriver_Dedicated> {
+public:
+	/* virtual */ const char *GetName() { return "dedicated"; }
+	/* virtual */ const char *GetDescription() { return "Dedicated Video Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new VideoDriver_Dedicated(); }
+};
 
 #endif /* VIDEO_DEDICATED_H */
--- a/src/video/null_v.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/video/null_v.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -9,7 +9,9 @@
 #include "../blitter/factory.hpp"
 #include "null_v.h"
 
-static const char* NullVideoStart(const char* const* parm)
+static FVideoDriver_Null iFVideoDriver_Null;
+
+const char *VideoDriver_Null::Start(const char* const *parm)
 {
 	_screen.width = _screen.pitch = _cur_resolution[0];
 	_screen.height = _cur_resolution[1];
@@ -19,11 +21,11 @@
 	return NULL;
 }
 
-static void NullVideoStop() { }
+void VideoDriver_Null::Stop() { }
 
-static void NullVideoMakeDirty(int left, int top, int width, int height) {}
+void VideoDriver_Null::MakeDirty(int left, int top, int width, int height) {}
 
-static void NullVideoMainLoop()
+void VideoDriver_Null::MainLoop()
 {
 	uint i;
 
@@ -34,14 +36,6 @@
 	}
 }
 
-static bool NullVideoChangeRes(int w, int h) { return false; }
-static void NullVideoFullScreen(bool fs) {}
+bool VideoDriver_Null::ChangeResolution(int w, int h) { return false; }
 
-const HalVideoDriver _null_video_driver = {
-	NullVideoStart,
-	NullVideoStop,
-	NullVideoMakeDirty,
-	NullVideoMainLoop,
-	NullVideoChangeRes,
-	NullVideoFullScreen,
-};
+void VideoDriver_Null::ToggleFullscreen(bool fs) {}
--- a/src/video/null_v.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/video/null_v.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef VIDEO_NULL_H
 #define VIDEO_NULL_H
 
-#include "../hal.h"
+#include "video_driver.hpp"
 
-extern const HalVideoDriver _null_video_driver;
+class VideoDriver_Null: public VideoDriver {
+public:
+	/* virtual */ bool CanProbe() { return false; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void MakeDirty(int left, int top, int width, int height);
+
+	/* virtual */ void MainLoop();
+
+	/* virtual */ bool ChangeResolution(int w, int h);
+
+	/* virtual */ void ToggleFullscreen(bool fullscreen);
+};
+
+class FVideoDriver_Null: public VideoDriverFactory<FVideoDriver_Null> {
+public:
+	/* virtual */ const char *GetName() { return "null"; }
+	/* virtual */ const char *GetDescription() { return "Null Video Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new VideoDriver_Null(); }
+};
 
 #endif /* VIDEO_NULL_H */
--- a/src/video/sdl_v.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/video/sdl_v.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -17,6 +17,8 @@
 #include "sdl_v.h"
 #include <SDL.h>
 
+static FVideoDriver_SDL iFVideoDriver_SDL;
+
 static SDL_Surface *_sdl_screen;
 static bool _all_modes;
 
@@ -24,7 +26,7 @@
 static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS];
 static int _num_dirty_rects;
 
-static void SdlVideoMakeDirty(int left, int top, int width, int height)
+void VideoDriver_SDL::MakeDirty(int left, int top, int width, int height)
 {
 	if (_num_dirty_rects < MAX_DIRTY_RECTS) {
 		_dirty_rects[_num_dirty_rects].x = left;
@@ -415,7 +417,7 @@
 	return -1;
 }
 
-static const char *SdlVideoStart(const char * const *parm)
+const char *VideoDriver_SDL::Start(const char * const *parm)
 {
 	char buf[30];
 
@@ -434,12 +436,12 @@
 	return NULL;
 }
 
-static void SdlVideoStop()
+void VideoDriver_SDL::Stop()
 {
 	SdlClose(SDL_INIT_VIDEO);
 }
 
-static void SdlVideoMainLoop()
+void VideoDriver_SDL::MainLoop()
 {
 	uint32 cur_ticks = SDL_CALL SDL_GetTicks();
 	uint32 last_cur_ticks = cur_ticks;
@@ -505,28 +507,19 @@
 	}
 }
 
-static bool SdlVideoChangeRes(int w, int h)
+bool VideoDriver_SDL::ChangeResolution(int w, int h)
 {
 	return CreateMainSurface(w, h);
 }
 
-static void SdlVideoFullScreen(bool full_screen)
+void VideoDriver_SDL::ToggleFullscreen(bool fullscreen)
 {
-	_fullscreen = full_screen;
+	_fullscreen = fullscreen;
 	GetVideoModes(); // get the list of available video modes
-	if (_num_resolutions == 0 || !_video_driver->change_resolution(_cur_resolution[0], _cur_resolution[1])) {
+	if (_num_resolutions == 0 || !this->ChangeResolution(_cur_resolution[0], _cur_resolution[1])) {
 		// switching resolution failed, put back full_screen to original status
 		_fullscreen ^= true;
 	}
 }
 
-const HalVideoDriver _sdl_video_driver = {
-	SdlVideoStart,
-	SdlVideoStop,
-	SdlVideoMakeDirty,
-	SdlVideoMainLoop,
-	SdlVideoChangeRes,
-	SdlVideoFullScreen,
-};
-
 #endif /* WITH_SDL */
--- a/src/video/sdl_v.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/video/sdl_v.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef VIDEO_SDL_H
 #define VIDEO_SDL_H
 
-#include "../hal.h"
+#include "video_driver.hpp"
 
-extern const HalVideoDriver _sdl_video_driver;
+class VideoDriver_SDL: public VideoDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void MakeDirty(int left, int top, int width, int height);
+
+	/* virtual */ void MainLoop();
+
+	/* virtual */ bool ChangeResolution(int w, int h);
+
+	/* virtual */ void ToggleFullscreen(bool fullscreen);
+};
+
+class FVideoDriver_SDL: public VideoDriverFactory<FVideoDriver_SDL> {
+public:
+	/* virtual */ const char *GetName() { return "sdl"; }
+	/* virtual */ const char *GetDescription() { return "SDL Video Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new VideoDriver_SDL(); }
+};
 
 #endif /* VIDEO_SDL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/video_driver.hpp	Thu Jul 05 12:23:54 2007 +0000
@@ -0,0 +1,35 @@
+/* $Id$ */
+
+#ifndef VIDEO_VIDEO_DRIVER_HPP
+#define VIDEO_VIDEO_DRIVER_HPP
+
+#include "../driver.h"
+
+class VideoDriver: public Driver {
+public:
+	virtual void MakeDirty(int left, int top, int width, int height) = 0;
+
+	virtual void MainLoop() = 0;
+
+	virtual bool ChangeResolution(int w, int h) = 0;
+
+	virtual void ToggleFullscreen(bool fullscreen) = 0;
+};
+
+class VideoDriverFactoryBase: public DriverFactoryBase {
+};
+
+template <class T>
+class VideoDriverFactory: public VideoDriverFactoryBase {
+public:
+	VideoDriverFactory() { this->RegisterDriver(((T *)this)->GetName(), Driver::DT_VIDEO); }
+
+	/**
+	 * Get the long, human readable, name for the Driver-class.
+	 */
+	const char *GetName();
+};
+
+extern VideoDriver *_video_driver;
+
+#endif /* VIDEO_VIDEO_DRIVER_HPP */
--- a/src/video/win32_v.cpp	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/video/win32_v.cpp	Thu Jul 05 12:23:54 2007 +0000
@@ -751,8 +751,9 @@
 	SortResolutions(_num_resolutions);
 }
 
+static FVideoDriver_Win32 iFVideoDriver_Win32;
 
-static const char *Win32GdiStart(const char * const *parm)
+const char *VideoDriver_Win32::Start(const char * const *parm)
 {
 	memset(&_wnd, 0, sizeof(_wnd));
 
@@ -774,7 +775,7 @@
 	return NULL;
 }
 
-static void Win32GdiStop()
+void VideoDriver_Win32::Stop()
 {
 	DeleteObject(_wnd.gdi_palette);
 	DeleteObject(_wnd.dib_sect);
@@ -786,7 +787,7 @@
 	MyShowCursor(true);
 }
 
-static void Win32GdiMakeDirty(int left, int top, int width, int height)
+void VideoDriver_Win32::MakeDirty(int left, int top, int width, int height)
 {
 	RECT r = { left, top, left + width, top + height };
 
@@ -800,7 +801,7 @@
 	InvalidateRect(_wnd.main_wnd, NULL, FALSE);
 }
 
-static void Win32GdiMainLoop()
+void VideoDriver_Win32::MainLoop()
 {
 	MSG mesg;
 	uint32 cur_ticks = GetTickCount();
@@ -873,7 +874,7 @@
 	}
 }
 
-static bool Win32GdiChangeRes(int w, int h)
+bool VideoDriver_Win32::ChangeResolution(int w, int h)
 {
 	_wnd.width = _wnd.width_org = w;
 	_wnd.height = _wnd.height_org = h;
@@ -883,16 +884,7 @@
 	return true;
 }
 
-static void Win32GdiFullScreen(bool full_screen)
+void VideoDriver_Win32::ToggleFullscreen(bool full_screen)
 {
 	MakeWindow(full_screen);
 }
-
-const HalVideoDriver _win32_video_driver = {
-	Win32GdiStart,
-	Win32GdiStop,
-	Win32GdiMakeDirty,
-	Win32GdiMainLoop,
-	Win32GdiChangeRes,
-	Win32GdiFullScreen,
-};
--- a/src/video/win32_v.h	Thu Jul 05 06:35:09 2007 +0000
+++ b/src/video/win32_v.h	Thu Jul 05 12:23:54 2007 +0000
@@ -3,8 +3,30 @@
 #ifndef VIDEO_WIN32_H
 #define VIDEO_WIN32_H
 
-#include "../hal.h"
+#include "video_driver.hpp"
 
-extern const HalVideoDriver _win32_video_driver;
+class VideoDriver_Win32: public VideoDriver {
+public:
+	/* virtual */ bool CanProbe() { return true; }
+
+	/* virtual */ const char *Start(const char * const *param);
+
+	/* virtual */ void Stop();
+
+	/* virtual */ void MakeDirty(int left, int top, int width, int height);
+
+	/* virtual */ void MainLoop();
+
+	/* virtual */ bool ChangeResolution(int w, int h);
+
+	/* virtual */ void ToggleFullscreen(bool fullscreen);
+};
+
+class FVideoDriver_Win32: public VideoDriverFactory<FVideoDriver_Win32> {
+public:
+	/* virtual */ const char *GetName() { return "win32"; }
+	/* virtual */ const char *GetDescription() { return "Win32 Video Driver"; }
+	/* virtual */ Driver *CreateInstance() { return new VideoDriver_Win32(); }
+};
 
 #endif /* VIDEO_WIN32_H */