/* client/targets.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #ifndef __INCLUDED_CLIENT_TARGET_H__ #define __INCLUDED_CLIENT_TARGET_H__ #include #include #include #include #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/entity.h" #include "core/func.h" #include "core/gameinterface.h" #include "math/vector3f.h" #include "render/gl.h" #include "render/render.h" #include "render/text.h" namespace client { 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()) return false; else 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()) return; if (!core::Entity::registry.size()) { current_target = 0; current_target_id = 0; return; } std::map::iterator it = core::Entity::registry.begin(); if (!current_target_id) { // first entity it = core::Entity::registry.begin(); while (!is_legal_target((*it).second) && it != core::Entity::registry.end()) it++; } else { // current entity it = core::Entity::registry.find(current_target_id); // next legal entity if (it != core::Entity::registry.end()) it++; if (it == core::Entity::registry.end()) { it = core::Entity::registry.begin(); } while (!is_legal_target((*it).second)) { it++; if (it == core::Entity::registry.end()) it = core::Entity::registry.begin(); if ((*it).first == current_target_id) { current_target = (*it).second; return; } } } if (it != core::Entity::registry.end()) { select_target((*it).second); } else { current_target = 0; current_target_id = 0; } } void func_target_prev(std::string const &args) { if (!core::localcontrol()) return; if (!core::Entity::registry.size()) { current_target = 0; current_target_id = 0; return; } std::map::reverse_iterator rit = core::Entity::registry.rbegin(); if (!current_target_id) { // last entity rit = core::Entity::registry.rbegin(); while (!is_legal_target((*rit).second) && rit != core::Entity::registry.rend()) rit++; } else { // current entity while (rit != core::Entity::registry.rend() && ((*rit).first != current_target_id)) ++rit; // previous legal entity if (rit != core::Entity::registry.rend()) ++rit; if (rit == core::Entity::registry.rend()) { rit = core::Entity::registry.rbegin(); } while (!is_legal_target((*rit).second)) { ++rit; if (rit == core::Entity::registry.rend()) rit = core::Entity::registry.rbegin(); if ((*rit).first == current_target_id) { current_target = (*rit).second; return; } } } if (rit != core::Entity::registry.rend()) { select_target((*rit).second); } else { current_target = 0; current_target_id = 0; } } void reset() { current_target = 0; current_target_id = 0; current_hover = 0; } void init() { snd_engines = core::Cvar::get("snd_engines", "1", core::Cvar::Archive); snd_engines->set_info("[bool] enable or disable engine sounds"); core::Func *func = 0; func = core::Func::add("target_next", func_target_next); func->set_info("select next target"); core::Func::add("target_prev", func_target_prev); func->set_info("select previous target"); reset(); } void shutdown() { reset(); core::Func::remove("target_next"); core::Func::remove("target_prev"); } void render_listener_sound() { if (!(snd_engines && snd_engines->value())) return; math::Vector3f velocity(0, 0 ,0); if (core::localcontrol()) { velocity.assign(core::localcontrol()->state()->axis().forward() * core::localcontrol()->speed()); } audio::update_listener(render::Camera::eye(), render::Camera::axis(), velocity); } void render_entity_sound(core::Entity *entity) { if (!(entity->type() == core::Entity::Controlable)) return; if (!(snd_engines && snd_engines->value())) { entity->state()->clearsound(); return; } core::EntityControlable *entitycontrolable = (core::EntityControlable *) entity; core::ClientState *state = entity->state(); if (entity->model() && state->detailvisible() && entitycontrolable->thrust() > 0 ) { float speed = entitycontrolable->speed(); float pitch = 0.2f + entitycontrolable->thrust() * 0.8f; if (!state->state_enginesound) { if ((state->state_enginesound = audio::Sources::get()) > 0 ) { size_t enginesound = 0; if (entity->model()) enginesound = entity->model()->enginesound(); std::stringstream soundname; soundname << "engines/loop" << std::setfill('0') << std::setw(2) << enginesound; audio::loop(state->state_enginesound, soundname.str().c_str(), pitch, 0); } } if (state->state_enginesound) { audio::update_source(state->state_enginesound, state->location() - state->axis().forward() * entity->model()->maxbbox().y , state->axis().forward() * speed, pitch); } } else { entity->state()->clearsound(); } } // render client targets 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; float y = (float)(input::mouse_y - video::height /2) / (float)video::height / render::Camera::aspect(); Vector3f cursor = render::Camera::eye() + render::Camera::axis().forward() * (render::Camera::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::Camera::frustum_front() +0.01f)); for (std::map::iterator it=core::Entity::registry.begin(); it != core::Entity::registry.end(); it++) { core::Entity *entity = (*it).second; // render entity sound render_entity_sound(entity); // 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; } } } } } if (!current_target) { current_target_id = 0; } else { core::Entity *entity = current_target; // if target is in visible space Vector3f v(entity->state()->location() - render::Camera::eye()); v.normalize(); if (math::dotproduct(render::Camera::axis().forward(), v) > 0.75 ) { // find the intersection of the line [ eye - target ] in the frustum front plane Vector3f const &plane_normal = render::Camera::axis().forward(); Vector3f const &plane_point = render::Camera::eye() + render::Camera::axis().forward() * (render::Camera::frustum_front() + 0.001); float d = (plane_normal.x * plane_point.x + plane_normal.y * plane_point.y + plane_normal.z * plane_point.z); float t = d - plane_normal.x * render::Camera::eye().x - plane_normal.y * render::Camera::eye().y - plane_normal.z * render::Camera::eye().z; t /= plane_normal.x * (entity->state()->location().x - render::Camera::eye().x) + plane_normal.y * (entity->state()->location().y - render::Camera::eye().y) + plane_normal.z * (entity->state()->location().z - render::Camera::eye().z); Vector3f intersection = render::Camera::eye() + (entity->state()->location() - render::Camera::eye()) * t; // draw the target cursor in the frustum front plane, but in real world coordinates const float r = 0.05; render::gl::color(1, 1, 1, 1); render::gl::begin(render::gl::LineLoop); render::gl::vertex(intersection + render::Camera::axis().up() * r); render::gl::vertex(intersection + render::Camera::axis().left() * r); render::gl::vertex(intersection - render::Camera::axis().up() * r); render::gl::vertex(intersection - render::Camera::axis().left() * r); 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(); */ } } } #endif // __INCLUDED_CLIENT_RADAR_H__