From a888b232fe1315e4922c541f30b214647511bb93 Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Sat, 4 May 2013 10:03:56 +0300
Subject: [PATCH] Add header.png and footer.png support for games, and support
 texture packs via <gameid>_menu_<background/overlay/header/footer>.png

---
 src/main.cpp    | 141 ++++++++++++++++++++++++++++++++++++++++--------
 src/subgame.cpp |   6 +--
 src/subgame.h   |   6 ---
 3 files changed, 121 insertions(+), 32 deletions(-)

diff --git a/src/main.cpp b/src/main.cpp
index 501e4cdf4..3cf6728e4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -612,15 +612,53 @@ class RandomInputHandler : public InputHandler
 	bool rightreleased;
 };
 
-void drawMenuBackground(video::IVideoDriver* driver, const SubgameSpec *spec)
+struct MenuTextures
 {
-	v2u32 screensize = driver->getScreenSize();
+	std::string current_gameid;
+	video::ITexture *background;
+	video::ITexture *overlay;
+	video::ITexture *header;
+	video::ITexture *footer;
+
+	MenuTextures():
+		background(NULL),
+		overlay(NULL),
+		header(NULL),
+		footer(NULL)
+	{}
 
-	/* Figure out background texture */
-	video::ITexture *texture = NULL;
-	if(spec && spec->menubackground_path != ""){
-		texture = driver->getTexture(spec->menubackground_path.c_str());
+	static video::ITexture* getMenuTexture(const std::string &tname,
+			video::IVideoDriver* driver, const SubgameSpec *spec)
+	{
+		std::string path;
+		// eg. minetest_menu_background.png (for texture packs)
+		std::string pack_tname = spec->id + "_menu_" + tname + ".png";
+		path = getTexturePath(pack_tname);
+		if(path != "")
+			return driver->getTexture(path.c_str());
+		// eg. games/minetest_game/menu/background.png
+		path = getImagePath(spec->path + DIR_DELIM + "menu" + DIR_DELIM + tname + ".png");
+		if(path != "")
+			return driver->getTexture(path.c_str());
+		return NULL;
+	}
+
+	void update(video::IVideoDriver* driver, const SubgameSpec *spec)
+	{
+		if(spec->id == current_gameid)
+			return;
+		current_gameid = spec->id;
+		background = getMenuTexture("background", driver, spec);
+		overlay = getMenuTexture("overlay", driver, spec);
+		header = getMenuTexture("header", driver, spec);
+		footer = getMenuTexture("footer", driver, spec);
 	}
+};
+
+void drawMenuBackground(video::IVideoDriver* driver, const MenuTextures &menutextures)
+{
+	v2u32 screensize = driver->getScreenSize();
+	video::ITexture *texture = menutextures.background;
 
 	/* If no texture, draw background of solid color */
 	if(!texture){
@@ -638,15 +676,10 @@ void drawMenuBackground(video::IVideoDriver* driver, const SubgameSpec *spec)
 		NULL, NULL, true);
 }
 
-void drawMenuOverlay(video::IVideoDriver* driver, const SubgameSpec *spec)
+void drawMenuOverlay(video::IVideoDriver* driver, const MenuTextures &menutextures)
 {
 	v2u32 screensize = driver->getScreenSize();
-
-	/* Figure out overlay texture */
-	video::ITexture *texture = NULL;
-	if(spec && spec->menuoverlay_path != ""){
-		texture = driver->getTexture(spec->menuoverlay_path.c_str());
-	}
+	video::ITexture *texture = menutextures.overlay;
 
 	/* If no texture, draw nothing */
 	if(!texture)
@@ -660,6 +693,66 @@ void drawMenuOverlay(video::IVideoDriver* driver, const SubgameSpec *spec)
 		NULL, NULL, true);
 }
 
