diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp
index d3e3c007a796c23f75e72912ce298d215dc22e04..07efbb62f853334673bb37a8602fc1c968d099c9 100644
--- a/src/guiMainMenu.cpp
+++ b/src/guiMainMenu.cpp
@@ -162,6 +162,8 @@ enum
 	GUI_ID_SERVERLIST_TOGGLE,
 	GUI_ID_SERVERLIST_DELETE,
 	GUI_ID_SERVERLIST_TITLE,
+	GUI_ID_GAME_BUTTON_FIRST = 130,
+	GUI_ID_GAME_BUTTON_MAX = 150,
 };
 
 enum
@@ -255,8 +257,12 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, size.X, 40);
 		rect += v2s32(4, 0);
-		Environment->addStaticText(narrow_to_wide(
-				"Minetest " VERSION_STRING).c_str(),
+		std::string t = "Minetest " VERSION_STRING;
+		if(m_data->selected_game != ""){
+			t += "/";
+			t += m_data->selected_game;
+		}
+		Environment->addStaticText(narrow_to_wide(t).c_str(),
 				rect, false, true, this, -1);
 	}
 
@@ -900,6 +906,27 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		}
 	}
 
+	/* Add game selection buttons */
+
+	video::IVideoDriver* driver = Environment->getVideoDriver();
+	for(size_t i=0; i<m_data->games.size(); i++){
+		const SubgameSpec *spec = &m_data->games[i];
+		v2s32 p(8 + i*(48+8), screensize.Y - (48+8));
+		core::rect<s32> rect(0, 0, 48, 48);
+		rect += p;
+		video::ITexture *bgtexture = NULL;
+		if(spec->menuicon_path != "")
+			bgtexture = driver->getTexture(spec->menuicon_path.c_str());
+		gui::IGUIButton *b = Environment->addButton(rect, this,
+				GUI_ID_GAME_BUTTON_FIRST+i, narrow_to_wide(wrap_rows(spec->id, 4)).c_str());
+		if(bgtexture){
+			b->setImage(bgtexture);
+			b->setText(L"");
+			b->setDrawBorder(false);
+			b->setUseAlphaChannel(true);
+		}
+	}
+
 	m_is_regenerating = false;
 }
 
@@ -909,7 +936,9 @@ void GUIMainMenu::drawMenu()
 	if (!skin)
 		return;
 	video::IVideoDriver* driver = Environment->getVideoDriver();
-	
+
+	/* Draw menu background */
+
 	/*video::SColor bgcolor(140,0,0,0);
 	driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);*/
 
@@ -976,6 +1005,8 @@ void GUIMainMenu::drawMenu()
 		}
 	}
 
+	/* Draw UI elements */
+
 	gui::IGUIElement::draw();
 }
 
@@ -1221,7 +1252,7 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
 				return true;
 			}
 			case GUI_ID_CREATE_WORLD_BUTTON: {
-				std::vector<SubgameSpec> games = getAvailableGames();
+				const std::vector<SubgameSpec> &games = m_data->games;
 				if(games.size() == 0){
 					wchar_t* text = wgettext("Cannot create world: No games found");
 					GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
@@ -1308,6 +1339,14 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
 			}
 			#endif
 			}
+			/* Game buttons */
+			int eid = event.GUIEvent.Caller->getID();
+			if(eid >= GUI_ID_GAME_BUTTON_FIRST &&
+					eid <= GUI_ID_GAME_BUTTON_MAX){
+				m_data->selected_game =
+						m_data->games[eid - GUI_ID_GAME_BUTTON_FIRST].id;
+				regenerateGui(m_screensize_old);
+			}
 		}
 		if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
 		{
diff --git a/src/guiMainMenu.h b/src/guiMainMenu.h
index a594ccd418bac8c2b9a052b5740ab6ccc1245440..b0c9ff24b9583f846d256434230988367fc05acb 100644
--- a/src/guiMainMenu.h
+++ b/src/guiMainMenu.h
@@ -39,6 +39,7 @@ struct MainMenuData
 	// These are in the native format of the gui elements
 	// Generic
 	int selected_tab;
+	std::string selected_game;
 	// Client options
 	std::string servername;
 	std::string serverdescription;
@@ -78,6 +79,7 @@ struct MainMenuData
 	MainMenuData():
 		// Generic
 		selected_tab(0),
+		selected_game("minetest"),
 		// Client opts
 		fancy_trees(false),
 		smooth_lighting(false),
diff --git a/src/main.cpp b/src/main.cpp
index eef65cdb2ab77eee7b75630b01a3ff68d7576d13..67aa82bc4d299eada1c49609f0fa7d412dacb050 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -612,122 +612,65 @@ class RandomInputHandler : public InputHandler
 	bool rightreleased;
 };
 
