From 81c863ac4df1530123ef7952713623dadb049bec Mon Sep 17 00:00:00 2001
From: Zeg9 <dazeg9@gmail.com>
Date: Thu, 9 May 2013 18:23:48 +0200
Subject: [PATCH] Add clouds to all loading screens and better progress
 handling

---
 src/game.cpp | 188 ++++++++++++++++++++++++++++++++++-----------------
 src/main.cpp |  44 +++++++-----
 src/main.h   |   8 +++
 3 files changed, 161 insertions(+), 79 deletions(-)

diff --git a/src/game.cpp b/src/game.cpp
index 61e4963c0..81f35d4c0 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -396,12 +396,11 @@ PointedThing getPointedThing(Client *client, v3f player_position,
 	Draws a screen with a single text on it.
 	Text will be removed when the screen is drawn the next time.
 	Additionally, a progressbar can be drawn when percent is set between 0 and 100.
-	With drawsmgr, you can for example draw clouds
 */
 /*gui::IGUIStaticText **/
 void draw_load_screen(const std::wstring &text,
 		IrrlichtDevice* device, gui::IGUIFont* font,
-		int percent=-1, bool drawsmgr=false)
+		float dtime=0 ,int percent=0, bool clouds=true)
 {
 	video::IVideoDriver* driver = device->getVideoDriver();
 	v2u32 screensize = driver->getScreenSize();
@@ -415,11 +414,13 @@ void draw_load_screen(const std::wstring &text,
 			loadingtext, textrect, false, false);
 	guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
 
-	if (drawsmgr)
+	bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
+	if (cloud_menu_background)
 	{
+		g_menuclouds->step(dtime*3);
+		g_menuclouds->render();
 		driver->beginScene(true, true, video::SColor(255,140,186,250));
-		scene::ISceneManager* smgr = device->getSceneManager();
-		smgr->drawAll();
+		g_menucloudsmgr->drawAll();
 	}
 	else
 		driver->beginScene(true, true, video::SColor(255,0,0,0));
@@ -428,7 +429,7 @@ void draw_load_screen(const std::wstring &text,
 		core::vector2d<s32> barsize(256,32);
 		core::rect<s32> barrect(center-barsize/2, center+barsize/2);
 		driver->draw2DRectangle(video::SColor(255,255,255,255),barrect, NULL); // border
-		driver->draw2DRectangle(video::SColor(255,0,0,0), core::rect<s32> (
+		driver->draw2DRectangle(video::SColor(255,64,64,64), core::rect<s32> (
 				barrect.UpperLeftCorner+1,
 				barrect.LowerRightCorner-1), NULL); // black inside the bar
 		driver->draw2DRectangle(video::SColor(255,128,128,128), core::rect<s32> (
@@ -907,7 +908,11 @@ void the_game(
 		Draw "Loading" screen
 	*/
 
-	draw_load_screen(L"Loading...", device, font);
+	{
+		wchar_t* text = wgettext("Loading...");
+		draw_load_screen(text, device, font,0,0);
+		delete[] text;
+	}
 	
 	// Create texture source
 	IWritableTextureSource *tsrc = createTextureSource(device);
@@ -964,7 +969,9 @@ void the_game(
 	*/
 
 	if(address == ""){
-		draw_load_screen(L"Creating server...", device, font);
+		wchar_t* text = wgettext("Creating server....");
+		draw_load_screen(text, device, font,0,25);
+		delete[] text;
 		infostream<<"Creating server"<<std::endl;
 		server = new Server(map_dir, configpath, gamespec,
 				simple_singleplayer_mode);
@@ -977,7 +984,11 @@ void the_game(
 		Create client
 	*/
 
-	draw_load_screen(L"Creating client...", device, font);
+	{
+		wchar_t* text = wgettext("Creating client...");
+		draw_load_screen(text, device, font,0,50);
+		delete[] text;
+	}
 	infostream<<"Creating client"<<std::endl;
 	
 	MapDrawControl draw_control;
@@ -987,8 +998,12 @@ void the_game(
 	
 	// Client acts as our GameDef
 	IGameDef *gamedef = &client;
-			
-	draw_load_screen(L"Resolving address...", device, font);
+	
+	{
+		wchar_t* text = wgettext("Resolving address...");
+		draw_load_screen(text, device, font,0,75);
+		delete[] text;
+	}
 	Address connect_address(0,0,0,0, port);
 	try{
 		if(address == "")
@@ -1020,15 +1035,26 @@ void the_game(
 	bool could_connect = false;
 	bool connect_aborted = false;
 	try{
-		float frametime = 0.033;
 		float time_counter = 0.0;
 		input->clear();
+		float fps_max = g_settings->getFloat("fps_max");
+		bool cloud_menu_background = g_settings->getBool("menu_clouds");
+		u32 lasttime = device->getTimer()->getTime();
 		while(device->run())
 		{
+			f32 dtime=0; // in seconds
+			if (cloud_menu_background) {
+				u32 time = device->getTimer()->getTime();
+				if(time > lasttime)
+					dtime = (time - lasttime) / 1000.0;
+				else
+					dtime = 0;
+				lasttime = time;
+			}
 			// Update client and server
-			client.step(frametime);
+			client.step(dtime);
 			if(server != NULL)
-				server->step(frametime);
+				server->step(dtime);
 			
 			// End condition
 			if(client.connectedAndInitialized()){
@@ -1049,15 +1075,37 @@ void the_game(
 			}
 			
 			// Display status
-			std::wostringstream ss;
-			ss<<L"Connecting to server... (press Escape to cancel)\n";
-			std::wstring animation = L"/-\\|";
-			ss<<animation[(int)(time_counter/0.2)%4];
-			draw_load_screen(ss.str(), device, font);
+			{
+				wchar_t* text = wgettext("Connecting to server...");
+				draw_load_screen(text, device, font, dtime, 100);
+				delete[] text;
+			}
 			
-			// Delay a bit
-			sleep_ms(1000*frametime);
-			time_counter += frametime;
+			// On some computers framerate doesn't seem to be
+			// automatically limited
+			if (cloud_menu_background) {
+				// Time of frame without fps limit
+				float busytime;
+				u32 busytime_u32;
+				// not using getRealTime is necessary for wine
+				u32 time = device->getTimer()->getTime();
+				if(time > lasttime)
+					busytime_u32 = time - lasttime;
+				else
+					busytime_u32 = 0;
+				busytime = busytime_u32 / 1000.0;
+
+				// FPS limiter
+				u32 frametime_min = 1000./fps_max;
+
+				if(busytime_u32 < frametime_min) {
+					u32 sleeptime = frametime_min - busytime_u32;
+					device->sleep(sleeptime);
+				}
+			} else {
+				sleep_ms(25);
+			}
+			time_counter += dtime;
 		}
 	}
 	catch(con::PeerNotFoundException &e)
@@ -1081,32 +1129,26 @@ void the_game(
 	bool got_content = false;
 	bool content_aborted = false;
 	{
-		float frametime = 0.033;
 		float time_counter = 0.0;
 		input->clear();
-		
-		scene::ISceneManager* smgr = device->getSceneManager();
-		Clouds *clouds = 0;
-		if (g_settings->getBool("menu_clouds"))
-		{
-			// add 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);
-		}
-		
+		float fps_max = g_settings->getFloat("fps_max");
+		bool cloud_menu_background = g_settings->getBool("menu_clouds");
+		u32 lasttime = device->getTimer()->getTime();
 		while(device->run())
 		{
+			f32 dtime=0; // in seconds
+			if (cloud_menu_background) {
+				u32 time = device->getTimer()->getTime();
+				if(time > lasttime)
+					dtime = (time - lasttime) / 1000.0;
+				else
+					dtime = 0;
+				lasttime = time;
+			}
 			// Update client and server
-			client.step(frametime);
+			client.step(dtime);
 			if(server != NULL)
-				server->step(frametime);
+				server->step(dtime);
 			
 			// End condition
 			if(client.texturesReceived() &&
@@ -1128,30 +1170,52 @@ void the_game(
 			}
 			
 			// Display status
-			std::wostringstream ss;
+			std::ostringstream ss;
+			int progress=0;
 			if (!client.itemdefReceived())
-				ss << L"Item definitions...";
+			{
+				ss << "Item definitions...";
+				progress = 0;
+			}
 			else if (!client.nodedefReceived())
-				ss << L"Node definitions...";
+			{
+				ss << "Node definitions...";
+				progress = 25;
+			}
 			else
-				ss << L"Media (" << (int)(client.mediaReceiveProgress()*100+0.5) << L"%)...";
-			
-			if (clouds != 0)
 			{
-				clouds->step(frametime*3); 
-				clouds->render();
+				ss << "Media...";
+				progress = 50+client.mediaReceiveProgress()*50+0.5;
 			}
+			wchar_t* text = wgettext(ss.str().c_str());
+			draw_load_screen(text, device, font, dtime, progress);
+			delete[] text;
 			
-			draw_load_screen(ss.str(), device, font, client.mediaReceiveProgress()*100+0.5, clouds!=0);
-			
-			// Delay a bit
-			sleep_ms(1000*frametime);
-			time_counter += frametime;
-		}
-		if (clouds != 0)
-		{
-			smgr->addToDeletionQueue(clouds);
-			clouds->drop();
+			// On some computers framerate doesn't seem to be
+			// automatically limited
+			if (cloud_menu_background) {
+				// Time of frame without fps limit
+				float busytime;
+				u32 busytime_u32;
+				// not using getRealTime is necessary for wine
+				u32 time = device->getTimer()->getTime();
+				if(time > lasttime)
+					busytime_u32 = time - lasttime;
+				else
+					busytime_u32 = 0;
+				busytime = busytime_u32 / 1000.0;
+
+				// FPS limiter
+				u32 frametime_min = 1000./fps_max;
+
+				if(busytime_u32 < frametime_min) {
+					u32 sleeptime = frametime_min - busytime_u32;
+					device->sleep(sleeptime);
+				}
+			} else {
+				sleep_ms(25);
+			}
+			time_counter += dtime;
 		}
 	}
 
@@ -3278,7 +3342,9 @@ void the_game(
 	*/
 	{
 		/*gui::IGUIStaticText *gui_shuttingdowntext = */
-		draw_load_screen(L"Shutting down stuff...", device, font);
+		wchar_t* text = wgettext("Shutting down stuff...");
+		draw_load_screen(text, device, font, 0, -1, false);
+		delete[] text;
 		/*driver->beginScene(true, true, video::SColor(255,0,0,0));
 		guienv->drawAll();
 		driver->endScene();
diff --git a/src/main.cpp b/src/main.cpp
index b87a3e6d0..94382ec60 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -88,6 +88,10 @@ Settings *g_settings = &main_settings;
 Profiler main_profiler;
 Profiler *g_profiler = &main_profiler;
 
+// Menu clouds are created later
+Clouds *g_menuclouds = 0;
+irr::scene::ISceneManager *g_menucloudsmgr = 0;
+
 /*
 	Debug streams
 */
@@ -1569,6 +1573,19 @@ int main(int argc, char *argv[])
 	skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255,96,134,49));
 #endif
 
+
+	// Create the menu clouds
+	if (!g_menucloudsmgr)
+		g_menucloudsmgr = smgr->createNewSceneManager();
+	if (!g_menuclouds)
+		g_menuclouds = new Clouds(g_menucloudsmgr->getRootSceneNode(),
+			g_menucloudsmgr, -1, rand(), 100);
+	g_menuclouds->update(v2f(0, 0), video::SColor(255,200,200,255));
+	scene::ICameraSceneNode* camera;
+	camera = g_menucloudsmgr->addCameraSceneNode(0,
+				v3f(0,0,0), v3f(0, 60, 100));
+	camera->setFarValue(10000);
+
 	/*
 		GUI stuff
 	*/
@@ -1744,18 +1761,6 @@ int main(int argc, char *argv[])
 								&g_menumgr, &menudata, g_gamecallback);
 					menu->allowFocusRemoval(true);
 
-					// 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"")
 					{
 						verbosestream<<"error_message = "
@@ -1796,7 +1801,7 @@ int main(int argc, char *argv[])
 						}
 
 						// Time calc for the clouds
-						f32 dtime; // in seconds
+						f32 dtime=0; // in seconds
 						if (cloud_menu_background) {
 							u32 time = device->getTimer()->getTime();
 							if(time > lasttime)
@@ -1811,9 +1816,9 @@ int main(int argc, char *argv[])
 
 						if (cloud_menu_background) {
 							// *3 otherwise the clouds would move very slowly
-							clouds->step(dtime*3); 
-							clouds->render();
-							smgr->drawAll();
+							g_menuclouds->step(dtime*3); 
+							g_menuclouds->render();
+							g_menucloudsmgr->drawAll();
 							drawMenuOverlay(driver, menutextures);
 							drawMenuHeader(driver, menutextures);
 							drawMenuFooter(driver, menutextures);
@@ -1856,8 +1861,6 @@ int main(int argc, char *argv[])
 					infostream<<"Dropping main menu"<<std::endl;
 
 					menu->drop();
-					clouds->drop();
-					smgr->clear();
 				}
 
 				playername = wide_to_narrow(menudata.name);
@@ -2018,6 +2021,7 @@ int main(int argc, char *argv[])
 				gamespec,
 				simple_singleplayer_mode
 			);
+			smgr->clear();
 
 		} //try
 		catch(con::PeerNotFoundException &e)
@@ -2048,6 +2052,10 @@ int main(int argc, char *argv[])
 		}
 	} // Menu-game loop
 	
+	
+	g_menuclouds->drop();
+	g_menucloudsmgr->drop();
+	
 	delete input;
 
 	/*
diff --git a/src/main.h b/src/main.h
index daa8c70d2..df67a6348 100644
--- a/src/main.h
+++ b/src/main.h
@@ -28,6 +28,14 @@ extern Settings *g_settings;
 class Profiler;
 extern Profiler *g_profiler;
 
+// Menu clouds
+class Clouds;
+extern Clouds *g_menuclouds;
+
+// Scene manager used for menu clouds
+namespace irr{namespace scene{class ISceneManager;}}
+extern irr::scene::ISceneManager *g_menucloudsmgr;
+
 // Debug streams
 
 #include <fstream>
-- 
GitLab