From ac3ca340c9502e2e0c83c75d5aba5211429e25ae Mon Sep 17 00:00:00 2001
From: Stijn Buys <ingar@osirion.org>
Date: Sun, 20 Jul 2008 23:10:08 +0000
Subject: targetting

---
 src/client/input.cc    |  63 +++++++++++++++-----------
 src/client/input.h     |   3 +-
 src/client/keyboard.cc |   2 +-
 src/client/targets.cc  | 117 +++++++++++++++++++++++++++++++++++++++----------
 src/client/targets.h   |   7 +++
 src/client/view.cc     |  69 +++++++++++++++++------------
 6 files changed, 183 insertions(+), 78 deletions(-)

(limited to 'src/client')

diff --git a/src/client/input.cc b/src/client/input.cc
index 3d9caa5..8075058 100644
--- a/src/client/input.cc
+++ b/src/client/input.cc
@@ -11,6 +11,7 @@
 #include "client/chat.h"
 #include "client/console.h"
 #include "client/keyboard.h"
+#include "client/targets.h"
 #include "client/video.h"
 #include "render/camera.h"
 #include "math/functions.h"
@@ -21,7 +22,7 @@
 namespace client
 {
 
-core::Cvar *cl_mousecontrol = 0;
+core::Cvar *input_mousecontrol = 0;
 
 namespace input
 {
@@ -31,7 +32,7 @@ namespace input
 Keyboard *keyboard = 0;
 
 //bool free_control = true;
-bool cl_mousecontrol_override = false;
+
 
 // local controls
 float local_direction = 0.0f;
@@ -51,7 +52,9 @@ float mouse_direction = 0;
 
 // true if the mouse is in the deadzone
 bool mouse_deadzone = false;
+
 // true if the mouse has control
+bool mouse_control_override = false;
 bool mouse_control = false;
 
 const float thruster_offset = 0.05f;
@@ -71,13 +74,13 @@ void func_ui_control(std::string const &args)
 	if (!core::localcontrol())
 		return;
 
-	if (cl_mousecontrol->value() > 0) {
-			(*cl_mousecontrol) = 0.0f;
+	if (input_mousecontrol->value() > 0) {
+			(*input_mousecontrol) = 0.0f;
 	} else {
-		(*cl_mousecontrol) = 1.0f;
+		(*input_mousecontrol) = 1.0f;
 	}
 
-	if (!cl_mousecontrol->value()) {
+	if (!input_mousecontrol->value()) {
 		local_direction = 0.0f;
 		local_pitch = 0.0f;
 		local_roll = 0.0f;
@@ -169,8 +172,8 @@ void init()
 	SDL_WM_GrabInput(SDL_GRAB_ON);
 //	SDL_EnableUNICODE(1);
 
-	cl_mousecontrol = core::Cvar::get("cl_mousecontrol", "1", core::Cvar::Archive);
-	cl_mousecontrol->set_info("[bool] set mouse control on or off");
+	input_mousecontrol = core::Cvar::get("input_mousecontrol", "1", core::Cvar::Archive);
+	input_mousecontrol->set_info("[bool] enable or disable mouse control");
 
 	core::Func *func = 0;
 
@@ -181,10 +184,10 @@ void init()
 	func->set_info("toggle chatbox on or of");
 
 	func = core::Func::add("ui_view", func_ui_view);
-	func->set_info("switch view mode");
+	func->set_info("switch camera view");
 
 	func = core::Func::add("ui_control",func_ui_control);
-	func->set_info("toggle mouse control on or off");
+	func->set_info("toggle mouse control");
 
 	func = core::Func::add("list_keys", func_list_keys);
 	func->set_info("list keyboard key names");
@@ -251,7 +254,7 @@ void action_press(std::string const &action)
 	
 	/* -- mouse control ------------------------------- */
 	} else if (action.compare("+control") == 0) {
-		cl_mousecontrol_override = true;
+		mouse_control_override = true;
 
 	/* -- directional control ------------------------- */
 	} else if (action.compare("+left") == 0) {
@@ -299,8 +302,8 @@ void action_release(std::string const &action)
 
 	/* -- mouse control ------------------------------- */
 	} else if (action.compare("+control") == 0) {
-		cl_mousecontrol_override = false;
-		if (!cl_mousecontrol->value()) {
+		mouse_control_override = false;
+		if (!input_mousecontrol->value()) {
 			local_direction = 0.0f;
 			local_pitch = 0.0f;
 			local_roll = 0.0f;
@@ -357,8 +360,8 @@ void frame(float seconds)
 		mouse_x = video::width / 2;
 		mouse_y = video::height / 2;
 		render::Camera::reset();
-		cl_mousecontrol_override = false;
-
+		mouse_control_override = false;
+		targets::reset();
 		render::reset();	
 	}
 
@@ -379,6 +382,7 @@ void frame(float seconds)
 				break;
 
 			case SDL_MOUSEBUTTONDOWN:
+				// override for gui mouse down
 				key = keyboard->press(512 + event.button.button);
 				pressed = true;
 				break;
@@ -411,8 +415,10 @@ void frame(float seconds)
 				if (keysym.mod & KMOD_CAPS) capslock = true; else capslock = false;
 				if ((keysym.mod & KMOD_LSHIFT) || (keysym.mod & KMOD_RSHIFT)) capslock != capslock;
 */
-				// console key is always captured
-				if (key->bind().compare("ui_console") == 0) {
+				// FIXME console key is always captured
+				// FIXME ESC should escape to gui
+
+				if ((key->sym() == SDLK_ESCAPE) || (key->bind().compare("ui_console") == 0)) {
 					console()->toggle();
 					local_direction = 0.0f;
 					local_pitch = 0.0f;
@@ -433,15 +439,22 @@ void frame(float seconds)
 	
 				} else if (core::application()->connected() && core::localcontrol()) {
 
-					char c = key->bind().c_str()[0];
-					if (c == '+' || c == '-') {
-						// action bind
-						action_press(key->bind());
+					if ((key->sym() ==  512 + SDL_BUTTON_LEFT) && targets::hover()) {
+						// hovering target selected
+						targets::select_target(targets::hover());
 
-					} else if (c) {
-						// normal bind
-						core::cmd() << key->bind() << "\n";
+					} else {
+						char c = key->bind().c_str()[0];
+						if (c == '+' || c == '-') {
+							// action bind
+							action_press(key->bind());
+	
+						} else if (c) {
+							// normal bind
+							core::cmd() << key->bind() << "\n";
+						}
 					}
+
 				} else if (core::application()->connected()) {
 					
 					char c = key->bind().c_str()[0];
@@ -470,7 +483,7 @@ void frame(float seconds)
 
 	if (core::application()->connected() && core::localcontrol()) {
 
-		mouse_control = !console()->visible() && ((cl_mousecontrol->value() > 0) || cl_mousecontrol_override);
+		mouse_control = !console()->visible() && ((input_mousecontrol->value() > 0) || mouse_control_override);
 
 		if (mouse_control) {
 			// the mouse will not react if it is in the deadzone
diff --git a/src/client/input.h b/src/client/input.h
index 201f4e9..96192f8 100644
--- a/src/client/input.h
+++ b/src/client/input.h
@@ -29,10 +29,11 @@ extern int mouse_y;
 
 extern bool mouse_deadzone;
 extern bool mouse_control;
+extern bool mouse_control_override;
 
 } // namespace input
 
-extern core::Cvar *cl_mousecontrol;
+extern core::Cvar *input_mousecontrol;
 
 } // namespace client
 
diff --git a/src/client/keyboard.cc b/src/client/keyboard.cc
index 4237b20..8295fce 100644
--- a/src/client/keyboard.cc
+++ b/src/client/keyboard.cc
@@ -32,7 +32,7 @@ Keyboard::Keyboard()
    	add_key("clear", SDLK_CLEAR);
    	add_key("enter", SDLK_RETURN);
    	add_key("pause", SDLK_PAUSE);
-   	add_key("escape", SDLK_ESCAPE);
+   	add_key("esc", SDLK_ESCAPE);
    	add_key("space", SDLK_SPACE, ' ', "ui_control");
    	add_key("!", SDLK_EXCLAIM, '!');
    	add_key("\"", SDLK_QUOTEDBL, '"');
diff --git a/src/client/targets.cc b/src/client/targets.cc
index 418ca47..1264cbb 100644
--- a/src/client/targets.cc
+++ b/src/client/targets.cc
@@ -14,14 +14,16 @@
 
 #include "audio/audio.h"
 #include "audio/sources.h"
+#include "client/input.h"
 #include "client/view.h"
+#include "client/video.h"
 #include "core/application.h"
-#include "core/gameinterface.h"
 #include "core/entity.h"
 #include "core/func.h"
+#include "core/gameinterface.h"
 #include "math/vector3f.h"
-#include "render/render.h"
 #include "render/gl.h"
+#include "render/render.h"
 #include "render/text.h"
 
 namespace client {
@@ -30,9 +32,12 @@ namespace targets {
 
 const float TARGETBOXRADIUS = 0.025f;
 unsigned int current_target_id = 0;
+unsigned int current_hover = 0;
+
 core::Entity *current_target = 0;
 core::Cvar *snd_engines = 0;
 
+
 bool is_legal_target(core::Entity *entity)
 {
 	if (entity->id() == core::localcontrol()->id())
@@ -41,6 +46,31 @@ bool is_legal_target(core::Entity *entity)
 		return true;
 }
 
+core::Entity* current()
+{
+	return current_target;
+}
+
+unsigned int hover()
+{
+	return current_hover;
+}
+
+void select_target(core::Entity *entity)
+{
+	current_target = entity;
+	current_target_id = current_target->id();
+	core::application()->notify_sound("ui/target");
+}
+
+void select_target(unsigned int id)
+{
+	// FIXME validate
+	core::Entity * entity = core::Entity::find(id);
+	if (entity)
+		select_target(entity);
+}
+
 void func_target_next(std::string const &args)
 {
 	if (!core::localcontrol())
@@ -83,9 +113,7 @@ void func_target_next(std::string const &args)
 	}
 
 	if (it !=  core::Entity::registry.end()) {
-		current_target = (*it).second;
-		current_target_id = current_target->id();
-		core::application()->notify_sound("ui/target");
+		select_target((*it).second);
 	} else {
 		current_target = 0;
 		current_target_id = 0;
@@ -134,19 +162,20 @@ void func_target_prev(std::string const &args)
 	}
 
 	if (rit != core::Entity::registry.rend()) {
-		current_target = (*rit).second;
-		current_target_id = current_target->id();
-		core::application()->notify_sound("ui/target");
+		select_target((*rit).second);
+
 	} else {
 		current_target = 0;
 		current_target_id = 0;
-	
 	}
 }
 
-core::Entity* current()
+void reset()
 {
-	return current_target;
+	current_target = 0;
+	current_target_id = 0;
+	current_hover = 0;
+	
 }
 
 void init()
@@ -162,25 +191,17 @@ void init()
 	core::Func::add("target_prev", func_target_prev);
 	func->set_info("select previous target");
 
-	current_target = 0;
-	current_target_id = 0;
+	reset();
 }
 
 void shutdown()
 {
-	current_target = 0;
-	current_target_id = 0;
+	reset();
 
 	core::Func::remove("target_next");
 	core::Func::remove("target_prev");
 }
 
-void reset()
-{
-	current_target = 0;
-	current_target_id = 0;
-}
-
 void render_listener_sound()
 {
 	if (!(snd_engines && snd_engines->value()))
@@ -238,11 +259,26 @@ void render_entity_sound(core::Entity *entity)
 void draw()
 {
 
+	/* Notes
+		http://en.wikipedia.org/wiki/Line-plane_intersection
+		http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
+	*/
 	using math::Vector3f;
 
 	render_listener_sound();
 
 	current_target = 0;
+	current_hover = 0;
+
+	float z = -1;
+
+	// mouse cursor location in 3d world space
+	float x = (float)(input::mouse_x - video::width /2) / (float)video::width *  render::Camera::aspect();
+	float y = (float)(input::mouse_y - video::height /2) / (float)video::height;
+
+	Vector3f cursor = render::Camera::eye() + render::Camera::axis().forward() * (render::frustum_front + 0.001);
+	cursor -= render::Camera::axis().left() * x;
+	cursor -= render::Camera::axis().up() * y;
 
 	math::Vector3f center = render::Camera::eye() + (render::Camera::axis().forward() * (render::frustum_front +0.01f));
 	for (std::map<unsigned int, core::Entity *>::iterator it=core::Entity::registry.begin(); it != core::Entity::registry.end(); it++) {
@@ -251,10 +287,30 @@ void draw()
 		// render entity sound
 		render_entity_sound(entity);
 
-		// calculate target information
+		// find the current target
 		if (entity->id() == current_target_id) {
 			current_target = entity;
+		}
+		
+		// check if the mouse is hovering the entity
+		if (core::localcontrol() && entity->state()->visible()) {
+			Vector3f v(entity->state()->location() - render::Camera::eye());
+			v.normalize();
 
+			if (is_legal_target(entity) && (math::dotproduct(render::Camera::axis().forward(), v) > 0.75 )) {
+
+				// caculate the distance from entity location to the line [eye - cursor]
+				float d = math::Vector3f::length(math::crossproduct( (cursor - render::Camera::eye()) , (render::Camera::eye() - entity->location()))) / math::Vector3f::length(cursor - render::Camera::eye());
+	
+				// if the cursor-beam hits the entity sphere
+				if (d < entity->radius() * 0.5f) {
+					float myz = math::distance(cursor, entity->location());
+					if (z < 0 || myz < z) {
+						current_hover = entity->id();
+						z = myz;
+					}
+				}
+			}
 		}
 	}
 	
@@ -294,6 +350,23 @@ void draw()
 			render::gl::end();
 		}
 	}
+
+/*
+	math::Color color(1, 1, 1, 1);
+	core::Cvar *cl_crosshaircolor = core::Cvar::get("cl_crosshaircolor", "1 1 1");
+	if (cl_crosshaircolor) {
+				std::stringstream colorstr(cl_crosshaircolor->str());
+				colorstr >> color;
+	}
+	const float r = 0.05;
+	render::gl::color(color);
+	render::gl::begin(render::gl::LineLoop);
+	render::gl::vertex(cursorposition + render::Camera::axis().up() * r);
+	render::gl::vertex(cursorposition + render::Camera::axis().left() * r);
+	render::gl::vertex(cursorposition - render::Camera::axis().up() * r);
+	render::gl::vertex(cursorposition - render::Camera::axis().left() * r);
+	render::gl::end();
+*/	
 }
 
 }
diff --git a/src/client/targets.h b/src/client/targets.h
index 32ea7cd..c1f78c7 100644
--- a/src/client/targets.h
+++ b/src/client/targets.h
@@ -20,6 +20,7 @@ void init();
 
 void shutdown();
 
+void reset();
 
 /// render client side entity properties
 void draw();
@@ -33,6 +34,12 @@ void render_entity_sound(core::Entity *Entity);
 /// current selected target, 0 if there is no current targer
 core::Entity *current();
 
+/// id if target the mouse is currently hovering, 0 if none
+unsigned int hover();
+
+/// target a specific entity
+void select_target(unsigned int id);
+
 }
 
 }
diff --git a/src/client/view.cc b/src/client/view.cc
index 1ee50ed..db0fa64 100644
--- a/src/client/view.cc
+++ b/src/client/view.cc
@@ -33,8 +33,8 @@ core::Cvar *draw_ui = 0;
 core::Cvar *draw_stats = 0;
 core::Cvar *draw_location = 0;
 
-core::Cvar *cl_crosshaircolor = 0;
-
+core::Cvar *ui_pointercolor = 0;
+core::Cvar *ui_pointerhovercolor =0;
 namespace view
 {
 
@@ -51,8 +51,11 @@ void init()
 	draw_ui = core::Cvar::get("draw_ui", "1", core::Cvar::Archive);
 	draw_ui->set_info("[bool] draw the user interface");
 
-	cl_crosshaircolor = core::Cvar::get("cl_crosshaircolor", "1 1 1", core::Cvar::Archive);
-	cl_crosshaircolor->set_info("[r g b] crosshairs color");	
+	ui_pointercolor = core::Cvar::get("ui_pointercolor", "0 .5 0", core::Cvar::Archive);
+	ui_pointercolor->set_info("[r g b] mouse pointer color");
+
+	ui_pointerhovercolor = core::Cvar::get("ui_pointerhovercolor", "0 1 0", core::Cvar::Archive);
+	ui_pointerhovercolor->set_info("[r g b] mouse pointer hover color");
 
 	targets::init();
 }
@@ -157,9 +160,9 @@ void draw_cursor()
 	if (!core::localcontrol() || console()->visible()) 
 		return;
 
-	float crosshair_size = 48.0f;
-	float x = input::mouse_x - (crosshair_size /2);
-	float y = input::mouse_y - (crosshair_size /2);
+	float pointer_size = 48.0f;
+	float x = input::mouse_x - (pointer_size /2);
+	float y = input::mouse_y - (pointer_size /2);
 
 	using namespace render;
 	
@@ -167,24 +170,32 @@ void draw_cursor()
 	color.a = 0.5f;
 
 	if (render::Camera::mode() == render::Camera::Overview) {
-		render::Textures::bind("bitmaps/crosshairs/aim");
+		render::Textures::bind("bitmaps/pointers/aim");
 
 	} else {
 
-		if (input::mouse_control) {
+		if (!input::mouse_control_override && targets::hover()) {
+
+			if (ui_pointerhovercolor) {
+				std::stringstream colorstr(ui_pointerhovercolor->str());
+				colorstr >> color;
+			}
+			render::Textures::bind("bitmaps/pointers/target");
+
+		} else if (input::mouse_control) {
 			
-			if (cl_crosshaircolor) {
-				std::stringstream colorstr(cl_crosshaircolor->str());
+			if (ui_pointercolor) {
+				std::stringstream colorstr(ui_pointercolor->str());
 				colorstr >> color;
 			}
 
 			if (render::Camera::mode() == render::Camera::Cockpit 
 			|| render::Camera::mode() == render::Camera::Track) {
 
-				render::Textures::bind("bitmaps/crosshairs/center");
+				render::Textures::bind("bitmaps/pointers/center");
 
-				x = (video::width - crosshair_size) /2;
-				y = (video::height - crosshair_size) /2;
+				x = (video::width - pointer_size) /2;
+				y = (video::height - pointer_size) /2;
 		
 				gl::color(color);
 				gl::begin(gl::Quads);
@@ -193,32 +204,32 @@ void draw_cursor()
 				gl::vertex(x,y,0.0f);
 			
 				glTexCoord2f(1, 0);
-				gl::vertex(x+crosshair_size, y, 0.0f);
+				gl::vertex(x+pointer_size, y, 0.0f);
 			
 				glTexCoord2f(1, 1);
-				gl::vertex(x+crosshair_size, y+crosshair_size, 0.0f);
+				gl::vertex(x+pointer_size, y+pointer_size, 0.0f);
 			
 				glTexCoord2f(0, 1);
-				gl::vertex(x, y+crosshair_size, 0.0f);
+				gl::vertex(x, y+pointer_size, 0.0f);
 			
 				gl::end();
 				
 			}
 			
-			render::Textures::bind("bitmaps/crosshairs/control");
+			render::Textures::bind("bitmaps/pointers/control");
 
-			if (!input::mouse_deadzone) {
-				x = input::mouse_x - (crosshair_size /2);
-				y = input::mouse_y - (crosshair_size /2);
+//			if (!input::mouse_deadzone) {
+				x = input::mouse_x - (pointer_size /2);
+				y = input::mouse_y - (pointer_size /2);
 
-			} else {
-				x = (video::width - crosshair_size) /2;
-				y = (video::height - crosshair_size) /2;
-			}
+// 			} else {
+// 				x = (video::width - pointer_size) /2;
+// 				y = (video::height - pointer_size) /2;
+// 			}
 
 		} else {
 
-			render::Textures::bind("bitmaps/crosshairs/aim");
+			render::Textures::bind("bitmaps/pointers/aim");
 		}
 
 	}
@@ -230,13 +241,13 @@ void draw_cursor()
 	gl::vertex(x,y,0.0f);
 
 	glTexCoord2f(1, 0);
-	gl::vertex(x+crosshair_size, y, 0.0f);
+	gl::vertex(x+pointer_size, y, 0.0f);
 
 	glTexCoord2f(1, 1);
-	gl::vertex(x+crosshair_size, y+crosshair_size, 0.0f);
+	gl::vertex(x+pointer_size, y+pointer_size, 0.0f);
 
 	glTexCoord2f(0, 1);
-	gl::vertex(x, y+crosshair_size, 0.0f);
+	gl::vertex(x, y+pointer_size, 0.0f);
 
 	gl::end();
 }
-- 
cgit v1.2.3