From 21f1bec72433748e220d19e97a846df83340518e Mon Sep 17 00:00:00 2001
From: RealBadAngel <maciej.kasatkin@yahoo.com>
Date: Sun, 26 Jan 2014 21:31:59 +0100
Subject: New HUD element - waypoint.

---
 src/client.cpp                  |  9 +++++++++
 src/client.h                    |  2 ++
 src/game.cpp                    | 10 +++++++++-
 src/hud.cpp                     | 35 ++++++++++++++++++++++++++++++++---
 src/hud.h                       | 13 +++++++++----
 src/script/lua_api/l_object.cpp | 13 +++++++++++++
 src/server.cpp                  |  4 ++++
 7 files changed, 78 insertions(+), 8 deletions(-)

(limited to 'src')

diff --git a/src/client.cpp b/src/client.cpp
index b2709b6f0..6c4d9eea8 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -1941,6 +1941,10 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
 		u32 dir          = readU32(is);
 		v2f align        = readV2F1000(is);
 		v2f offset       = readV2F1000(is);
+		v3f world_pos;
+		try{
+			world_pos    = readV3F1000(is);
+		}catch(SerializationError &e) {};
 
 		ClientEvent event;
 		event.type = CE_HUDADD;
@@ -1955,6 +1959,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
 		event.hudadd.dir    = dir;
 		event.hudadd.align  = new v2f(align);
 		event.hudadd.offset = new v2f(offset);
+		event.hudadd.world_pos = new v3f(world_pos);
 		m_client_event_queue.push_back(event);
 	}
 	else if(command == TOCLIENT_HUDRM)
@@ -1973,6 +1978,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
 	{
 		std::string sdata;
 		v2f v2fdata;
+		v3f v3fdata;
 		u32 intdata = 0;
 		
 		std::string datastring((char *)&data[2], datasize - 2);
@@ -1986,6 +1992,8 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
 			v2fdata = readV2F1000(is);
 		else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
 			sdata = deSerializeString(is);
+		else if (stat == HUD_STAT_WORLD_POS)
+			v3fdata = readV3F1000(is);
 		else
 			intdata = readU32(is);
 		
@@ -1994,6 +2002,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
 		event.hudchange.id      = id;
 		event.hudchange.stat    = (HudElementStat)stat;
 		event.hudchange.v2fdata = new v2f(v2fdata);
+		event.hudchange.v3fdata = new v3f(v3fdata);
 		event.hudchange.sdata   = new std::string(sdata);
 		event.hudchange.data    = intdata;
 		m_client_event_queue.push_back(event);
diff --git a/src/client.h b/src/client.h
index 7f13c8149..9a788dfca 100644
--- a/src/client.h
+++ b/src/client.h
@@ -204,6 +204,7 @@ struct ClientEvent
 			u32 dir;
 			v2f *align;
 			v2f *offset;
+			v3f *world_pos;
 		} hudadd;
 		struct{
 			u32 id;
@@ -214,6 +215,7 @@ struct ClientEvent
 			v2f *v2fdata;
 			std::string *sdata;
 			u32 data;
+			v3f *v3fdata;
 		} hudchange;
 	};
 };