-//Draw the tiled menu background
-void drawMenuBackground(video::IVideoDriver* driver) {
-	core::dimension2d<u32> screensize = driver->getScreenSize();
-
-	std::string path = getTexturePath("menubg.png");
-	if (path[0]) {
-		static const video::ITexture *bgtexture =
-			driver->getTexture(path.c_str());
+void drawMenuBackground(video::IVideoDriver* driver, const SubgameSpec *spec)
+{
+	v2u32 screensize = driver->getScreenSize();
 
-		if (bgtexture) {
-			s32 scaledsize = 128;
-		
-			// The important difference between destsize and screensize is
-			// that destsize is rounded to whole scaled pixels.
-			// These formulas use component-wise multiplication and division of v2u32.
-			v2u32 texturesize = bgtexture->getSize();
-			v2u32 sourcesize = texturesize * screensize / scaledsize + v2u32(1,1);
-			v2u32 destsize = scaledsize * sourcesize / texturesize;
-		
-			// Default texture wrapping mode in Irrlicht is ETC_REPEAT.
-			driver->draw2DImage(bgtexture,
-				core::rect<s32>(0, 0, destsize.X, destsize.Y),
-				core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
-				NULL, NULL, true);
-		}
+	/* Figure out background texture */
+	video::ITexture *texture = NULL;
+	if(spec && spec->menubackground_path != ""){
+		texture = driver->getTexture(spec->menubackground_path.c_str());
 	}
-}
 
-//Draw the footer at the bottom of the window
-void drawMenuFooter(video::IVideoDriver* driver, bool clouds) {
-	core::dimension2d<u32> screensize = driver->getScreenSize();
-	std::string path = getTexturePath(clouds ?
-						"menufooter_clouds.png" : "menufooter.png");
-	if (path[0]) {
-		static const video::ITexture *footertexture =
-			driver->getTexture(path.c_str());
-
-		if (footertexture) {
-			f32 mult = (((f32)screensize.Width)) /
-				((f32)footertexture->getOriginalSize().Width);
-
-			v2s32 footersize(((f32)footertexture->getOriginalSize().Width) * mult,
-					((f32)footertexture->getOriginalSize().Height) * mult);
-
-			// Don't draw the footer if there isn't enough room
-			s32 free_space = (((s32)screensize.Height)-320)/2;
-			if (free_space > footersize.Y) {
-				core::rect<s32> rect(0,0,footersize.X,footersize.Y);
-				rect += v2s32(screensize.Width/2,screensize.Height-footersize.Y);
-				rect -= v2s32(footersize.X/2, 0);
-
-				driver->draw2DImage(footertexture, rect,
-					core::rect<s32>(core::position2d<s32>(0,0),
-					core::dimension2di(footertexture->getSize())),
-					NULL, NULL, true);
-			}
-		}
+	/* If no texture, draw background of solid color */
+	if(!texture){
+		video::SColor color(255,80,58,37);
+		core::rect<s32> rect(0, 0, screensize.X, screensize.Y);
+		driver->draw2DRectangle(color, rect, NULL);
+		return;
 	}
-}
-
-// Draw the Header over the main menu
-void drawMenuHeader(video::IVideoDriver* driver) {
-	core::dimension2d<u32> screensize = driver->getScreenSize();
-
-	std::string path = getTexturePath("menuheader.png");
-	if (path[0]) {
-		static const video::ITexture *splashtexture =
-		driver->getTexture(path.c_str());
-
-		if(splashtexture) {
-			f32 mult = (((f32)screensize.Width / 2)) /
-				((f32)splashtexture->getOriginalSize().Width);
 
-			v2s32 splashsize(((f32)splashtexture->getOriginalSize().Width) * mult,
-					((f32)splashtexture->getOriginalSize().Height) * mult);
-
-			// Don't draw the header is there isn't enough room
-			s32 free_space = (((s32)screensize.Height)-320)/2;
-			if (free_space > splashsize.Y) {
-				core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y);
-				splashrect += v2s32((screensize.Width/2)-(splashsize.X/2),
-					((free_space/2)-splashsize.Y/2)+10);
+	/* Draw background texture */
+	v2u32 sourcesize = texture->getSize();
+	driver->draw2DImage(texture,
+		core::rect<s32>(0, 0, screensize.X, screensize.Y),
+		core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
+		NULL, NULL, true);
+}
 
-				video::SColor bgcolor(255,50,50,50);
+void drawMenuOverlay(video::IVideoDriver* driver, const SubgameSpec *spec)
+{
+	v2u32 screensize = driver->getScreenSize();
 
-				driver->draw2DImage(splashtexture, splashrect,
-					core::rect<s32>(core::position2d<s32>(0,0),
-					core::dimension2di(splashtexture->getSize())),
-					NULL, NULL, true);
-			}
-		}
+	/* Figure out overlay texture */
+	video::ITexture *texture = NULL;
+	if(spec && spec->menuoverlay_path != ""){
+		texture = driver->getTexture(spec->menuoverlay_path.c_str());
 	}
-}
 
-// Draw the Splash over the clouds and under the main menu
-void drawMenuSplash(video::IVideoDriver* driver) {
-	core::dimension2d<u32> screensize = driver->getScreenSize();
-	std::string path = getTexturePath("menusplash.png");
-	if (path[0]) {
-		static const video::ITexture *splashtexture =
-			driver->getTexture(path.c_str());
+	/* If no texture, draw nothing */
+	if(!texture)
+		return;
 
-		if(splashtexture) {
-			core::rect<s32> splashrect(0, 0, screensize.Width, screensize.Height);
-
-			video::SColor bgcolor(255,50,50,50);
+	/* Draw overlay texture */
+	v2u32 sourcesize = texture->getSize();
+	driver->draw2DImage(texture,
+		core::rect<s32>(0, 0, screensize.X, screensize.Y),
+		core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
+		NULL, NULL, true);
+}
 
-			driver->draw2DImage(splashtexture, splashrect,
-				core::rect<s32>(core::position2d<s32>(0,0),
-				core::dimension2di(splashtexture->getSize())),
-				NULL, NULL, true);
+static const SubgameSpec* getMenuGame(const MainMenuData &menudata)
+{
+	for(size_t i=0; i<menudata.games.size(); i++){
+		if(menudata.games[i].id == menudata.selected_game){
+			return &menudata.games[i];
 		}
 	}
+	return NULL;
 }
 
-#endif
+#endif // !SERVER
 
 // These are defined global so that they're not optimized too much.
 // Can't change them to volatile.
@@ -1558,6 +1501,8 @@ int main(int argc, char *argv[])
 					menudata.selected_tab = g_settings->getS32("selected_mainmenu_tab");
 				if(g_settings->exists("selected_serverlist"))
 					menudata.selected_serverlist = g_settings->getS32("selected_serverlist");
+				if(g_settings->exists("selected_mainmenu_game"))
+					menudata.selected_game = g_settings->get("selected_mainmenu_game");
 				menudata.address = narrow_to_wide(address);
 				menudata.name = narrow_to_wide(playername);
 				menudata.port = narrow_to_wide(itos(port));
@@ -1611,6 +1556,14 @@ int main(int argc, char *argv[])
 				}
 				// Copy worldspecs to menu
 				menudata.worlds = worldspecs;
+				// Get game listing
+				menudata.games = getAvailableGames();
+				// If selected game doesn't exist, take first from list
+				if(findSubgame(menudata.selected_game).id == "" &&
+						!menudata.games.empty()){
+					menudata.selected_game = menudata.games[0].id;
+				}
+				const SubgameSpec *menugame = getMenuGame(menudata);
 
 				if(skip_main_menu == false)
 				{
@@ -1623,7 +1576,7 @@ int main(int argc, char *argv[])
 							break;
 						driver->beginScene(true, true,
 								video::SColor(255,128,128,128));
-						drawMenuBackground(driver);
+						drawMenuBackground(driver, menugame);
 						guienv->drawAll();
 						driver->endScene();
 						// On some computers framerate doesn't seem to be
@@ -1637,21 +1590,17 @@ int main(int argc, char *argv[])
 								&g_menumgr, &menudata, g_gamecallback);
 					menu->allowFocusRemoval(true);
 
-					// Clouds for the main menu
-					bool cloud_menu_background = false;
-					Clouds *clouds = NULL;
-					if (g_settings->getBool("menu_clouds")) {
-						cloud_menu_background = true;
-						clouds = new Clouds(smgr->getRootSceneNode(),
-											smgr, -1, rand(), 100);
-						clouds->update(v2f(0, 0), video::SColor(255,200,200,255));
-
-						// A camera to see the clouds
-						scene::ICameraSceneNode* camera;
-						camera = smgr->addCameraSceneNode(0,
-									v3f(0,0,0), v3f(0, 60, 100));
-						camera->setFarValue(10000);
-					}
+					// Always create clouds because they may or may not be
+					// needed based on the game selected
+					Clouds *clouds = new Clouds(smgr->getRootSceneNode(),
+							smgr, -1, rand(), 100);
+					clouds->update(v2f(0, 0), video::SColor(255,200,200,255));
+
+					// A camera to see the clouds
+					scene::ICameraSceneNode* camera;
+					camera = smgr->addCameraSceneNode(0,
+								v3f(0,0,0), v3f(0, 60, 100));
+					camera->setFarValue(10000);
 
 					if(error_message != L"")
 					{
@@ -1675,6 +1624,24 @@ int main(int argc, char *argv[])
 						if(menu->getStatus() == true)
 							break;
 
+						// Game can be selected in the menu
+						menugame = getMenuGame(menudata);
+						// Clouds for the main menu
+						bool cloud_menu_background = g_settings->getBool("menu_clouds");
+						if(menugame){
+							// If game has regular background and no overlay, don't use clouds
+							if(cloud_menu_background &&
+									menugame->menuoverlay_path.empty() &&
+									!menugame->menubackground_path.empty()){
+								cloud_menu_background = false;
+							}
+							// If game game has overlay and no regular background, always draw clouds
+							else if(menugame->menubackground_path.empty() &&
+									!menugame->menuoverlay_path.empty()){
+								cloud_menu_background = true;
+							}
+						}
+
 						// Time calc for the clouds
 						f32 dtime; // in seconds
 						if (cloud_menu_background) {
@@ -1694,12 +1661,9 @@ int main(int argc, char *argv[])
 							clouds->step(dtime*3); 
 							clouds->render();
 							smgr->drawAll();
-							drawMenuSplash(driver);
-							drawMenuFooter(driver, true);
-							drawMenuHeader(driver);
+							drawMenuOverlay(driver, menugame);
 						} else {
-							drawMenuBackground(driver);
-							drawMenuFooter(driver, false);
+							drawMenuBackground(driver, menugame);
 						}
 
 						guienv->drawAll();
@@ -1735,10 +1699,8 @@ int main(int argc, char *argv[])
 					infostream<<"Dropping main menu"<<std::endl;
 
 					menu->drop();
-					if (cloud_menu_background) {
-						clouds->drop();
-						smgr->clear();
-					}
+					clouds->drop();
+					smgr->clear();
 				}
 
 				playername = wide_to_narrow(menudata.name);
@@ -1755,6 +1717,7 @@ int main(int argc, char *argv[])
 				// Save settings
 				g_settings->setS32("selected_mainmenu_tab", menudata.selected_tab);
 				g_settings->setS32("selected_serverlist", menudata.selected_serverlist);
+				g_settings->set("selected_mainmenu_game", menudata.selected_game);
 				g_settings->set("new_style_leaves", itos(menudata.fancy_trees));
 				g_settings->set("smooth_lighting", itos(menudata.smooth_lighting));
 				g_settings->set("enable_3d_clouds", itos(menudata.clouds_3d));
diff --git a/src/subgame.cpp b/src/subgame.cpp
index 19ad4e636be379fdd38171d175f72f42b49b455e..a17b1623466c301d509a0aadb2be6f6268f7e940 100644
--- a/src/subgame.cpp
+++ b/src/subgame.cpp
@@ -22,6 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "settings.h"
 #include "log.h"
+#ifndef SERVER
+#include "tile.h" // getImagePath
+#endif
 #include "util/string.h"
 
 bool getGameMinetestConfig(const std::string &game_path, Settings &conf)
@@ -94,7 +97,16 @@ SubgameSpec findSubgame(const std::string &id)
 	std::string game_name = getGameName(game_path);
 	if(game_name == "")
 		game_name = id;
-	return SubgameSpec(id, game_path, gamemod_path, mods_paths, game_name);
+	std::string menubackground_path;
+	std::string menuoverlay_path;
+	std::string menuicon_path;
+#ifndef SERVER
+	menubackground_path = getImagePath(game_path + DIR_DELIM + "menu/background.png");
+	menuoverlay_path = getImagePath(game_path + DIR_DELIM + "menu/overlay.png");
+	menuicon_path = getImagePath(game_path + DIR_DELIM + "menu/icon.png");
+#endif
+	return SubgameSpec(id, game_path, gamemod_path, mods_paths, game_name,
+			menubackground_path, menuoverlay_path, menuicon_path);
 }
 
 SubgameSpec findWorldSubgame(const std::string &world_path)
diff --git a/src/subgame.h b/src/subgame.h
index b120b75425482d8d5ee1e43dd54611734a63942b..2e16c2fec7f8357980cebdc74cfc78086d0a5328 100644
--- a/src/subgame.h
+++ b/src/subgame.h
@@ -35,17 +35,26 @@ struct SubgameSpec
 	std::string gamemods_path; //path to mods of the game
 	std::set<std::string> addon_mods_paths; //paths to addon mods for this game
 	std::string name;
+	std::string menubackground_path;
+	std::string menuoverlay_path;
+	std::string menuicon_path;
 
 	SubgameSpec(const std::string &id_="",
 			const std::string &path_="",	
 			const std::string &gamemods_path_="",
 			const std::set<std::string> &addon_mods_paths_=std::set<std::string>(),
-			const std::string &name_=""):
+			const std::string &name_="",
+			const std::string &menubackground_path_="",
+			const std::string &menuoverlay_path_="",
+			const std::string &menuicon_path_=""):
 		id(id_),
 		path(path_),
 		gamemods_path(gamemods_path_),		
 		addon_mods_paths(addon_mods_paths_),
-		name(name_)
+		name(name_),
+		menubackground_path(menubackground_path_),
+		menuoverlay_path(menuoverlay_path_),
+		menuicon_path(menuicon_path_)
 	{}
 
 	bool isValid() const
diff --git a/src/tile.cpp b/src/tile.cpp
index 39f47962e9da676f07fd09c5216b08ff0499f984..5f25e123bdd21556029e407cd81304a7e3cbee91 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -77,7 +77,7 @@ static bool replace_ext(std::string &path, const char *ext)
 
 	If failed, return "".
 */
-static std::string getImagePath(std::string path)
+std::string getImagePath(std::string path)
 {
 	// A NULL-ended list of possible image extensions
 	const char *extensions[] = {
diff --git a/src/tile.h b/src/tile.h
index ea5c4be54b4598d1aeadede016ed27a114448205..531a93172894a3639f33fdcf95a9874b677b8d1e 100644
--- a/src/tile.h
+++ b/src/tile.h
@@ -34,6 +34,17 @@ class IGameDef;
 	tile.{h,cpp}: Texture handling stuff.
 */
 
+/*
+	Find out the full path of an image by trying different filename
+	extensions.
+
+	If failed, return "".
+
+	TODO: Should probably be moved out from here, because things needing
+	      this function do not need anything else from this header
+*/
+std::string getImagePath(std::string path);
+
 /*
 	Gets the path to a texture by first checking if the texture exists
 	in texture_path and if not, using the data path.