+void drawMenuHeader(video::IVideoDriver* driver, const MenuTextures &menutextures)
+{
+	core::dimension2d<u32> screensize = driver->getScreenSize();
+	video::ITexture *texture = menutextures.header;
+
+	/* If no texture, draw nothing */
+	if(!texture)
+		return;
+
+	f32 mult = (((f32)screensize.Width / 2)) /
+		((f32)texture->getOriginalSize().Width);
+
+	v2s32 splashsize(((f32)texture->getOriginalSize().Width) * mult,
+			((f32)texture->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);
+
+		video::SColor bgcolor(255,50,50,50);
+
+		driver->draw2DImage(texture, splashrect,
+			core::rect<s32>(core::position2d<s32>(0,0),
+			core::dimension2di(texture->getSize())),
+			NULL, NULL, true);
+	}
+}
+
+void drawMenuFooter(video::IVideoDriver* driver, const MenuTextures &menutextures)
+{
+	core::dimension2d<u32> screensize = driver->getScreenSize();
+	video::ITexture *texture = menutextures.footer;
+
+	/* If no texture, draw nothing */
+	if(!texture)
+		return;
+
+	f32 mult = (((f32)screensize.Width)) /
+		((f32)texture->getOriginalSize().Width);
+
+	v2s32 footersize(((f32)texture->getOriginalSize().Width) * mult,
+			((f32)texture->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(texture, rect,
+			core::rect<s32>(core::position2d<s32>(0,0),
+			core::dimension2di(texture->getSize())),
+			NULL, NULL, true);
+	}
+}
+
 static const SubgameSpec* getMenuGame(const MainMenuData &menudata)
 {
 	for(size_t i=0; i<menudata.games.size(); i++){
@@ -1567,6 +1660,9 @@ int main(int argc, char *argv[])
 				}
 				const SubgameSpec *menugame = getMenuGame(menudata);
 
+				MenuTextures menutextures;
+				menutextures.update(driver, menugame);
+
 				if(skip_main_menu == false)
 				{
 					video::IVideoDriver* driver = device->getVideoDriver();
@@ -1578,7 +1674,7 @@ int main(int argc, char *argv[])
 							break;
 						driver->beginScene(true, true,
 								video::SColor(255,128,128,128));
-						drawMenuBackground(driver, menugame);
+						drawMenuBackground(driver, menutextures);
 						guienv->drawAll();
 						driver->endScene();
 						// On some computers framerate doesn't seem to be
@@ -1628,18 +1724,17 @@ int main(int argc, char *argv[])
 
 						// Game can be selected in the menu
 						menugame = getMenuGame(menudata);
+						menutextures.update(driver, menugame);
 						// 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()){
+							if(cloud_menu_background && menutextures.background &&
+									!menutextures.overlay){
 								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()){
+							else if(menutextures.overlay && !menutextures.background){
 								cloud_menu_background = true;
 							}
 						}
@@ -1663,9 +1758,13 @@ int main(int argc, char *argv[])
 							clouds->step(dtime*3); 
 							clouds->render();
 							smgr->drawAll();
-							drawMenuOverlay(driver, menugame);
+							drawMenuOverlay(driver, menutextures);
+							drawMenuHeader(driver, menutextures);
+							drawMenuFooter(driver, menutextures);
 						} else {
-							drawMenuBackground(driver, menugame);
+							drawMenuBackground(driver, menutextures);
+							drawMenuHeader(driver, menutextures);
+							drawMenuFooter(driver, menutextures);
 						}
 
 						guienv->drawAll();
diff --git a/src/subgame.cpp b/src/subgame.cpp
index 1bee630b2..cdb546619 100644
--- a/src/subgame.cpp
+++ b/src/subgame.cpp
@@ -97,16 +97,12 @@ SubgameSpec findSubgame(const std::string &id)
 	std::string game_name = getGameName(game_path);
 	if(game_name == "")
 		game_name = id;
-	std::string menubackground_path;
-	std::string menuoverlay_path;
 	std::string menuicon_path;
 #ifndef SERVER
-	menubackground_path = getImagePath(game_path + DIR_DELIM + "menu" + DIR_DELIM + "background.png");
-	menuoverlay_path = getImagePath(game_path + DIR_DELIM + "menu" + DIR_DELIM + "overlay.png");
 	menuicon_path = getImagePath(game_path + DIR_DELIM + "menu" + DIR_DELIM + "icon.png");
 #endif
 	return SubgameSpec(id, game_path, gamemod_path, mods_paths, game_name,
-			menubackground_path, menuoverlay_path, menuicon_path);
+			menuicon_path);
 }
 
 SubgameSpec findWorldSubgame(const std::string &world_path)
diff --git a/src/subgame.h b/src/subgame.h
index 2e16c2fec..4b15faa8d 100644
--- a/src/subgame.h
+++ b/src/subgame.h
@@ -35,8 +35,6 @@ 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_="",
@@ -44,16 +42,12 @@ struct SubgameSpec
 			const std::string &gamemods_path_="",
 			const std::set<std::string> &addon_mods_paths_=std::set<std::string>(),
 			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_),
-		menubackground_path(menubackground_path_),
-		menuoverlay_path(menuoverlay_path_),
 		menuicon_path(menuicon_path_)
 	{}
 
-- 
GitLab