diff --git a/src/game.cpp b/src/game.cpp
index 16fd42f16..407672ac2 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1486,7 +1486,7 @@ void the_game(
 	/*
 		HUD object
 	*/
-	Hud hud(driver, guienv, font, text_height,
+	Hud hud(driver, smgr, guienv, font, text_height,
 			gamedef, player, &local_inventory);
 
 	bool use_weather = g_settings->getBool("weather");
@@ -2376,6 +2376,7 @@ void the_game(
 						delete event.hudadd.text;
 						delete event.hudadd.align;
 						delete event.hudadd.offset;
+						delete event.hudadd.world_pos;
 						continue;
 					}
 					
@@ -2390,6 +2391,7 @@ void the_game(
 					e->dir    = event.hudadd.dir;
 					e->align  = *event.hudadd.align;
 					e->offset = *event.hudadd.offset;
+					e->world_pos = *event.hudadd.world_pos;
 					
 					if (id == nhudelem)
 						player->hud.push_back(e);
@@ -2402,6 +2404,7 @@ void the_game(
 					delete event.hudadd.text;
 					delete event.hudadd.align;
 					delete event.hudadd.offset;
+					delete event.hudadd.world_pos;
 				}
 				else if (event.type == CE_HUDRM)
 				{
@@ -2415,6 +2418,7 @@ void the_game(
 				{
 					u32 id = event.hudchange.id;
 					if (id >= player->hud.size() || !player->hud[id]) {
+						delete event.hudchange.v3fdata;
 						delete event.hudchange.v2fdata;
 						delete event.hudchange.sdata;
 						continue;
@@ -2449,8 +2453,12 @@ void the_game(
 						case HUD_STAT_OFFSET:
 							e->offset = *event.hudchange.v2fdata;
 							break;
+						case HUD_STAT_WORLD_POS:
+							e->world_pos = *event.hudchange.v3fdata;
+							break;
 					}
 					
+					delete event.hudchange.v3fdata;
 					delete event.hudchange.v2fdata;
 					delete event.hudchange.sdata;
 				}
diff --git a/src/hud.cpp b/src/hud.cpp
index 183f94e49..80112a6ec 100644
--- a/src/hud.cpp
+++ b/src/hud.cpp
@@ -29,14 +29,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "inventory.h"
 #include "tile.h"
 #include "localplayer.h"
+#include "camera.h"
 
 #include <IGUIStaticText.h>
 
 
-Hud::Hud(video::IVideoDriver *driver, gui::IGUIEnvironment* guienv,
-		gui::IGUIFont *font, u32 text_height, IGameDef *gamedef,
+Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr,
+		gui::IGUIEnvironment* guienv, gui::IGUIFont *font,
+		u32 text_height, IGameDef *gamedef,
 		LocalPlayer *player, Inventory *inventory) {
 	this->driver      = driver;
+	this->smgr        = smgr;
 	this->guienv      = guienv;
 	this->font        = font;
 	this->text_height = text_height;
@@ -268,6 +271,33 @@ void Hud::drawLuaElements() {
 				InventoryList *inv = inventory->getList(e->text);
 				drawItem(pos, hotbar_imagesize, e->number, inv, e->item, e->dir);
 				break; }
+			case HUD_ELEM_WAYPOINT: {
+				v3f p_pos = player->getPosition() / BS;
+				v3f w_pos = e->world_pos * BS;
+				float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
+				scene::ICameraSceneNode* camera = smgr->getActiveCamera();
+				core::matrix4 trans = camera->getProjectionMatrix();
+				trans *= camera->getViewMatrix();
+				f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
+				trans.multiplyWith1x4Matrix(transformed_pos);
+				if (transformed_pos[3] < 0)
+					break;
+				f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
+					core::reciprocal(transformed_pos[3]);
+				pos.X = screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
+				pos.Y = screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
+				video::SColor color(255, (e->number >> 16) & 0xFF,
+										 (e->number >> 8)  & 0xFF,
+										 (e->number >> 0)  & 0xFF);
+				core::rect<s32> size(0, 0, 200, 2 * text_height);
+				std::wstring text = narrow_to_wide(e->name);
+				font->draw(text.c_str(), size + pos, color);
+				std::ostringstream os;
+				os<<distance<<e->text;
+				text = narrow_to_wide(os.str());
+				pos.Y += text_height;
+				font->draw(text.c_str(), size + pos, color);
+				break; }
 			default:
 				infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
 					" of hud element ID " << i << " due to unrecognized type" << std::endl;
@@ -477,4 +507,3 @@ void drawItemStack(video::IVideoDriver *driver,
 		font->draw(text.c_str(), rect2, color, false, false, clip);
 	}
 }
-
diff --git a/src/hud.h b/src/hud.h
index c69867a23..1a24d0945 100644
--- a/src/hud.h
+++ b/src/hud.h
@@ -49,7 +49,8 @@ enum HudElementType {
 	HUD_ELEM_IMAGE     = 0,
 	HUD_ELEM_TEXT      = 1,
 	HUD_ELEM_STATBAR   = 2,
-	HUD_ELEM_INVENTORY = 3
+	HUD_ELEM_INVENTORY = 3,
+	HUD_ELEM_WAYPOINT  = 4,
 };
 
 enum HudElementStat {
@@ -61,7 +62,8 @@ enum HudElementStat {
 	HUD_STAT_ITEM,
 	HUD_STAT_DIR,
 	HUD_STAT_ALIGN,
-	HUD_STAT_OFFSET
+	HUD_STAT_OFFSET,
+	HUD_STAT_WORLD_POS
 };
 
 struct HudElement {
@@ -75,6 +77,7 @@ struct HudElement {
 	u32 dir;
 	v2f align;
 	v2f offset;
+	v3f world_pos;
 };
 
 #ifndef SERVER
@@ -93,6 +96,7 @@ struct ItemStack;
 class Hud {
 public:
 	video::IVideoDriver *driver;
+	scene::ISceneManager* smgr;
 	gui::IGUIEnvironment *guienv;
 	gui::IGUIFont *font;
 	u32 text_height;
@@ -113,8 +117,9 @@ public:
 	std::string hotbar_selected_image;
 	bool use_hotbar_selected_image;
 	
-	Hud(video::IVideoDriver *driver, gui::IGUIEnvironment* guienv,
-		gui::IGUIFont *font, u32 text_height, IGameDef *gamedef,
+	Hud(video::IVideoDriver *driver,scene::ISceneManager* smgr,
+		gui::IGUIEnvironment* guienv, gui::IGUIFont *font,
+		u32 text_height, IGameDef *gamedef,
 		LocalPlayer *player, Inventory *inventory);
 	
 	void drawItem(v2s32 upperleftpos, s32 imgsize, s32 itemcount,
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index 6d4ce54fc..6c6415a09 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -38,6 +38,7 @@ struct EnumString es_HudElementType[] =
 	{HUD_ELEM_TEXT,      "text"},
 	{HUD_ELEM_STATBAR,   "statbar"},
 	{HUD_ELEM_INVENTORY, "inventory"},
+	{HUD_ELEM_WAYPOINT,  "waypoint"},
 {0, NULL},
 };
 
@@ -53,6 +54,7 @@ struct EnumString es_HudElementStat[] =
 	{HUD_STAT_DIR,    "direction"},
 	{HUD_STAT_ALIGN,  "alignment"},
 	{HUD_STAT_OFFSET, "offset"},
+	{HUD_STAT_WORLD_POS, "world_pos"},
 	{0, NULL},
 };
 
@@ -862,6 +864,10 @@ int ObjectRef::l_hud_add(lua_State *L)
 	elem->offset = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
 	lua_pop(L, 1);
 
+	lua_getfield(L, 2, "world_pos");
+	elem->world_pos = lua_istable(L, -1) ? read_v3f(L, -1) : v3f();
+	lua_pop(L, 1);
+
 	u32 id = getServer(L)->hudAdd(player, elem);
 	if (id == (u32)-1) {
 		delete elem;
@@ -953,6 +959,10 @@ int ObjectRef::l_hud_change(lua_State *L)
 			e->offset = read_v2f(L, 4);
 			value = &e->offset;
 			break;
+		case HUD_STAT_WORLD_POS:
+			e->world_pos = read_v3f(L, 4);
+			value = &e->world_pos;
+			break;
 	}
 
 	getServer(L)->hudChange(player, id, stat, value);
@@ -1003,6 +1013,9 @@ int ObjectRef::l_hud_get(lua_State *L)
 	lua_pushnumber(L, e->dir);
 	lua_setfield(L, -2, "dir");
 
+	push_v3f(L, e->world_pos);
+	lua_setfield(L, -2, "world_pos");
+
 	return 1;
 }
 
diff --git a/src/server.cpp b/src/server.cpp
index 0ada4d818..9fb0455eb 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -3724,6 +3724,7 @@ void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
 	writeU32(os, form->dir);
 	writeV2F1000(os, form->align);
 	writeV2F1000(os, form->offset);
+	writeV3F1000(os, form->world_pos);
 
 	// Make data buffer
 	std::string s = os.str();
@@ -3767,6 +3768,9 @@ void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value
 		case HUD_STAT_TEXT:
 			os << serializeString(*(std::string *)value);
 			break;
+		case HUD_STAT_WORLD_POS:
+			writeV3F1000(os, *(v3f *)value);
+			break;
 		case HUD_STAT_NUMBER:
 		case HUD_STAT_ITEM:
 		case HUD_STAT_DIR:
-- 
cgit v1.2.3